aboutsummaryrefslogtreecommitdiff
path: root/arch/ia64/ia32
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Makefile12
-rw-r--r--arch/ia64/ia32/binfmt_elf32.c294
-rw-r--r--arch/ia64/ia32/elfcore32.h138
-rw-r--r--arch/ia64/ia32/ia32_entry.S500
-rw-r--r--arch/ia64/ia32/ia32_ioctl.c48
-rw-r--r--arch/ia64/ia32/ia32_ldt.c147
-rw-r--r--arch/ia64/ia32/ia32_signal.c1036
-rw-r--r--arch/ia64/ia32/ia32_support.c264
-rw-r--r--arch/ia64/ia32/ia32_traps.c156
-rw-r--r--arch/ia64/ia32/ia32priv.h544
-rw-r--r--arch/ia64/ia32/sys_ia32.c2747
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(&current->mm->mmap_sem);
+ {
+ if (insert_vm_struct(current->mm, vma)) {
+ kmem_cache_free(vm_area_cachep, vma);
+ up_write(&current->mm->mmap_sem);
+ BUG();
+ }
+ }
+ up_write(&current->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(&current->mm->mmap_sem);
+ {
+ if (insert_vm_struct(current->mm, vma)) {
+ kmem_cache_free(vm_area_cachep, vma);
+ up_write(&current->mm->mmap_sem);
+ BUG();
+ }
+ }
+ up_write(&current->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(&current->mm->mmap_sem);
+ {
+ if (insert_vm_struct(current->mm, vma)) {
+ kmem_cache_free(vm_area_cachep, vma);
+ up_write(&current->mm->mmap_sem);
+ BUG();
+ }
+ }
+ up_write(&current->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(&current->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(&current->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(&current->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 = &regs
+ 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 = &regs
+ 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