1/*
2 * Support for 32-bit Linux for S390 ELF binaries.
3 *
4 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
5 * Author(s): Gerhard Tonn (ton@de.ibm.com)
6 *
7 * Heavily inspired by the 32-bit Sparc compat code which is
8 * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
9 * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek   (jj@ultra.linux.cz)
10 */
11
12
13#define __ASMS390_ELF_H
14
15/*
16 * These are used to set parameters in the core dumps.
17 */
18#define ELF_CLASS	ELFCLASS32
19#define ELF_DATA	ELFDATA2MSB
20#define ELF_ARCH	EM_S390
21
22/*
23 * This is used to ensure we don't load something for the wrong architecture.
24 */
25#define elf_check_arch(x) \
26	(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
27         && (x)->e_ident[EI_CLASS] == ELF_CLASS)
28
29/* ELF register definitions */
30#define NUM_GPRS      16
31#define NUM_FPRS      16
32#define NUM_ACRS      16
33
34#define TASK31_SIZE		(0x80000000UL)
35
36/* For SVR4/S390 the function pointer to be registered with `atexit` is
37   passed in R14. */
38#define ELF_PLAT_INIT(_r) \
39	do { \
40	_r->gprs[14] = 0; \
41	current->thread.flags |= S390_FLAG_31BIT; \
42	} while(0)
43
44#define USE_ELF_CORE_DUMP
45#define ELF_EXEC_PAGESIZE       4096
46
47/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
48   use of this is to invoke "./ld.so someprog" to test out a new version of
49   the loader.  We need to make sure that it is out of the way of the program
50   that it will "exec", and that there is sufficient room for the brk.  */
51
52#define ELF_ET_DYN_BASE         ((TASK31_SIZE & 0x80000000) \
53                                ? TASK31_SIZE / 3 * 2 \
54                                : 2 * TASK31_SIZE / 3)
55
56/* Wow, the "main" arch needs arch dependent functions too.. :) */
57
58/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
59   now struct_user_regs, they are different) */
60
61#define ELF_CORE_COPY_REGS(pr_reg, regs)        \
62	{ \
63	int i; \
64	memcpy(&pr_reg.psw.mask, &regs->psw.mask, 4); \
65	memcpy(&pr_reg.psw.addr, ((char*)&regs->psw.addr)+4, 4); \
66	for(i=0; i<NUM_GPRS; i++) \
67		pr_reg.gprs[i] = regs->gprs[i]; \
68	for(i=0; i<NUM_ACRS; i++) \
69		pr_reg.acrs[i] = regs->acrs[i]; \
70	pr_reg.orig_gpr2 = regs->orig_gpr2; \
71	}
72
73
74
75/* This yields a mask that user programs can use to figure out what
76   instruction set this CPU supports. */
77
78#define ELF_HWCAP (0)
79
80/* This yields a string that ld.so will use to load implementation
81   specific libraries for optimization.  This is more specific in
82   intent than poking at uname or /proc/cpuinfo.
83
84   For the moment, we have only optimizations for the Intel generations,
85   but that could change... */
86
87#define ELF_PLATFORM (NULL)
88
89#ifdef __KERNEL__
90#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
91#endif
92
93#include "linux32.h"
94
95typedef _s390_fp_regs32 elf_fpregset_t;
96
97typedef struct
98{
99
100	_psw_t32	psw;
101	__u32		gprs[__NUM_GPRS];
102	__u32		acrs[__NUM_ACRS];
103	__u32		orig_gpr2;
104} s390_regs32;
105typedef s390_regs32 elf_gregset_t;
106
107#include <asm/processor.h>
108#include <linux/module.h>
109#include <linux/config.h>
110#include <linux/elfcore.h>
111
112int setup_arg_pages32(struct linux_binprm *bprm);
113
114struct timeval32
115{
116    int tv_sec, tv_usec;
117};
118
119#define elf_prstatus elf_prstatus32
120struct elf_prstatus32
121{
122	struct elf_siginfo pr_info;	/* Info associated with signal */
123	short	pr_cursig;		/* Current signal */
124	u32	pr_sigpend;	/* Set of pending signals */
125	u32	pr_sighold;	/* Set of held signals */
126	pid_t	pr_pid;
127	pid_t	pr_ppid;
128	pid_t	pr_pgrp;
129	pid_t	pr_sid;
130	struct timeval32 pr_utime;	/* User time */
131	struct timeval32 pr_stime;	/* System time */
132	struct timeval32 pr_cutime;	/* Cumulative user time */
133	struct timeval32 pr_cstime;	/* Cumulative system time */
134	elf_gregset_t pr_reg;	/* GP registers */
135	int pr_fpvalid;		/* True if math co-processor being used.  */
136};
137
138#define elf_prpsinfo elf_prpsinfo32
139struct elf_prpsinfo32
140{
141	char	pr_state;	/* numeric process state */
142	char	pr_sname;	/* char for pr_state */
143	char	pr_zomb;	/* zombie */
144	char	pr_nice;	/* nice val */
145	u32	pr_flag;	/* flags */
146	u16	pr_uid;
147	u16	pr_gid;
148	pid_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
149	/* Lots missing */
150	char	pr_fname[16];	/* filename of executable */
151	char	pr_psargs[ELF_PRARGSZ];	/* initial part of arg list */
152};
153
154#include <linux/highuid.h>
155
156#undef NEW_TO_OLD_UID
157#undef NEW_TO_OLD_GID
158#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
159#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
160
161#define elf_addr_t	u32
162#define elf_caddr_t	u32
163/*
164#define init_elf_binfmt init_elf32_binfmt
165*/
166#undef CONFIG_BINFMT_ELF
167#ifdef CONFIG_BINFMT_ELF32
168#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
169#endif
170#undef CONFIG_BINFMT_ELF_MODULE
171#ifdef CONFIG_BINFMT_ELF32_MODULE
172#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
173#endif
174
175#undef start_thread
176#define start_thread                    start_thread31
177#define setup_arg_pages(bprm)           setup_arg_pages32(bprm)
178#define elf_map				elf_map32
179
180MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
181                   " Copyright 2000 IBM Corporation");
182MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
183
184#undef MODULE_DESCRIPTION
185#undef MODULE_AUTHOR
186
187#include "../../../fs/binfmt_elf.c"
188
189static unsigned long
190elf_map32 (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
191{
192	unsigned long map_addr;
193
194	if(!addr)
195		addr = 0x40000000;
196
197	down_write(&current->mm->mmap_sem);
198	map_addr = do_mmap(filep, ELF_PAGESTART(addr),
199			   eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
200			   eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
201	up_write(&current->mm->mmap_sem);
202	return(map_addr);
203}
204
205