1/* 2 * Written 2000,2002 by Andi Kleen. 3 * 4 * Losely 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#include <linux/types.h> 9#include <linux/config.h> 10#include <linux/stddef.h> 11#include <linux/module.h> 12#include <linux/rwsem.h> 13#include <linux/sched.h> 14#include <linux/string.h> 15#include <asm/segment.h> 16#include <asm/ptrace.h> 17#include <asm/processor.h> 18#include <asm/user32.h> 19#include <asm/sigcontext32.h> 20#include <asm/fpu32.h> 21#include <asm/i387.h> 22 23struct file; 24struct elf_phdr; 25 26#define IA32_EMULATOR 1 27 28#define IA32_PAGE_OFFSET 0xFFFFF000 29#define IA32_STACK_TOP IA32_PAGE_OFFSET 30#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) 31 32#undef ELF_ARCH 33#define ELF_ARCH EM_386 34 35#undef ELF_CLASS 36#define ELF_CLASS ELFCLASS32 37 38#define ELF_DATA ELFDATA2LSB 39 40#define USE_ELF_CORE_DUMP 1 41 42/* Overwrite elfcore.h */ 43#define _LINUX_ELFCORE_H 1 44typedef unsigned int elf_greg_t; 45 46#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t)) 47typedef elf_greg_t elf_gregset_t[ELF_NGREG]; 48 49struct elf_siginfo 50{ 51 int si_signo; /* signal number */ 52 int si_code; /* extra code */ 53 int si_errno; /* errno */ 54}; 55 56struct timeval32 57{ 58 int tv_sec, tv_usec; 59}; 60 61struct elf_prstatus 62{ 63 struct elf_siginfo pr_info; /* Info associated with signal */ 64 short pr_cursig; /* Current signal */ 65 unsigned int pr_sigpend; /* Set of pending signals */ 66 unsigned int pr_sighold; /* Set of held signals */ 67 pid_t pr_pid; 68 pid_t pr_ppid; 69 pid_t pr_pgrp; 70 pid_t pr_sid; 71 struct timeval32 pr_utime; /* User time */ 72 struct timeval32 pr_stime; /* System time */ 73 struct timeval32 pr_cutime; /* Cumulative user time */ 74 struct timeval32 pr_cstime; /* Cumulative system time */ 75 elf_gregset_t pr_reg; /* GP registers */ 76 int pr_fpvalid; /* True if math co-processor being used. */ 77}; 78 79#define ELF_PRARGSZ (80) /* Number of chars for args */ 80 81struct elf_prpsinfo 82{ 83 char pr_state; /* numeric process state */ 84 char pr_sname; /* char for pr_state */ 85 char pr_zomb; /* zombie */ 86 char pr_nice; /* nice val */ 87 unsigned int pr_flag; /* flags */ 88 __u16 pr_uid; 89 __u16 pr_gid; 90 pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; 91 /* Lots missing */ 92 char pr_fname[16]; /* filename of executable */ 93 char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ 94}; 95 96#define __STR(x) #x 97#define STR(x) __STR(x) 98 99#define _GET_SEG(x) \ 100 ({ __u32 seg; asm("movl %%" STR(x) ",%0" : "=r"(seg)); seg; }) 101 102/* Assumes current==process to be dumped */ 103#define ELF_CORE_COPY_REGS(pr_reg, regs) \ 104 pr_reg[0] = regs->rbx; \ 105 pr_reg[1] = regs->rcx; \ 106 pr_reg[2] = regs->rdx; \ 107 pr_reg[3] = regs->rsi; \ 108 pr_reg[4] = regs->rdi; \ 109 pr_reg[5] = regs->rbp; \ 110 pr_reg[6] = regs->rax; \ 111 pr_reg[7] = _GET_SEG(ds); \ 112 pr_reg[8] = _GET_SEG(es); \ 113 pr_reg[9] = _GET_SEG(fs); \ 114 pr_reg[10] = _GET_SEG(gs); \ 115 pr_reg[11] = regs->orig_rax; \ 116 pr_reg[12] = regs->rip; \ 117 pr_reg[13] = regs->cs; \ 118 pr_reg[14] = regs->eflags; \ 119 pr_reg[15] = regs->rsp; \ 120 pr_reg[16] = regs->ss; 121 122#define user user32 123 124#define dump_fpu dump_fpu_ia32 125 126#define __ASM_X86_64_ELF_H 1 127#include <asm/ia32.h> 128#include <linux/elf.h> 129 130typedef struct user_i387_ia32_struct elf_fpregset_t; 131typedef struct user32_fxsr_struct elf_fpxregset_t; 132 133#undef elf_check_arch 134#define elf_check_arch(x) \ 135 ((x)->e_machine == EM_386) 136 137#define ELF_EXEC_PAGESIZE PAGE_SIZE 138#define ELF_HWCAP (boot_cpu_data.x86_capability[0]) 139#define ELF_PLATFORM ("i686") 140#define SET_PERSONALITY(ex, ibcs2) \ 141do { \ 142 set_personality((ibcs2)?PER_SVR4:current->personality); \ 143} while (0) 144 145/* Override some function names */ 146#define elf_format elf32_format 147 148#define init_elf_binfmt init_elf32_binfmt 149#define exit_elf_binfmt exit_elf32_binfmt 150 151#define load_elf_binary load_elf32_binary 152 153#undef CONFIG_BINFMT_ELF 154#ifdef CONFIG_BINFMT_ELF32 155# define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32 156#endif 157 158#undef CONFIG_BINFMT_ELF_MODULE 159#ifdef CONFIG_BINFMT_ELF32_MODULE 160# define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE 161#endif 162 163#define ELF_PLAT_INIT(r) elf32_init(r) 164#define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) 165 166#undef start_thread 167#define start_thread(regs,new_rip,new_rsp) do { \ 168 __asm__("movl %0,%%fs": :"r" (0)); \ 169 __asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \ 170 wrmsrl(MSR_KERNEL_GS_BASE, 0); \ 171 (regs)->rip = (new_rip); \ 172 (regs)->rsp = (new_rsp); \ 173 (regs)->eflags = 0x200; \ 174 (regs)->cs = __USER32_CS; \ 175 (regs)->ss = __USER32_DS; \ 176 set_fs(USER_DS); \ 177} while(0) 178 179 180#define elf_map elf32_map 181 182MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries."); 183MODULE_AUTHOR("Eric Youngdale, Andi Kleen"); 184 185#undef MODULE_DESCRIPTION 186#undef MODULE_AUTHOR 187 188#define elf_addr_t __u32 189#define elf_caddr_t __u32 190 191static void elf32_init(struct pt_regs *); 192int ia32_setup_arg_pages(struct linux_binprm *bprm); 193 194#include "../../../fs/binfmt_elf.c" 195 196static void elf32_init(struct pt_regs *regs) 197{ 198 struct task_struct *me = current; 199 regs->rdi = 0; 200 regs->rsi = 0; 201 regs->rdx = 0; 202 regs->rcx = 0; 203 regs->rax = 0; 204 regs->rbx = 0; 205 regs->rbp = 0; 206 me->thread.fs = 0; 207 me->thread.gs = 0; 208 me->thread.fsindex = 0; 209 me->thread.gsindex = 0; 210 me->thread.ds = __USER_DS; 211 me->thread.es = __USER_DS; 212 me->thread.flags |= THREAD_IA32; 213} 214 215extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address); 216 217 218int ia32_setup_arg_pages(struct linux_binprm *bprm) 219{ 220 unsigned long stack_base; 221 struct vm_area_struct *mpnt; 222 int i; 223 224 stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; 225 226 bprm->p += stack_base; 227 if (bprm->loader) 228 bprm->loader += stack_base; 229 bprm->exec += stack_base; 230 231 mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); 232 if (!mpnt) 233 return -ENOMEM; 234 235 down_write(¤t->mm->mmap_sem); 236 { 237 mpnt->vm_mm = current->mm; 238 mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; 239 mpnt->vm_end = IA32_STACK_TOP; 240 mpnt->vm_page_prot = PAGE_COPY; 241 mpnt->vm_flags = VM_STACK_FLAGS; 242 mpnt->vm_ops = NULL; 243 mpnt->vm_pgoff = 0; 244 mpnt->vm_file = NULL; 245 mpnt->vm_private_data = (void *) 0; 246 insert_vm_struct(current->mm, mpnt); 247 current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; 248 } 249 250 for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 251 struct page *page = bprm->page[i]; 252 if (page) { 253 bprm->page[i] = NULL; 254 current->mm->rss++; 255 put_dirty_page(current,page,stack_base); 256 } 257 stack_base += PAGE_SIZE; 258 } 259 up_write(¤t->mm->mmap_sem); 260 261 return 0; 262} 263static unsigned long 264elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) 265{ 266 unsigned long map_addr; 267 struct task_struct *me = current; 268 269 if (prot & PROT_READ) 270 prot |= PROT_EXEC; 271 272 down_write(&me->mm->mmap_sem); 273 map_addr = do_mmap(filep, ELF_PAGESTART(addr), 274 eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, 275 type|MAP_32BIT, 276 eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); 277 up_write(&me->mm->mmap_sem); 278 return(map_addr); 279} 280 281int dump_fpu_ia32(struct pt_regs *regs, elf_fpregset_t *fp) 282{ 283 struct _fpstate_ia32 *fpu = (void*)fp; 284 struct task_struct *tsk = current; 285 mm_segment_t oldfs = get_fs(); 286 int ret; 287 288 if (!tsk->used_math) 289 return 0; 290 if (!(tsk->thread.flags & THREAD_IA32)) 291 BUG(); 292 unlazy_fpu(tsk); 293 set_fs(KERNEL_DS); 294 ret = save_i387_ia32(current, fpu, regs, 1); 295 /* Correct for i386 bug. It puts the fop into the upper 16bits of 296 the tag word (like FXSAVE), not into the fcs*/ 297 fpu->cssel |= fpu->tag & 0xffff0000; 298 set_fs(oldfs); 299 return ret; 300} 301