diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ia64/ia32 |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ia64/ia32')
-rw-r--r-- | arch/ia64/ia32/Makefile | 12 | ||||
-rw-r--r-- | arch/ia64/ia32/binfmt_elf32.c | 294 | ||||
-rw-r--r-- | arch/ia64/ia32/elfcore32.h | 138 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32_entry.S | 500 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32_ioctl.c | 48 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32_ldt.c | 147 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32_signal.c | 1036 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32_support.c | 264 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32_traps.c | 156 | ||||
-rw-r--r-- | arch/ia64/ia32/ia32priv.h | 544 | ||||
-rw-r--r-- | arch/ia64/ia32/sys_ia32.c | 2747 |
11 files changed, 5886 insertions, 0 deletions
diff --git a/arch/ia64/ia32/Makefile b/arch/ia64/ia32/Makefile new file mode 100644 index 00000000000..2ed90da8116 --- /dev/null +++ b/arch/ia64/ia32/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the ia32 kernel emulation subsystem. +# + +obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o \ + ia32_support.o ia32_traps.o binfmt_elf32.o ia32_ldt.o + +CFLAGS_ia32_ioctl.o += -Ifs/ + +# Don't let GCC uses f16-f31 so that save_ia32_fpstate_live() and +# restore_ia32_fpstate_live() can be sure the live register contain user-level state. +CFLAGS_ia32_signal.o += -mfixed-range=f16-f31 diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c new file mode 100644 index 00000000000..31de70b7c67 --- /dev/null +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -0,0 +1,294 @@ +/* + * IA-32 ELF support. + * + * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> + * Copyright (C) 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + * + * 06/16/00 A. Mallick initialize csd/ssd/tssd/cflg for ia32_load_state + * 04/13/01 D. Mosberger dropped saving tssd in ar.k1---it's not needed + * 09/14/01 D. Mosberger fixed memory management for gdt/tss page + */ +#include <linux/config.h> + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/security.h> + +#include <asm/param.h> +#include <asm/signal.h> + +#include "ia32priv.h" +#include "elfcore32.h" + +/* Override some function names */ +#undef start_thread +#define start_thread ia32_start_thread +#define elf_format elf32_format +#define init_elf_binfmt init_elf32_binfmt +#define exit_elf_binfmt exit_elf32_binfmt + +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC + +extern void ia64_elf32_init (struct pt_regs *regs); + +static void elf32_set_personality (void); + +#define setup_arg_pages(bprm,tos,exec) ia32_setup_arg_pages(bprm,exec) +#define elf_map elf32_map + +#undef SET_PERSONALITY +#define SET_PERSONALITY(ex, ibcs2) elf32_set_personality() + +#define elf_read_implies_exec(ex, have_pt_gnu_stack) (!(have_pt_gnu_stack)) + +/* Ugly but avoids duplication */ +#include "../../../fs/binfmt_elf.c" + +extern struct page *ia32_shared_page[]; +extern unsigned long *ia32_gdt; +extern struct page *ia32_gate_page; + +struct page * +ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *pg = ia32_shared_page[smp_processor_id()]; + get_page(pg); + if (type) + *type = VM_FAULT_MINOR; + return pg; +} + +struct page * +ia32_install_gate_page (struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *pg = ia32_gate_page; + get_page(pg); + if (type) + *type = VM_FAULT_MINOR; + return pg; +} + + +static struct vm_operations_struct ia32_shared_page_vm_ops = { + .nopage = ia32_install_shared_page +}; + +static struct vm_operations_struct ia32_gate_page_vm_ops = { + .nopage = ia32_install_gate_page +}; + +void +ia64_elf32_init (struct pt_regs *regs) +{ + struct vm_area_struct *vma; + + /* + * Map GDT below 4GB, where the processor can find it. We need to map + * it with privilege level 3 because the IVE uses non-privileged accesses to these + * tables. IA-32 segmentation is used to protect against IA-32 accesses to them. + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_start = IA32_GDT_OFFSET; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = PAGE_SHARED; + vma->vm_flags = VM_READ|VM_MAYREAD|VM_RESERVED; + vma->vm_ops = &ia32_shared_page_vm_ops; + down_write(¤t->mm->mmap_sem); + { + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + BUG(); + } + } + up_write(¤t->mm->mmap_sem); + } + + /* + * When user stack is not executable, push sigreturn code to stack makes + * segmentation fault raised when returning to kernel. So now sigreturn + * code is locked in specific gate page, which is pointed by pretcode + * when setup_frame_ia32 + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_start = IA32_GATE_OFFSET; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = PAGE_COPY_EXEC; + vma->vm_flags = VM_READ | VM_MAYREAD | VM_EXEC + | VM_MAYEXEC | VM_RESERVED; + vma->vm_ops = &ia32_gate_page_vm_ops; + down_write(¤t->mm->mmap_sem); + { + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + BUG(); + } + } + up_write(¤t->mm->mmap_sem); + } + + /* + * Install LDT as anonymous memory. This gives us all-zero segment descriptors + * until a task modifies them via modify_ldt(). + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_start = IA32_LDT_OFFSET; + vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); + vma->vm_page_prot = PAGE_SHARED; + vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE; + down_write(¤t->mm->mmap_sem); + { + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + BUG(); + } + } + up_write(¤t->mm->mmap_sem); + } + + ia64_psr(regs)->ac = 0; /* turn off alignment checking */ + regs->loadrs = 0; + /* + * According to the ABI %edx points to an `atexit' handler. Since we don't have + * one we'll set it to 0 and initialize all the other registers just to make + * things more deterministic, ala the i386 implementation. + */ + regs->r8 = 0; /* %eax */ + regs->r11 = 0; /* %ebx */ + regs->r9 = 0; /* %ecx */ + regs->r10 = 0; /* %edx */ + regs->r13 = 0; /* %ebp */ + regs->r14 = 0; /* %esi */ + regs->r15 = 0; /* %edi */ + + current->thread.eflag = IA32_EFLAG; + current->thread.fsr = IA32_FSR_DEFAULT; + current->thread.fcr = IA32_FCR_DEFAULT; + current->thread.fir = 0; + current->thread.fdr = 0; + + /* + * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor + * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 + * architecture manual. Also note that the only fields that are not ignored are + * `base', `limit', 'G', `P' (must be 1) and `S' (must be 0). + */ + regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, + 0, 0, 0, 1, 0, 0, 0)); + /* Setup the segment selectors */ + regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ + + ia32_load_segment_descriptors(current); + ia32_load_state(current); +} + +int +ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) +{ + unsigned long stack_base; + struct vm_area_struct *mpnt; + struct mm_struct *mm = current->mm; + int i, ret; + + stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; + mm->arg_start = bprm->p + stack_base; + + bprm->p += stack_base; + if (bprm->loader) + bprm->loader += stack_base; + bprm->exec += stack_base; + + mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!mpnt) + return -ENOMEM; + + if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p)) + >> PAGE_SHIFT)) { + kmem_cache_free(vm_area_cachep, mpnt); + return -ENOMEM; + } + + memset(mpnt, 0, sizeof(*mpnt)); + + down_write(¤t->mm->mmap_sem); + { + mpnt->vm_mm = current->mm; + mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; + mpnt->vm_end = IA32_STACK_TOP; + if (executable_stack == EXSTACK_ENABLE_X) + mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC; + else if (executable_stack == EXSTACK_DISABLE_X) + mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC; + else + mpnt->vm_flags = VM_STACK_FLAGS; + mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)? + PAGE_COPY_EXEC: PAGE_COPY; + if ((ret = insert_vm_struct(current->mm, mpnt))) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } + current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt); + } + + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + struct page *page = bprm->page[i]; + if (page) { + bprm->page[i] = NULL; + install_arg_page(mpnt, page, stack_base); + } + stack_base += PAGE_SIZE; + } + up_write(¤t->mm->mmap_sem); + + /* Can't do it in ia64_elf32_init(). Needs to be done before calls to + elf32_map() */ + current->thread.ppl = ia32_init_pp_list(); + + return 0; +} + +static void +elf32_set_personality (void) +{ + set_personality(PER_LINUX32); + current->thread.map_base = IA32_PAGE_OFFSET/3; + current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ + set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ +} + +static unsigned long +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +{ + unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; + + return ia32_do_mmap(filep, (addr & IA32_PAGE_MASK), eppnt->p_filesz + pgoff, prot, type, + eppnt->p_offset - pgoff); +} + +#define cpu_uses_ia32el() (local_cpu_data->family > 0x1f) + +static int __init check_elf32_binfmt(void) +{ + if (cpu_uses_ia32el()) { + printk("Please use IA-32 EL for executing IA-32 binaries\n"); + return unregister_binfmt(&elf_format); + } + return 0; +} + +module_init(check_elf32_binfmt) diff --git a/arch/ia64/ia32/elfcore32.h b/arch/ia64/ia32/elfcore32.h new file mode 100644 index 00000000000..b73b8b6b10c --- /dev/null +++ b/arch/ia64/ia32/elfcore32.h @@ -0,0 +1,138 @@ +/* + * IA-32 ELF core dump support. + * + * Copyright (C) 2003 Arun Sharma <arun.sharma@intel.com> + * + * Derived from the x86_64 version + */ +#ifndef _ELFCORE32_H_ +#define _ELFCORE32_H_ + +#include <asm/intrinsics.h> +#include <asm/uaccess.h> + +#define USE_ELF_CORE_DUMP 1 + +/* Override elfcore.h */ +#define _LINUX_ELFCORE_H 1 +typedef unsigned int elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct ia32_user_i387_struct elf_fpregset_t; +typedef struct ia32_user_fxsr_struct elf_fpxregset_t; + +struct elf_siginfo +{ + int si_signo; /* signal number */ + int si_code; /* extra code */ + int si_errno; /* errno */ +}; + +#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0) + +struct elf_prstatus +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned int pr_sigpend; /* Set of pending signals */ + unsigned int pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct compat_timeval pr_utime; /* User time */ + struct compat_timeval pr_stime; /* System time */ + struct compat_timeval pr_cutime; /* Cumulative user time */ + struct compat_timeval pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + int pr_fpvalid; /* True if math co-processor being used. */ +}; + +#define ELF_PRARGSZ (80) /* Number of chars for args */ + +struct elf_prpsinfo +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + unsigned int pr_flag; /* flags */ + __u16 pr_uid; + __u16 pr_gid; + pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + pr_reg[0] = regs->r11; \ + pr_reg[1] = regs->r9; \ + pr_reg[2] = regs->r10; \ + pr_reg[3] = regs->r14; \ + pr_reg[4] = regs->r15; \ + pr_reg[5] = regs->r13; \ + pr_reg[6] = regs->r8; \ + pr_reg[7] = regs->r16 & 0xffff; \ + pr_reg[8] = (regs->r16 >> 16) & 0xffff; \ + pr_reg[9] = (regs->r16 >> 32) & 0xffff; \ + pr_reg[10] = (regs->r16 >> 48) & 0xffff; \ + pr_reg[11] = regs->r1; \ + pr_reg[12] = regs->cr_iip; \ + pr_reg[13] = regs->r17 & 0xffff; \ + pr_reg[14] = ia64_getreg(_IA64_REG_AR_EFLAG); \ + pr_reg[15] = regs->r12; \ + pr_reg[16] = (regs->r17 >> 16) & 0xffff; + +static inline void elf_core_copy_regs(elf_gregset_t *elfregs, + struct pt_regs *regs) +{ + ELF_CORE_COPY_REGS((*elfregs), regs) +} + +static inline int elf_core_copy_task_regs(struct task_struct *t, + elf_gregset_t* elfregs) +{ + struct pt_regs *pp = ia64_task_regs(t); + ELF_CORE_COPY_REGS((*elfregs), pp); + return 1; +} + +static inline int +elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpregset_t *fpu) +{ + struct ia32_user_i387_struct *fpstate = (void*)fpu; + mm_segment_t old_fs; + + if (!tsk_used_math(tsk)) + return 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + save_ia32_fpstate(tsk, (struct ia32_user_i387_struct __user *) fpstate); + set_fs(old_fs); + + return 1; +} + +#define ELF_CORE_COPY_XFPREGS 1 +static inline int +elf_core_copy_task_xfpregs(struct task_struct *tsk, elf_fpxregset_t *xfpu) +{ + struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu; + mm_segment_t old_fs; + + if (!tsk_used_math(tsk)) + return 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + save_ia32_fpxstate(tsk, (struct ia32_user_fxsr_struct __user *) fpxstate); + set_fs(old_fs); + + return 1; +} + +#endif /* _ELFCORE32_H_ */ diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S new file mode 100644 index 00000000000..829a6d80711 --- /dev/null +++ b/arch/ia64/ia32/ia32_entry.S @@ -0,0 +1,500 @@ +#include <asm/asmmacro.h> +#include <asm/ia32.h> +#include <asm/offsets.h> +#include <asm/signal.h> +#include <asm/thread_info.h> + +#include "../kernel/minstate.h" + + /* + * execve() is special because in case of success, we need to + * setup a null register window frame (in case an IA-32 process + * is exec'ing an IA-64 program). + */ +ENTRY(ia32_execve) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3) + alloc loc1=ar.pfs,3,2,4,0 + mov loc0=rp + .body + zxt4 out0=in0 // filename + ;; // stop bit between alloc and call + zxt4 out1=in1 // argv + zxt4 out2=in2 // envp + add out3=16,sp // regs + br.call.sptk.few rp=sys32_execve +1: cmp.ge p6,p0=r8,r0 + mov ar.pfs=loc1 // restore ar.pfs + ;; +(p6) mov ar.pfs=r0 // clear ar.pfs in case of success + sxt4 r8=r8 // return 64-bit result + mov rp=loc0 + br.ret.sptk.few rp +END(ia32_execve) + +ENTRY(ia32_clone) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) + alloc r16=ar.pfs,5,2,6,0 + DO_SAVE_SWITCH_STACK + mov loc0=rp + mov loc1=r16 // save ar.pfs across do_fork + .body + zxt4 out1=in1 // newsp + mov out3=16 // stacksize (compensates for 16-byte scratch area) + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s + mov out0=in0 // out0 = clone_flags + zxt4 out4=in2 // out4 = parent_tidptr + zxt4 out5=in4 // out5 = child_tidptr + br.call.sptk.many rp=do_fork +.ret0: .restore sp + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov ar.pfs=loc1 + mov rp=loc0 + br.ret.sptk.many rp +END(ia32_clone) + +ENTRY(sys32_rt_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in0 // mask + mov out1=in1 // sigsetsize + mov out2=sp // out2 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" + ;; + .body + br.call.sptk.many rp=ia32_rt_sigsuspend +1: .restore sp + adds sp=16,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_rt_sigsuspend) + +ENTRY(sys32_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in2 // mask (first two args are ignored) + ;; + mov out1=sp // out1 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" + .body + br.call.sptk.many rp=ia32_sigsuspend +1: .restore sp + adds sp=16,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_sigsuspend) + +GLOBAL_ENTRY(ia32_ret_from_clone) + PT_REGS_UNWIND_INFO(0) +{ /* + * Some versions of gas generate bad unwind info if the first instruction of a + * procedure doesn't go into the first slot of a bundle. This is a workaround. + */ + nop.m 0 + nop.i 0 + /* + * We need to call schedule_tail() to complete the scheduling process. + * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the + * address of the previously executing task. + */ + br.call.sptk.many rp=ia64_invoke_schedule_tail +} +.ret1: + adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; + ld4 r2=[r2] + ;; + mov r8=0 + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 + ;; + cmp.ne p6,p0=r2,r0 +(p6) br.cond.spnt .ia32_strace_check_retval + ;; // prevent RAW on r8 +END(ia32_ret_from_clone) + // fall thrugh +GLOBAL_ENTRY(ia32_ret_from_syscall) + PT_REGS_UNWIND_INFO(0) + + cmp.ge p6,p7=r8,r0 // syscall executed successfully? + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 + ;; + alloc r3=ar.pfs,0,0,0,0 // drop the syscall argument frame + st8 [r2]=r8 // store return value in slot for r8 + br.cond.sptk.many ia64_leave_kernel +END(ia32_ret_from_syscall) + + // + // Invoke a system call, but do some tracing before and after the call. + // We MUST preserve the current register frame throughout this routine + // because some system calls (such as ia64_execve) directly + // manipulate ar.pfs. + // + // Input: + // r8 = syscall number + // b6 = syscall entry point + // +GLOBAL_ENTRY(ia32_trace_syscall) + PT_REGS_UNWIND_INFO(0) + mov r3=-38 + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp + ;; + st8 [r2]=r3 // initialize return code to -ENOSYS + br.call.sptk.few rp=syscall_trace_enter // give parent a chance to catch syscall args +.ret2: // Need to reload arguments (they may be changed by the tracing process) + adds r2=IA64_PT_REGS_R1_OFFSET+16,sp // r2 = &pt_regs.r1 + adds r3=IA64_PT_REGS_R13_OFFSET+16,sp // r3 = &pt_regs.r13 + mov r15=IA32_NR_syscalls + ;; + ld4 r8=[r2],IA64_PT_REGS_R9_OFFSET-IA64_PT_REGS_R1_OFFSET + movl r16=ia32_syscall_table + ;; + ld4 r33=[r2],8 // r9 == ecx + ld4 r37=[r3],16 // r13 == ebp + cmp.ltu.unc p6,p7=r8,r15 + ;; + ld4 r34=[r2],8 // r10 == edx + ld4 r36=[r3],8 // r15 == edi +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number + ;; + ld8 r16=[r16] + ;; + ld4 r32=[r2],8 // r11 == ebx + mov b6=r16 + ld4 r35=[r3],8 // r14 == esi + br.call.sptk.few rp=b6 // do the syscall +.ia32_strace_check_retval: + cmp.lt p6,p0=r8,r0 // syscall failed? + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 + ;; + st8.spill [r2]=r8 // store return value in slot for r8 + br.call.sptk.few rp=syscall_trace_leave // give parent a chance to catch return value +.ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame + br.cond.sptk.many ia64_leave_kernel +END(ia32_trace_syscall) + +GLOBAL_ENTRY(sys32_vfork) + alloc r16=ar.pfs,2,2,4,0;; + mov out0=IA64_CLONE_VFORK|IA64_CLONE_VM|SIGCHLD // out0 = clone_flags + br.cond.sptk.few .fork1 // do the work +END(sys32_vfork) + +GLOBAL_ENTRY(sys32_fork) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc r16=ar.pfs,2,2,4,0 + mov out0=SIGCHLD // out0 = clone_flags + ;; +.fork1: + mov loc0=rp + mov loc1=r16 // save ar.pfs across do_fork + DO_SAVE_SWITCH_STACK + + .body + + mov out1=0 + mov out3=0 + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s + br.call.sptk.few rp=do_fork +.ret5: .restore sp + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov ar.pfs=loc1 + mov rp=loc0 + br.ret.sptk.many rp +END(sys32_fork) + + .rodata + .align 8 + .globl ia32_syscall_table +ia32_syscall_table: + data8 sys_ni_syscall /* 0 - old "setup(" system call*/ + data8 sys_exit + data8 sys32_fork + data8 sys_read + data8 sys_write + data8 sys32_open /* 5 */ + data8 sys_close + data8 sys32_waitpid + data8 sys_creat + data8 sys_link + data8 sys_unlink /* 10 */ + data8 ia32_execve + data8 sys_chdir + data8 compat_sys_time + data8 sys_mknod + data8 sys_chmod /* 15 */ + data8 sys_lchown /* 16-bit version */ + data8 sys_ni_syscall /* old break syscall holder */ + data8 sys_ni_syscall + data8 sys32_lseek + data8 sys_getpid /* 20 */ + data8 compat_sys_mount + data8 sys_oldumount + data8 sys_setuid /* 16-bit version */ + data8 sys_getuid /* 16-bit version */ + data8 compat_sys_stime /* 25 */ + data8 sys32_ptrace + data8 sys32_alarm + data8 sys_ni_syscall + data8 sys32_pause + data8 compat_sys_utime /* 30 */ + data8 sys_ni_syscall /* old stty syscall holder */ + data8 sys_ni_syscall /* old gtty syscall holder */ + data8 sys_access + data8 sys_nice + data8 sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + data8 sys_sync + data8 sys_kill + data8 sys_rename + data8 sys_mkdir + data8 sys_rmdir /* 40 */ + data8 sys_dup + data8 sys32_pipe + data8 compat_sys_times + data8 sys_ni_syscall /* old prof syscall holder */ + data8 sys32_brk /* 45 */ + data8 sys_setgid /* 16-bit version */ + data8 sys_getgid /* 16-bit version */ + data8 sys32_signal + data8 sys_geteuid /* 16-bit version */ + data8 sys_getegid /* 16-bit version */ /* 50 */ + data8 sys_acct + data8 sys_umount /* recycled never used phys( */ + data8 sys_ni_syscall /* old lock syscall holder */ + data8 compat_sys_ioctl + data8 compat_sys_fcntl /* 55 */ + data8 sys_ni_syscall /* old mpx syscall holder */ + data8 sys_setpgid + data8 sys_ni_syscall /* old ulimit syscall holder */ + data8 sys_ni_syscall + data8 sys_umask /* 60 */ + data8 sys_chroot + data8 sys_ustat + data8 sys_dup2 + data8 sys_getppid + data8 sys_getpgrp /* 65 */ + data8 sys_setsid + data8 sys32_sigaction + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_setreuid /* 16-bit version */ /* 70 */ + data8 sys_setregid /* 16-bit version */ + data8 sys32_sigsuspend + data8 compat_sys_sigpending + data8 sys_sethostname + data8 compat_sys_setrlimit /* 75 */ + data8 compat_sys_old_getrlimit + data8 compat_sys_getrusage + data8 sys32_gettimeofday + data8 sys32_settimeofday + data8 sys32_getgroups16 /* 80 */ + data8 sys32_setgroups16 + data8 sys32_old_select + data8 sys_symlink + data8 sys_ni_syscall + data8 sys_readlink /* 85 */ + data8 sys_uselib + data8 sys_swapon + data8 sys_reboot + data8 sys32_readdir + data8 sys32_mmap /* 90 */ + data8 sys32_munmap + data8 sys_truncate + data8 sys_ftruncate + data8 sys_fchmod + data8 sys_fchown /* 16-bit version */ /* 95 */ + data8 sys_getpriority + data8 sys_setpriority + data8 sys_ni_syscall /* old profil syscall holder */ + data8 compat_sys_statfs + data8 compat_sys_fstatfs /* 100 */ + data8 sys_ni_syscall /* ioperm */ + data8 compat_sys_socketcall + data8 sys_syslog + data8 compat_sys_setitimer + data8 compat_sys_getitimer /* 105 */ + data8 compat_sys_newstat + data8 compat_sys_newlstat + data8 compat_sys_newfstat + data8 sys_ni_syscall + data8 sys_ni_syscall /* iopl */ /* 110 */ + data8 sys_vhangup + data8 sys_ni_syscall /* used to be sys_idle */ + data8 sys_ni_syscall + data8 compat_sys_wait4 + data8 sys_swapoff /* 115 */ + data8 sys32_sysinfo + data8 sys32_ipc + data8 sys_fsync + data8 sys32_sigreturn + data8 ia32_clone /* 120 */ + data8 sys_setdomainname + data8 sys32_newuname + data8 sys32_modify_ldt + data8 sys_ni_syscall /* adjtimex */ + data8 sys32_mprotect /* 125 */ + data8 compat_sys_sigprocmask + data8 sys_ni_syscall /* create_module */ + data8 sys_ni_syscall /* init_module */ + data8 sys_ni_syscall /* delete_module */ + data8 sys_ni_syscall /* get_kernel_syms */ /* 130 */ + data8 sys_quotactl + data8 sys_getpgid + data8 sys_fchdir + data8 sys_ni_syscall /* sys_bdflush */ + data8 sys_sysfs /* 135 */ + data8 sys32_personality + data8 sys_ni_syscall /* for afs_syscall */ + data8 sys_setfsuid /* 16-bit version */ + data8 sys_setfsgid /* 16-bit version */ + data8 sys_llseek /* 140 */ + data8 compat_sys_getdents + data8 compat_sys_select + data8 sys_flock + data8 sys32_msync + data8 compat_sys_readv /* 145 */ + data8 compat_sys_writev + data8 sys_getsid + data8 sys_fdatasync + data8 sys32_sysctl + data8 sys_mlock /* 150 */ + data8 sys_munlock + data8 sys_mlockall + data8 sys_munlockall + data8 sys_sched_setparam + data8 sys_sched_getparam /* 155 */ + data8 sys_sched_setscheduler + data8 sys_sched_getscheduler + data8 sys_sched_yield + data8 sys_sched_get_priority_max + data8 sys_sched_get_priority_min /* 160 */ + data8 sys32_sched_rr_get_interval + data8 compat_sys_nanosleep + data8 sys32_mremap + data8 sys_setresuid /* 16-bit version */ + data8 sys32_getresuid16 /* 16-bit version */ /* 165 */ + data8 sys_ni_syscall /* vm86 */ + data8 sys_ni_syscall /* sys_query_module */ + data8 sys_poll + data8 sys_ni_syscall /* nfsservctl */ + data8 sys_setresgid /* 170 */ + data8 sys32_getresgid16 + data8 sys_prctl + data8 sys32_rt_sigreturn + data8 sys32_rt_sigaction + data8 sys32_rt_sigprocmask /* 175 */ + data8 sys_rt_sigpending + data8 compat_sys_rt_sigtimedwait + data8 sys32_rt_sigqueueinfo + data8 sys32_rt_sigsuspend + data8 sys32_pread /* 180 */ + data8 sys32_pwrite + data8 sys_chown /* 16-bit version */ + data8 sys_getcwd + data8 sys_capget + data8 sys_capset /* 185 */ + data8 sys32_sigaltstack + data8 sys32_sendfile + data8 sys_ni_syscall /* streams1 */ + data8 sys_ni_syscall /* streams2 */ + data8 sys32_vfork /* 190 */ + data8 compat_sys_getrlimit + data8 sys32_mmap2 + data8 sys32_truncate64 + data8 sys32_ftruncate64 + data8 sys32_stat64 /* 195 */ + data8 sys32_lstat64 + data8 sys32_fstat64 + data8 sys_lchown + data8 sys_getuid + data8 sys_getgid /* 200 */ + data8 sys_geteuid + data8 sys_getegid + data8 sys_setreuid + data8 sys_setregid + data8 sys_getgroups /* 205 */ + data8 sys_setgroups + data8 sys_fchown + data8 sys_setresuid + data8 sys_getresuid + data8 sys_setresgid /* 210 */ + data8 sys_getresgid + data8 sys_chown + data8 sys_setuid + data8 sys_setgid + data8 sys_setfsuid /* 215 */ + data8 sys_setfsgid + data8 sys_pivot_root + data8 sys_mincore + data8 sys_madvise + data8 compat_sys_getdents64 /* 220 */ + data8 compat_sys_fcntl64 + data8 sys_ni_syscall /* reserved for TUX */ + data8 sys_ni_syscall /* reserved for Security */ + data8 sys_gettid + data8 sys_readahead /* 225 */ + data8 sys_setxattr + data8 sys_lsetxattr + data8 sys_fsetxattr + data8 sys_getxattr + data8 sys_lgetxattr /* 230 */ + data8 sys_fgetxattr + data8 sys_listxattr + data8 sys_llistxattr + data8 sys_flistxattr + data8 sys_removexattr /* 235 */ + data8 sys_lremovexattr + data8 sys_fremovexattr + data8 sys_tkill + data8 sys_sendfile64 + data8 compat_sys_futex /* 240 */ + data8 compat_sys_sched_setaffinity + data8 compat_sys_sched_getaffinity + data8 sys32_set_thread_area + data8 sys32_get_thread_area + data8 compat_sys_io_setup /* 245 */ + data8 sys_io_destroy + data8 compat_sys_io_getevents + data8 compat_sys_io_submit + data8 sys_io_cancel + data8 sys_fadvise64 /* 250 */ + data8 sys_ni_syscall + data8 sys_exit_group + data8 sys_lookup_dcookie + data8 sys_epoll_create + data8 sys32_epoll_ctl /* 255 */ + data8 sys32_epoll_wait + data8 sys_remap_file_pages + data8 sys_set_tid_address + data8 sys32_timer_create + data8 compat_sys_timer_settime /* 260 */ + data8 compat_sys_timer_gettime + data8 sys_timer_getoverrun + data8 sys_timer_delete + data8 compat_sys_clock_settime + data8 compat_sys_clock_gettime /* 265 */ + data8 compat_sys_clock_getres + data8 compat_sys_clock_nanosleep + data8 compat_sys_statfs64 + data8 compat_sys_fstatfs64 + data8 sys_tgkill /* 270 */ + data8 compat_sys_utimes + data8 sys32_fadvise64_64 + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 275 */ + data8 sys_ni_syscall + data8 compat_sys_mq_open + data8 sys_mq_unlink + data8 compat_sys_mq_timedsend + data8 compat_sys_mq_timedreceive /* 280 */ + data8 compat_sys_mq_notify + data8 compat_sys_mq_getsetattr + data8 sys_ni_syscall /* reserved for kexec */ + data8 compat_sys_waitid + + // guard against failures to increase IA32_NR_syscalls + .org ia32_syscall_table + 8*IA32_NR_syscalls diff --git a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c new file mode 100644 index 00000000000..9845dabe261 --- /dev/null +++ b/arch/ia64/ia32/ia32_ioctl.c @@ -0,0 +1,48 @@ +/* + * IA32 Architecture-specific ioctl shim code + * + * Copyright (C) 2000 VA Linux Co + * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> + * Copyright (C) 2001-2003 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + */ + +#include <linux/signal.h> /* argh, msdos_fs.h isn't self-contained... */ +#include <linux/syscalls.h> +#include "ia32priv.h" + +#define INCLUDES +#include "compat_ioctl.c" +#include <asm/ioctl32.h> + +#define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) + +#define DO_IOCTL(fd, cmd, arg) ({ \ + int _ret; \ + mm_segment_t _old_fs = get_fs(); \ + \ + set_fs(KERNEL_DS); \ + _ret = sys_ioctl(fd, cmd, (unsigned long)arg); \ + set_fs(_old_fs); \ + _ret; \ +}) + +#define CODE +#include "compat_ioctl.c" + +typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *); + +#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl) +#define HANDLE_IOCTL(cmd,handler) { (cmd), (ioctl32_handler_t)(handler), NULL }, +#define IOCTL_TABLE_START \ + struct ioctl_trans ioctl_start[] = { +#define IOCTL_TABLE_END \ + }; + +IOCTL_TABLE_START +#define DECLARES +#include "compat_ioctl.c" +#include <linux/compat_ioctl.h> +IOCTL_TABLE_END + +int ioctl_table_size = ARRAY_SIZE(ioctl_start); diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c new file mode 100644 index 00000000000..a152738c7d0 --- /dev/null +++ b/arch/ia64/ia32/ia32_ldt.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2001, 2004 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + * + * Adapted from arch/i386/kernel/ldt.c + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/vmalloc.h> + +#include <asm/uaccess.h> + +#include "ia32priv.h" + +/* + * read_ldt() is not really atomic - this is not a problem since synchronization of reads |