blob: 55822d2cf05319acdf7464acdfd3e37271279b4b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Written 2000,2002 by Andi Kleen.
3 *
4 * Loosely based on the sparc64 and IA64 32bit emulation loaders.
5 * This tricks binfmt_elf.c into loading 32bit binaries using lots
6 * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
7 */
Ralf Baechle9f7290e2007-05-02 19:27:08 +02008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/stddef.h>
11#include <linux/rwsem.h>
12#include <linux/sched.h>
13#include <linux/compat.h>
14#include <linux/string.h>
15#include <linux/binfmts.h>
16#include <linux/mm.h>
17#include <linux/security.h>
Roland McGrath95d1b8f2007-10-19 20:35:02 +020018#include <linux/elfcore-compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20#include <asm/segment.h>
21#include <asm/ptrace.h>
22#include <asm/processor.h>
23#include <asm/user32.h>
24#include <asm/sigcontext32.h>
25#include <asm/fpu32.h>
26#include <asm/i387.h>
27#include <asm/uaccess.h>
28#include <asm/ia32.h>
29#include <asm/vsyscall32.h>
30
Roland McGrath95d1b8f2007-10-19 20:35:02 +020031#undef ELF_ARCH
32#undef ELF_CLASS
33#define ELF_CLASS ELFCLASS32
34#define ELF_ARCH EM_386
35
36#undef elfhdr
37#undef elf_phdr
38#undef elf_note
39#undef elf_addr_t
40#define elfhdr elf32_hdr
41#define elf_phdr elf32_phdr
42#define elf_note elf32_note
43#define elf_addr_t Elf32_Off
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define ELF_NAME "elf/i386"
46
47#define AT_SYSINFO 32
48#define AT_SYSINFO_EHDR 33
49
50int sysctl_vsyscall32 = 1;
51
Andi Kleen2aae9502007-07-21 17:10:01 +020052#undef ARCH_DLINFO
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define ARCH_DLINFO do { \
54 if (sysctl_vsyscall32) { \
Roland McGrath2ebc3cc2007-07-26 10:41:12 -070055 current->mm->context.vdso = (void *)VSYSCALL32_BASE; \
56 NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
57 NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL32_BASE); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 } \
59} while(0)
60
61struct file;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63#define IA32_EMULATOR 1
64
Roland McGrath95d1b8f2007-10-19 20:35:02 +020065#undef ELF_ET_DYN_BASE
66
Suresh Siddha84929802005-06-21 17:14:32 -070067#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define _GET_SEG(x) \
Glauber de Oliveira Costa92b2dc72007-10-17 18:04:38 +020072 ({ __u32 seg; asm("movl %%" __stringify(x) ",%0" : "=r"(seg)); seg; })
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/* Assumes current==process to be dumped */
Roland McGrath95d1b8f2007-10-19 20:35:02 +020075#undef ELF_CORE_COPY_REGS
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#define ELF_CORE_COPY_REGS(pr_reg, regs) \
77 pr_reg[0] = regs->rbx; \
78 pr_reg[1] = regs->rcx; \
79 pr_reg[2] = regs->rdx; \
80 pr_reg[3] = regs->rsi; \
81 pr_reg[4] = regs->rdi; \
82 pr_reg[5] = regs->rbp; \
83 pr_reg[6] = regs->rax; \
84 pr_reg[7] = _GET_SEG(ds); \
85 pr_reg[8] = _GET_SEG(es); \
86 pr_reg[9] = _GET_SEG(fs); \
87 pr_reg[10] = _GET_SEG(gs); \
88 pr_reg[11] = regs->orig_rax; \
89 pr_reg[12] = regs->rip; \
90 pr_reg[13] = regs->cs; \
91 pr_reg[14] = regs->eflags; \
92 pr_reg[15] = regs->rsp; \
93 pr_reg[16] = regs->ss;
94
Roland McGrath95d1b8f2007-10-19 20:35:02 +020095
96#define elf_prstatus compat_elf_prstatus
97#define elf_prpsinfo compat_elf_prpsinfo
98#define elf_fpregset_t struct user_i387_ia32_struct
99#define elf_fpxregset_t struct user32_fxsr_struct
100#define user user32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Ralf Baechle9f7290e2007-05-02 19:27:08 +0200102#undef elf_read_implies_exec
Markus Schoder3391c222006-07-10 17:06:06 +0200103#define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200105#define elf_core_copy_regs elf32_core_copy_regs
106static inline void elf32_core_copy_regs(compat_elf_gregset_t *elfregs,
107 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200109 ELF_CORE_COPY_REGS((&elfregs->ebx), regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110}
111
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200112#define elf_core_copy_task_regs elf32_core_copy_task_regs
113static inline int elf32_core_copy_task_regs(struct task_struct *t,
114 compat_elf_gregset_t* elfregs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Al Virobb049232006-01-12 01:05:38 -0800116 struct pt_regs *pp = task_pt_regs(t);
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200117 ELF_CORE_COPY_REGS((&elfregs->ebx), pp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 /* fix wrong segments */
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200119 elfregs->ds = t->thread.ds;
120 elfregs->fs = t->thread.fsindex;
121 elfregs->gs = t->thread.gsindex;
122 elfregs->es = t->thread.es;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return 1;
124}
125
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200126#define elf_core_copy_task_fpregs elf32_core_copy_task_fpregs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127static inline int
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200128elf32_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs,
129 elf_fpregset_t *fpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
131 struct _fpstate_ia32 *fpstate = (void*)fpu;
132 mm_segment_t oldfs = get_fs();
133
134 if (!tsk_used_math(tsk))
135 return 0;
136 if (!regs)
Al Virobb049232006-01-12 01:05:38 -0800137 regs = task_pt_regs(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 if (tsk == current)
139 unlazy_fpu(tsk);
140 set_fs(KERNEL_DS);
141 save_i387_ia32(tsk, fpstate, regs, 1);
142 /* Correct for i386 bug. It puts the fop into the upper 16bits of
143 the tag word (like FXSAVE), not into the fcs*/
144 fpstate->cssel |= fpstate->tag & 0xffff0000;
145 set_fs(oldfs);
146 return 1;
147}
148
149#define ELF_CORE_COPY_XFPREGS 1
Mark Nelson5b20cd82007-10-16 23:25:39 -0700150#define ELF_CORE_XFPREG_TYPE NT_PRXFPREG
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200151#define elf_core_copy_task_xfpregs elf32_core_copy_task_xfpregs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static inline int
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200153elf32_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Al Virobb049232006-01-12 01:05:38 -0800155 struct pt_regs *regs = task_pt_regs(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 if (!tsk_used_math(t))
157 return 0;
158 if (t == current)
159 unlazy_fpu(t);
160 memcpy(xfpu, &t->thread.i387.fxsave, sizeof(elf_fpxregset_t));
161 xfpu->fcs = regs->cs;
162 xfpu->fos = t->thread.ds; /* right? */
163 return 1;
164}
165
166#undef elf_check_arch
167#define elf_check_arch(x) \
168 ((x)->e_machine == EM_386)
169
170extern int force_personality32;
171
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200172#undef ELF_EXEC_PAGESIZE
173#undef ELF_HWCAP
174#undef ELF_PLATFORM
175#undef SET_PERSONALITY
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#define ELF_EXEC_PAGESIZE PAGE_SIZE
177#define ELF_HWCAP (boot_cpu_data.x86_capability[0])
178#define ELF_PLATFORM ("i686")
179#define SET_PERSONALITY(ex, ibcs2) \
180do { \
181 unsigned long new_flags = 0; \
182 if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
183 new_flags = _TIF_IA32; \
184 if ((current_thread_info()->flags & _TIF_IA32) \
185 != new_flags) \
186 set_thread_flag(TIF_ABI_PENDING); \
187 else \
188 clear_thread_flag(TIF_ABI_PENDING); \
189 /* XXX This overwrites the user set personality */ \
190 current->personality |= force_personality32; \
191} while (0)
192
193/* Override some function names */
194#define elf_format elf32_format
195
196#define init_elf_binfmt init_elf32_binfmt
197#define exit_elf_binfmt exit_elf32_binfmt
198
199#define load_elf_binary load_elf32_binary
200
Roland McGrath95d1b8f2007-10-19 20:35:02 +0200201#undef ELF_PLAT_INIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#define ELF_PLAT_INIT(r, load_addr) elf32_init(r)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
204#undef start_thread
205#define start_thread(regs,new_rip,new_rsp) do { \
206 asm volatile("movl %0,%%fs" :: "r" (0)); \
207 asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
208 load_gs_index(0); \
209 (regs)->rip = (new_rip); \
210 (regs)->rsp = (new_rsp); \
211 (regs)->eflags = 0x200; \
212 (regs)->cs = __USER32_CS; \
213 (regs)->ss = __USER32_DS; \
214 set_fs(USER_DS); \
215} while(0)
216
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218#include <linux/module.h>
219
220MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries.");
221MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
222
223#undef MODULE_DESCRIPTION
224#undef MODULE_AUTHOR
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226static void elf32_init(struct pt_regs *);
227
Andi Kleen1e014412005-04-16 15:24:55 -0700228#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
229#define arch_setup_additional_pages syscall32_setup_pages
230extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232#include "../../../fs/binfmt_elf.c"
233
234static void elf32_init(struct pt_regs *regs)
235{
236 struct task_struct *me = current;
237 regs->rdi = 0;
238 regs->rsi = 0;
239 regs->rdx = 0;
240 regs->rcx = 0;
241 regs->rax = 0;
242 regs->rbx = 0;
243 regs->rbp = 0;
244 regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
245 regs->r13 = regs->r14 = regs->r15 = 0;
246 me->thread.fs = 0;
247 me->thread.gs = 0;
248 me->thread.fsindex = 0;
249 me->thread.gsindex = 0;
250 me->thread.ds = __USER_DS;
251 me->thread.es = __USER_DS;
252}
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254#ifdef CONFIG_SYSCTL
255/* Register vsyscall32 into the ABI table */
256#include <linux/sysctl.h>
257
258static ctl_table abi_table2[] = {
Eric W. Biederman306421f2007-02-14 00:33:49 -0800259 {
Eric W. Biederman306421f2007-02-14 00:33:49 -0800260 .procname = "vsyscall32",
261 .data = &sysctl_vsyscall32,
262 .maxlen = sizeof(int),
263 .mode = 0644,
264 .proc_handler = proc_dointvec
265 },
266 {}
267};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Eric W. Biederman306421f2007-02-14 00:33:49 -0800269static ctl_table abi_root_table2[] = {
270 {
271 .ctl_name = CTL_ABI,
272 .procname = "abi",
273 .mode = 0555,
274 .child = abi_table2
275 },
276 {}
277};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279static __init int ia32_binfmt_init(void)
280{
Eric W. Biederman0b4d4142007-02-14 00:34:09 -0800281 register_sysctl_table(abi_root_table2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return 0;
283}
284__initcall(ia32_binfmt_init);
285#endif