Merge branch 'for-2.6.24' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerp...
[linux-2.6] / arch / x86 / ia32 / ia32_binfmt.c
1 /* 
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  */ 
8
9 #include <linux/types.h>
10 #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>
18 #include <linux/elfcore-compat.h>
19
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
31 #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
45 #define ELF_NAME "elf/i386"
46
47 #define AT_SYSINFO 32
48 #define AT_SYSINFO_EHDR         33
49
50 int sysctl_vsyscall32 = 1;
51
52 #undef ARCH_DLINFO
53 #define ARCH_DLINFO do {  \
54         if (sysctl_vsyscall32) { \
55                 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);    \
58         }       \
59 } while(0)
60
61 struct file;
62
63 #define IA32_EMULATOR 1
64
65 #undef ELF_ET_DYN_BASE
66
67 #define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE + 0x1000000)
68
69 #define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
70
71 #define _GET_SEG(x) \
72         ({ __u32 seg; asm("movl %%" __stringify(x) ",%0" : "=r"(seg)); seg; })
73
74 /* Assumes current==process to be dumped */
75 #undef  ELF_CORE_COPY_REGS
76 #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
95
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
101
102 #undef elf_read_implies_exec
103 #define elf_read_implies_exec(ex, executable_stack)     (executable_stack != EXSTACK_DISABLE_X)
104
105 #define elf_core_copy_regs              elf32_core_copy_regs
106 static inline void elf32_core_copy_regs(compat_elf_gregset_t *elfregs,
107                                         struct pt_regs *regs)
108 {
109         ELF_CORE_COPY_REGS((&elfregs->ebx), regs)
110 }
111
112 #define elf_core_copy_task_regs         elf32_core_copy_task_regs
113 static inline int elf32_core_copy_task_regs(struct task_struct *t,
114                                             compat_elf_gregset_t* elfregs)
115 {       
116         struct pt_regs *pp = task_pt_regs(t);
117         ELF_CORE_COPY_REGS((&elfregs->ebx), pp);
118         /* fix wrong segments */ 
119         elfregs->ds = t->thread.ds;
120         elfregs->fs = t->thread.fsindex;
121         elfregs->gs = t->thread.gsindex;
122         elfregs->es = t->thread.es;
123         return 1; 
124 }
125
126 #define elf_core_copy_task_fpregs       elf32_core_copy_task_fpregs
127 static inline int 
128 elf32_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs,
129                             elf_fpregset_t *fpu)
130 {
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)
137                 regs = task_pt_regs(tsk);
138         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
150 #define ELF_CORE_XFPREG_TYPE NT_PRXFPREG
151 #define elf_core_copy_task_xfpregs      elf32_core_copy_task_xfpregs
152 static inline int 
153 elf32_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
154 {
155         struct pt_regs *regs = task_pt_regs(t);
156         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
170 extern int force_personality32;
171
172 #undef  ELF_EXEC_PAGESIZE
173 #undef  ELF_HWCAP
174 #undef  ELF_PLATFORM
175 #undef  SET_PERSONALITY
176 #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)                      \
180 do {                                                    \
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
201 #undef  ELF_PLAT_INIT
202 #define ELF_PLAT_INIT(r, load_addr)     elf32_init(r)
203
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
218 #include <linux/module.h>
219
220 MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries."); 
221 MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
222
223 #undef MODULE_DESCRIPTION
224 #undef MODULE_AUTHOR
225
226 static void elf32_init(struct pt_regs *);
227
228 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
229 #define arch_setup_additional_pages syscall32_setup_pages
230 extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
231
232 #include "../../../fs/binfmt_elf.c" 
233
234 static 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
254 #ifdef CONFIG_SYSCTL
255 /* Register vsyscall32 into the ABI table */
256 #include <linux/sysctl.h>
257
258 static ctl_table abi_table2[] = {
259         {
260                 .procname       = "vsyscall32",
261                 .data           = &sysctl_vsyscall32,
262                 .maxlen         = sizeof(int),
263                 .mode           = 0644,
264                 .proc_handler   = proc_dointvec
265         },
266         {}
267 };
268
269 static ctl_table abi_root_table2[] = {
270         {
271                 .ctl_name = CTL_ABI,
272                 .procname = "abi",
273                 .mode = 0555,
274                 .child = abi_table2
275         },
276         {}
277 };
278
279 static __init int ia32_binfmt_init(void)
280
281         register_sysctl_table(abi_root_table2);
282         return 0;
283 }
284 __initcall(ia32_binfmt_init);
285 #endif