aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2003-05-14 04:10:49 +0000
committerPeter Wemm <peter@FreeBSD.org>2003-05-14 04:10:49 +0000
commitd85631c4ac29e17917c0444837225df309fba37e (patch)
tree65e4ac1aca11723390006ee027d286f8177b0ec6
parent5d5ca6d75e2f83055e723d2269dc0ca9934dfa88 (diff)
downloadsrc-d85631c4ac29e17917c0444837225df309fba37e.tar.gz
src-d85631c4ac29e17917c0444837225df309fba37e.zip
Add BASIC i386 binary support for the amd64 kernel. This is largely
stolen from the ia64/ia32 code (indeed there was a repocopy), but I've redone the MD parts and added and fixed a few essential syscalls. It is sufficient to run i386 binaries like /bin/ls, /usr/bin/id (dynamic) and p4. The ia64 code has not implemented signal delivery, so I had to do that. Before you say it, yes, this does need to go in a common place. But we're in a freeze at the moment and I didn't want to risk breaking ia64. I will sort this out after the freeze so that the common code is in a common place. On the AMD64 side, this required adding segment selector context switch support and some other support infrastructure. The %fs/%gs etc code is hairy because loading %gs will clobber the kernel's current MSR_GSBASE setting. The segment selectors are not used by the kernel, so they're only changed at context switch time or when changing modes. This still needs to be optimized. Approved by: re (amd64/* blanket)
Notes
Notes: svn path=/head/; revision=114987
-rw-r--r--sys/amd64/amd64/cpu_switch.S24
-rw-r--r--sys/amd64/amd64/exception.S35
-rw-r--r--sys/amd64/amd64/genassym.c7
-rw-r--r--sys/amd64/amd64/machdep.c40
-rw-r--r--sys/amd64/amd64/trap.c21
-rw-r--r--sys/amd64/amd64/vm_machdep.c2
-rw-r--r--sys/amd64/conf/GENERIC6
-rw-r--r--sys/amd64/ia32/ia32_exception.S69
-rw-r--r--sys/amd64/ia32/ia32_genassym.c24
-rw-r--r--sys/amd64/ia32/ia32_misc.c116
-rw-r--r--sys/amd64/ia32/ia32_signal.c559
-rw-r--r--sys/amd64/ia32/ia32_signal.h164
-rw-r--r--sys/amd64/ia32/ia32_sigtramp.S87
-rw-r--r--sys/amd64/ia32/ia32_syscall.c275
-rw-r--r--sys/amd64/ia32/ia32_sysvec.c225
-rw-r--r--sys/amd64/ia32/ia32_util.h2
-rw-r--r--sys/amd64/ia32/syscalls.master16
-rw-r--r--sys/amd64/include/cpufunc.h13
-rw-r--r--sys/amd64/include/elf.h18
-rw-r--r--sys/amd64/include/md_var.h1
-rw-r--r--sys/amd64/include/pcb.h5
-rw-r--r--sys/amd64/include/segments.h2
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c116
-rw-r--r--sys/compat/freebsd32/freebsd32_util.h2
-rw-r--r--sys/compat/freebsd32/syscalls.master16
-rw-r--r--sys/compat/ia32/ia32_genassym.c24
-rw-r--r--sys/compat/ia32/ia32_signal.h164
-rw-r--r--sys/compat/ia32/ia32_sigtramp.S87
-rw-r--r--sys/compat/ia32/ia32_sysvec.c225
-rw-r--r--sys/compat/ia32/ia32_util.h2
-rw-r--r--sys/conf/files.amd6422
-rw-r--r--sys/conf/options.amd641
32 files changed, 1983 insertions, 387 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index d5976d4b232f..3ca4ecd11bbc 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -106,6 +106,12 @@ ENTRY(cpu_switch)
pushfq /* PSL */
popq PCB_RFLAGS(%r8)
+ /* Save kernel %gs.base */
+ movl $MSR_GSBASE,%ecx
+ rdmsr
+ movl %eax,PCB_KGSBASE(%r8)
+ movl %edx,PCB_KGSBASE+4(%r8)
+
/* Save userland %fs */
movl $MSR_FSBASE,%ecx
rdmsr
@@ -118,6 +124,12 @@ ENTRY(cpu_switch)
movl %eax,PCB_GSBASE(%r8)
movl %edx,PCB_GSBASE+4(%r8)
+ /* Save segment selector numbers */
+ movl %ds,PCB_DS(%r8)
+ movl %es,PCB_ES(%r8)
+ movl %fs,PCB_FS(%r8)
+ movl %gs,PCB_GS(%r8)
+
/* have we used fp, and need a save? */
cmpq %rdi,PCPU(FPCURTHREAD)
jne 1f
@@ -160,6 +172,18 @@ sw1:
*/
movq TD_PCB(%rsi),%r8
+ /* Restore segment selector numbers */
+ movl PCB_DS(%r8),%ds
+ movl PCB_ES(%r8),%es
+ movl PCB_FS(%r8),%fs
+ movl PCB_GS(%r8),%gs
+
+ /* Restore kernel %gs.base */
+ movl $MSR_GSBASE,%ecx
+ movl PCB_KGSBASE(%r8),%eax
+ movl PCB_KGSBASE+4(%r8),%edx
+ wrmsr
+
/* Restore userland %fs */
movl $MSR_FSBASE,%ecx
movl PCB_FSBASE(%r8),%eax
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index 0469a9a4b048..282b427d7cf5 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -218,40 +218,6 @@ IDTVEC(page)
jmp alltraps_pushregs_no_rdi
/*
- * Call gate entry for FreeBSD ELF and Linux/NetBSD syscall (int 0x80)
- *
- * This is a SDT_SYSIDT entry point (unlike the i386 port) so that we
- * can do a swapgs before enabling interrupts. This is critical because
- * if we took an interrupt before swapgs, the interrupt code would see
- * that it originated in supervisor mode and skip the swapgs.
- */
- SUPERALIGN_TEXT
-IDTVEC(int0x80_syscall)
- swapgs
- sti
- pushq $2 /* sizeof "int 0x80" */
- subq $TF_ERR,%rsp /* skip over tf_trapno */
- movq %rdi,TF_RDI(%rsp)
- movq %rsi,TF_RSI(%rsp)
- movq %rdx,TF_RDX(%rsp)
- movq %rcx,TF_RCX(%rsp)
- movq %r8,TF_R8(%rsp)
- movq %r9,TF_R9(%rsp)
- movq %rax,TF_RAX(%rsp)
- movq %rbx,TF_RBX(%rsp)
- movq %rbp,TF_RBP(%rsp)
- movq %r10,TF_R10(%rsp)
- movq %r11,TF_R11(%rsp)
- movq %r12,TF_R12(%rsp)
- movq %r13,TF_R13(%rsp)
- movq %r14,TF_R14(%rsp)
- movq %r15,TF_R15(%rsp)
- FAKE_MCOUNT(13*4(%rsp))
- call syscall
- MEXITCOUNT
- jmp doreti
-
-/*
* Fast syscall entry point. We enter here with just our new %cs/%ss set,
* and the new privilige level. We are still running on the old user stack
* pointer. We have to juggle a few things around to find our stack etc.
@@ -353,6 +319,7 @@ ENTRY(fork_trampoline)
*/
.text
SUPERALIGN_TEXT
+ .globl doreti
.type doreti,@function
doreti:
FAKE_MCOUNT(bintr) /* init "from" bintr -> doreti */
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
index cf4315905484..b55ef085ca0b 100644
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
@@ -125,6 +125,11 @@ ASSYM(PCB_RIP, offsetof(struct pcb, pcb_rip));
ASSYM(PCB_RFLAGS, offsetof(struct pcb, pcb_rflags));
ASSYM(PCB_FSBASE, offsetof(struct pcb, pcb_fsbase));
ASSYM(PCB_GSBASE, offsetof(struct pcb, pcb_gsbase));
+ASSYM(PCB_KGSBASE, offsetof(struct pcb, pcb_kgsbase));
+ASSYM(PCB_DS, offsetof(struct pcb, pcb_ds));
+ASSYM(PCB_ES, offsetof(struct pcb, pcb_es));
+ASSYM(PCB_FS, offsetof(struct pcb, pcb_fs));
+ASSYM(PCB_GS, offsetof(struct pcb, pcb_gs));
ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
ASSYM(PCB_FULLCTX, PCB_FULLCTX);
@@ -181,8 +186,10 @@ ASSYM(KCSEL, GSEL(GCODE_SEL, SEL_KPL));
ASSYM(KDSEL, GSEL(GDATA_SEL, SEL_KPL));
ASSYM(KUCSEL, GSEL(GUCODE_SEL, SEL_UPL));
ASSYM(KUDSEL, GSEL(GUDATA_SEL, SEL_UPL));
+ASSYM(KUC32SEL, GSEL(GUCODE32_SEL, SEL_UPL));
ASSYM(MSR_FSBASE, MSR_FSBASE);
+ASSYM(MSR_GSBASE, MSR_GSBASE);
ASSYM(MSR_KGSBASE, MSR_KGSBASE);
ASSYM(GPROC0_SEL, GPROC0_SEL);
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index b72725665192..b0b6ce233449 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -124,12 +124,11 @@ extern void initializecpu(void);
#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
static void cpu_startup(void *);
-static void fpstate_drop(struct thread *td);
static void get_fpcontext(struct thread *td, mcontext_t *mcp);
static int set_fpcontext(struct thread *td, const mcontext_t *mcp);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL)
-int _udatasel, _ucodesel;
+int _udatasel, _ucodesel, _ucode32sel;
u_long atdevbase;
u_int64_t modulep; /* phys addr of metadata table */
@@ -390,6 +389,16 @@ sigreturn(td, uap)
return (EJUSTRETURN);
}
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
+{
+
+ return sigreturn(td, (struct sigreturn_args *)uap);
+}
+#endif
+
+
/*
* Machine dependent boot() routine
*
@@ -467,11 +476,25 @@ exec_setregs(td, entry, stack, ps_strings)
{
struct trapframe *regs = td->td_frame;
struct pcb *pcb = td->td_pcb;
+ u_int64_t pc;
- pcb->pcb_fsbase = 0;
- pcb->pcb_gsbase = 0;
wrmsr(MSR_FSBASE, 0);
wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
+ pcb->pcb_fsbase = 0;
+ pcb->pcb_gsbase = 0;
+ pcb->pcb_kgsbase = rdmsr(MSR_GSBASE);
+ load_ds(_udatasel);
+ load_es(_udatasel);
+ load_fs(_udatasel);
+ critical_enter();
+ pc = rdmsr(MSR_GSBASE);
+ load_gs(_udatasel); /* Clobbers kernel %GS.base */
+ wrmsr(MSR_GSBASE, pc);
+ critical_exit();
+ pcb->pcb_ds = _udatasel;
+ pcb->pcb_es = _udatasel;
+ pcb->pcb_fs = _udatasel;
+ pcb->pcb_gs = _udatasel;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = entry;
@@ -590,7 +613,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0xfffff, /* length - all address space */
SDT_MEMERA, /* segment type */
SEL_UPL, /* segment descriptor priority level */
- 0, /* segment descriptor present */
+ 1, /* segment descriptor present */
0, /* long */
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
@@ -661,7 +684,7 @@ extern inthand_t
IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm),
IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
- IDTVEC(xmm), IDTVEC(dblfault), IDTVEC(int0x80_syscall),
+ IDTVEC(xmm), IDTVEC(dblfault),
IDTVEC(fast_syscall), IDTVEC(fast_syscall32);
void
@@ -1232,7 +1255,6 @@ hammer_time(void)
setidt(17, &IDTVEC(align), SDT_SYSIGT, SEL_KPL, 0);
setidt(18, &IDTVEC(mchk), SDT_SYSIGT, SEL_KPL, 0);
setidt(19, &IDTVEC(xmm), SDT_SYSIGT, SEL_KPL, 0);
- setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYSIGT, SEL_UPL, 0);
r_idt.rd_limit = sizeof(idt0) - 1;
r_idt.rd_base = (long) idt;
@@ -1290,10 +1312,12 @@ hammer_time(void)
_ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
_udatasel = GSEL(GUDATA_SEL, SEL_UPL);
+ _ucode32sel = GSEL(GUCODE32_SEL, SEL_UPL);
/* setup proc 0's pcb */
thread0.td_pcb->pcb_flags = 0; /* XXXKSE */
thread0.td_pcb->pcb_cr3 = IdlePML4;
+ thread0.td_pcb->pcb_kgsbase = (u_int64_t)pc;
thread0.td_frame = &proc0_tf;
}
@@ -1613,7 +1637,7 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
return (0);
}
-static void
+void
fpstate_drop(struct thread *td)
{
register_t s;
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 8baa4560985c..1abab3bd6571 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -91,7 +91,7 @@
extern void trap(struct trapframe frame);
extern void syscall(struct trapframe frame);
-static int trap_pfault(struct trapframe *, int, vm_offset_t);
+static int trap_pfault(struct trapframe *, int);
static void trap_fatal(struct trapframe *, vm_offset_t);
void dblfault_handler(void);
@@ -161,13 +161,13 @@ trap(frame)
struct proc *p = td->td_proc;
u_int sticks = 0;
int i = 0, ucode = 0, type, code;
- vm_offset_t eva;
atomic_add_int(&cnt.v_trap, 1);
type = frame.tf_trapno;
#ifdef DDB
if (db_active) {
+ vm_offset_t eva;
eva = (type == T_PAGEFLT ? frame.tf_addr : 0);
trap_fatal(&frame, eva);
goto out;
@@ -202,7 +202,6 @@ trap(frame)
}
}
- eva = 0;
code = frame.tf_err;
if (type == T_PAGEFLT) {
/*
@@ -213,9 +212,8 @@ trap(frame)
* kernel can print out a useful trap message and even get
* to the debugger.
*/
- eva = frame.tf_addr;
if (PCPU_GET(spinlocks) != NULL)
- trap_fatal(&frame, eva);
+ trap_fatal(&frame, frame.tf_addr);
}
#ifdef DEVICE_POLLING
@@ -261,7 +259,7 @@ trap(frame)
break;
case T_PAGEFLT: /* page fault */
- i = trap_pfault(&frame, TRUE, eva);
+ i = trap_pfault(&frame, TRUE);
if (i == -1)
goto userout;
if (i == 0)
@@ -331,7 +329,7 @@ trap(frame)
("kernel trap doesn't have ucred"));
switch (type) {
case T_PAGEFLT: /* page fault */
- (void) trap_pfault(&frame, FALSE, eva);
+ (void) trap_pfault(&frame, FALSE);
goto out;
case T_DNA:
@@ -430,7 +428,7 @@ trap(frame)
#endif /* DEV_ISA */
}
- trap_fatal(&frame, eva);
+ trap_fatal(&frame, 0);
goto out;
}
@@ -445,7 +443,7 @@ trap(frame)
uprintf("fatal process exception: %s",
trap_msg[type]);
if ((type == T_PAGEFLT) || (type == T_PROTFLT))
- uprintf(", fault VA = 0x%lx", eva);
+ uprintf(", fault VA = 0x%lx", frame.tf_addr);
uprintf("\n");
}
#endif
@@ -462,10 +460,9 @@ out:
}
static int
-trap_pfault(frame, usermode, eva)
+trap_pfault(frame, usermode)
struct trapframe *frame;
int usermode;
- vm_offset_t eva;
{
vm_offset_t va;
struct vmspace *vm = NULL;
@@ -474,6 +471,7 @@ trap_pfault(frame, usermode, eva)
vm_prot_t ftype;
struct thread *td = curthread;
struct proc *p = td->td_proc;
+ vm_offset_t eva = frame->tf_addr;
va = trunc_page(eva);
if (va >= KERNBASE) {
@@ -813,4 +811,3 @@ syscall(frame)
mtx_assert(&sched_lock, MA_NOTOWNED);
mtx_assert(&Giant, MA_NOTOWNED);
}
-
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index a4ebe9c41264..0b7f5104af81 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -76,7 +76,6 @@
#include <amd64/isa/isa.h>
static void cpu_reset_real(void);
-extern int _ucodesel, _udatasel;
/*
* Finish a fork operation, with process p2 nearly set up.
@@ -143,6 +142,7 @@ cpu_fork(td1, p2, td2, flags)
* pcb2->pcb_savefpu: cloned above.
* pcb2->pcb_flags: cloned above.
* pcb2->pcb_onfault: cloned above (always NULL here?).
+ * pcb2->pcb_[fg]sbase: cloned above
*/
/*
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 79083ef7a30a..2e058e97f588 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -22,6 +22,8 @@ machine amd64
cpu HAMMER
ident GENERIC
maxusers 0
+options IA32
+options COMPAT_FREEBSD4
makeoptions NO_MODULES=not_yet
@@ -41,6 +43,10 @@ options NFS_ROOT #NFS usable as root device, requires NFSCLIENT
options INVARIANTS #Enable calls of extra sanity checking
options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+options SYSVMSG
+options SYSVSEM
+options SYSVSHM
+
device isa
device pci
diff --git a/sys/amd64/ia32/ia32_exception.S b/sys/amd64/ia32/ia32_exception.S
new file mode 100644
index 000000000000..aa901ef97bbf
--- /dev/null
+++ b/sys/amd64/ia32/ia32_exception.S
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asmacros.h>
+
+#include "assym.s"
+
+#define IDTVEC(name) ALIGN_TEXT; .globl __CONCAT(X,name); \
+ .type __CONCAT(X,name),@function; __CONCAT(X,name):
+
+ .text
+/*
+ * Call gate entry for FreeBSD ELF and Linux/NetBSD syscall (int 0x80)
+ *
+ * This is a SDT_SYSIDT entry point (unlike the i386 port) so that we
+ * can do a swapgs before enabling interrupts. This is critical because
+ * if we took an interrupt before swapgs, the interrupt code would see
+ * that it originated in supervisor mode and skip the swapgs.
+ */
+ SUPERALIGN_TEXT
+IDTVEC(int0x80_syscall)
+ swapgs
+ sti
+ pushq $2 /* sizeof "int 0x80" */
+ subq $TF_ERR,%rsp /* skip over tf_trapno */
+ movq %rdi,TF_RDI(%rsp)
+ movq %rsi,TF_RSI(%rsp)
+ movq %rdx,TF_RDX(%rsp)
+ movq %rcx,TF_RCX(%rsp)
+ movq %r8,TF_R8(%rsp)
+ movq %r9,TF_R9(%rsp)
+ movq %rax,TF_RAX(%rsp)
+ movq %rbx,TF_RBX(%rsp)
+ movq %rbp,TF_RBP(%rsp)
+ movq %r10,TF_R10(%rsp)
+ movq %r11,TF_R11(%rsp)
+ movq %r12,TF_R12(%rsp)
+ movq %r13,TF_R13(%rsp)
+ movq %r14,TF_R14(%rsp)
+ movq %r15,TF_R15(%rsp)
+ FAKE_MCOUNT(13*4(%rsp))
+ call ia32_syscall
+ MEXITCOUNT
+ jmp doreti
diff --git a/sys/amd64/ia32/ia32_genassym.c b/sys/amd64/ia32/ia32_genassym.c
new file mode 100644
index 000000000000..2134a4477c45
--- /dev/null
+++ b/sys/amd64/ia32/ia32_genassym.c
@@ -0,0 +1,24 @@
+/* $FreeBSD$ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/assym.h>
+#include <sys/systm.h>
+#include <sys/signal.h>
+
+#include <amd64/ia32/ia32_signal.h>
+
+ASSYM(IA32_SIGF_HANDLER, offsetof(struct ia32_sigframe, sf_ah));
+ASSYM(IA32_SIGF_UC, offsetof(struct ia32_sigframe, sf_uc));
+ASSYM(IA32_UC_GS, offsetof(struct ia32_ucontext, uc_mcontext.mc_gs));
+ASSYM(IA32_UC_FS, offsetof(struct ia32_ucontext, uc_mcontext.mc_fs));
+ASSYM(IA32_UC_ES, offsetof(struct ia32_ucontext, uc_mcontext.mc_es));
+ASSYM(IA32_UC_DS, offsetof(struct ia32_ucontext, uc_mcontext.mc_ds));
+#ifdef COMPAT_FREEBSD4
+ASSYM(IA32_SIGF_UC4, offsetof(struct ia32_sigframe, sf_uc));
+ASSYM(IA32_UC4_GS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_gs));
+ASSYM(IA32_UC4_FS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_fs));
+ASSYM(IA32_UC4_ES, offsetof(struct ia32_ucontext4, uc_mcontext.mc_es));
+ASSYM(IA32_UC4_DS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_ds));
+#endif
diff --git a/sys/amd64/ia32/ia32_misc.c b/sys/amd64/ia32/ia32_misc.c
index c1cdd2037664..9ef02c5c2421 100644
--- a/sys/amd64/ia32/ia32_misc.c
+++ b/sys/amd64/ia32/ia32_misc.c
@@ -74,9 +74,9 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
-#include <ia64/ia32/ia32_util.h>
-#include <ia64/ia32/ia32.h>
-#include <ia64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32_util.h>
+#include <amd64/ia32/ia32.h>
+#include <amd64/ia32/ia32_proto.h>
static const char ia32_emul_path[] = "/compat/ia32";
/*
@@ -439,6 +439,7 @@ ia32_execve(struct thread *td, struct ia32_execve_args *uap)
return execve(td, &ap);
}
+#ifdef __ia64__
static int
ia32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
int prot, int fd, off_t pos)
@@ -485,6 +486,7 @@ ia32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
return (0);
}
}
+#endif
int
ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
@@ -497,6 +499,7 @@ ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
int fd = uap->fd;
off_t pos = (uap->poslo
| ((off_t)uap->poshi << 32));
+#ifdef __ia64__
vm_size_t pageoff;
int error;
@@ -567,6 +570,7 @@ ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
addr = start;
len = end - start;
}
+#endif
ap.addr = (void *) addr;
ap.len = len;
@@ -653,6 +657,83 @@ ia32_select(struct thread *td, struct ia32_select_args *uap)
return (select(td, (struct select_args *) uap));
}
+struct kevent32 {
+ u_int32_t ident; /* identifier for this event */
+ short filter; /* filter for event */
+ u_short flags;
+ u_int fflags;
+ int32_t data;
+ u_int32_t udata; /* opaque user data identifier */
+};
+
+int
+ia32_kevent(struct thread *td, struct ia32_kevent_args *uap)
+{
+ int error;
+ caddr_t sg;
+ struct timespec32 ts32;
+ struct timespec ts;
+ struct kevent32 ks32;
+ struct kevent *ks;
+ struct kevent_args a;
+ int i;
+
+ sg = stackgap_init();
+
+ a.fd = uap->fd;
+ a.changelist = uap->changelist;
+ a.nchanges = uap->nchanges;
+ a.eventlist = uap->eventlist;
+ a.nevents = uap->nevents;
+ a.timeout = NULL;
+
+ if (uap->timeout) {
+ a.timeout = stackgap_alloc(&sg, sizeof(struct timespec));
+ error = copyin(uap->timeout, &ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32, ts, tv_sec);
+ CP(ts32, ts, tv_nsec);
+ error = copyout(&ts, (void *)(uintptr_t)a.timeout, sizeof(ts));
+ if (error)
+ return (error);
+ }
+ if (uap->changelist) {
+ a.changelist = (struct kevent *)stackgap_alloc(&sg, uap->nchanges * sizeof(struct kevent));
+ for (i = 0; i < uap->nchanges; i++) {
+ error = copyin(&uap->changelist[i], &ks32, sizeof(ks32));
+ if (error)
+ return (error);
+ ks = (struct kevent *)(uintptr_t)&a.changelist[i];
+ CP(ks32, *ks, ident);
+ CP(ks32, *ks, filter);
+ CP(ks32, *ks, flags);
+ CP(ks32, *ks, fflags);
+ CP(ks32, *ks, data);
+ PTRIN_CP(ks32, *ks, udata);
+ }
+ }
+ if (uap->eventlist) {
+ a.eventlist = stackgap_alloc(&sg, uap->nevents * sizeof(struct kevent));
+ }
+ error = kevent(td, &a);
+ if (uap->eventlist && error > 0) {
+ for (i = 0; i < error; i++) {
+ ks = &a.eventlist[i];
+ CP(*ks, ks32, ident);
+ CP(*ks, ks32, filter);
+ CP(*ks, ks32, flags);
+ CP(*ks, ks32, fflags);
+ CP(*ks, ks32, data);
+ PTROUT_CP(*ks, ks32, udata);
+ error = copyout(&ks32, &uap->eventlist[i], sizeof(ks32));
+ if (error)
+ return (error);
+ }
+ }
+ return error;
+}
+
int
ia32_gettimeofday(struct thread *td, struct ia32_gettimeofday_args *uap)
{
@@ -1287,6 +1368,35 @@ ia32_sigaction(struct thread *td, struct ia32_sigaction_args *uap)
return (error);
}
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_ia32_sigaction(struct thread *td, struct freebsd4_ia32_sigaction_args *uap)
+{
+ struct sigaction32 s32;
+ struct sigaction sa, osa, *sap;
+ int error;
+
+ if (uap->act) {
+ error = copyin(uap->act, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ sa.sa_handler = PTRIN(s32.sa_u);
+ CP(s32, sa, sa_flags);
+ CP(s32, sa, sa_mask);
+ sap = &sa;
+ } else
+ sap = NULL;
+ error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
+ if (error != 0 && uap->oact != NULL) {
+ s32.sa_u = PTROUT(osa.sa_handler);
+ CP(osa, s32, sa_flags);
+ CP(osa, s32, sa_mask);
+ error = copyout(&s32, uap->oact, sizeof(s32));
+ }
+ return (error);
+}
+#endif
+
#if 0
int
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
new file mode 100644
index 000000000000..ae966a536565
--- /dev/null
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -0,0 +1,559 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/fcntl.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mman.h>
+#include <sys/namei.h>
+#include <sys/pioctl.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+#include <sys/resourcevar.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/stat.h>
+#include <sys/sx.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+
+#include <amd64/ia32/ia32_util.h>
+#include <amd64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32_signal.h>
+#include <machine/psl.h>
+#include <machine/segments.h>
+#include <machine/specialreg.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cpufunc.h>
+
+#ifdef COMPAT_FREEBSD4
+static void freebsd4_ia32_sendsig(sig_t, int, sigset_t *, u_long);
+#endif
+static void ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp);
+static int ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp);
+
+extern int _ucode32sel, _udatasel;
+
+#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
+#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
+
+static void
+ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp)
+{
+ struct savefpu *addr;
+
+ /*
+ * XXX mc_fpstate might be misaligned, since its declaration is not
+ * unportabilized using __attribute__((aligned(16))) like the
+ * declaration of struct savemm, and anyway, alignment doesn't work
+ * for auto variables since we don't use gcc's pessimal stack
+ * alignment. Work around this by abusing the spare fields after
+ * mcp->mc_fpstate.
+ *
+ * XXX unpessimize most cases by only aligning when fxsave might be
+ * called, although this requires knowing too much about
+ * npxgetregs()'s internals.
+ */
+ addr = (struct savefpu *)&mcp->mc_fpstate;
+ if (td == PCPU_GET(fpcurthread) && ((uintptr_t)(void *)addr & 0xF)) {
+ do
+ addr = (void *)((char *)addr + 4);
+ while ((uintptr_t)(void *)addr & 0xF);
+ }
+ mcp->mc_ownedfp = npxgetregs(td, addr);
+ if (addr != (struct savefpu *)&mcp->mc_fpstate) {
+ bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
+ bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
+ }
+ mcp->mc_fpformat = npxformat();
+}
+
+static int
+ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp)
+{
+ struct savefpu *addr;
+
+ if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
+ return (0);
+ else if (mcp->mc_fpformat != _MC_FPFMT_XMM)
+ return (EINVAL);
+ else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
+ /* We don't care what state is left in the FPU or PCB. */
+ fpstate_drop(td);
+ else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
+ mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
+ /* XXX align as above. */
+ addr = (struct savefpu *)&mcp->mc_fpstate;
+ if (td == PCPU_GET(fpcurthread) &&
+ ((uintptr_t)(void *)addr & 0xF)) {
+ do
+ addr = (void *)((char *)addr + 4);
+ while ((uintptr_t)(void *)addr & 0xF);
+ bcopy(&mcp->mc_fpstate, addr, sizeof(mcp->mc_fpstate));
+ }
+ /*
+ * XXX we violate the dubious requirement that npxsetregs()
+ * be called with interrupts disabled.
+ */
+ npxsetregs(td, addr);
+ /*
+ * Don't bother putting things back where they were in the
+ * misaligned case, since we know that the caller won't use
+ * them again.
+ */
+ } else
+ return (EINVAL);
+ return (0);
+}
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * at top to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+#ifdef COMPAT_FREEBSD4
+static void
+freebsd4_ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
+{
+ struct ia32_sigframe4 sf, *sfp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ struct trapframe *regs;
+ int oonstack;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ psp = p->p_sigacts;
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_rsp);
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack.ss_sp = (uintptr_t)p->p_sigstk.ss_sp;
+ sf.sf_uc.uc_stack.ss_size = p->p_sigstk.ss_size;
+ sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
+ ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+ sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+ sf.sf_uc.uc_mcontext.mc_gs = rgs();
+ sf.sf_uc.uc_mcontext.mc_fs = rfs();
+ __asm __volatile("movl %%es,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_es));
+ __asm __volatile("movl %%ds,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_ds));
+ sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi;
+ sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi;
+ sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp;
+ sf.sf_uc.uc_mcontext.mc_isp = regs->tf_rsp; /* XXX */
+ sf.sf_uc.uc_mcontext.mc_ebx = regs->tf_rbx;
+ sf.sf_uc.uc_mcontext.mc_edx = regs->tf_rdx;
+ sf.sf_uc.uc_mcontext.mc_ecx = regs->tf_rcx;
+ sf.sf_uc.uc_mcontext.mc_eax = regs->tf_rax;
+ sf.sf_uc.uc_mcontext.mc_trapno = regs->tf_trapno;
+ sf.sf_uc.uc_mcontext.mc_err = regs->tf_err;
+ sf.sf_uc.uc_mcontext.mc_eip = regs->tf_rip;
+ sf.sf_uc.uc_mcontext.mc_cs = regs->tf_cs;
+ sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags;
+ sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp;
+ sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss;
+
+ /* Allocate space for the signal handler context. */
+ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sfp = (struct ia32_sigframe4 *)(p->p_sigstk.ss_sp +
+ p->p_sigstk.ss_size - sizeof(sf));
+ } else
+ sfp = (struct ia32_sigframe4 *)regs->tf_rsp - 1;
+ PROC_UNLOCK(p);
+
+ /* Translate the signal if appropriate. */
+ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
+ sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_ucontext = (register_t)&sfp->sf_uc;
+ PROC_LOCK(p);
+ if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ sf.sf_siginfo = (u_int32_t)(uintptr_t)&sfp->sf_si;
+ sf.sf_ah = (u_int32_t)(uintptr_t)catcher;
+
+ /* Fill in POSIX parts */
+ sf.sf_si.si_signo = sig;
+ sf.sf_si.si_code = code;
+ sf.sf_si.si_addr = regs->tf_addr;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_siginfo = code;
+ sf.sf_addr = regs->tf_addr;
+ sf.sf_ah = (u_int32_t)(uintptr_t)catcher;
+ }
+ PROC_UNLOCK(p);
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+#ifdef DEBUG
+ printf("process %ld has trashed its stack\n", (long)p->p_pid);
+#endif
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_rsp = (uintptr_t)sfp;
+ regs->tf_rip = PS_STRINGS - sz_freebsd4_ia32_sigcode;
+ regs->tf_rflags &= ~PSL_T;
+ regs->tf_cs = _ucode32sel;
+ regs->tf_ss = _udatasel;
+ load_ds(_udatasel);
+ td->td_pcb->pcb_ds = _udatasel;
+ load_es(_udatasel);
+ td->td_pcb->pcb_es = _udatasel;
+ /* leave user %fs and %gs untouched */
+ PROC_LOCK(p);
+}
+#endif /* COMPAT_FREEBSD4 */
+
+void
+ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
+{
+ struct ia32_sigframe sf, *sfp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ char *sp;
+ struct trapframe *regs;
+ int oonstack;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ psp = p->p_sigacts;
+#ifdef COMPAT_FREEBSD4
+ if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
+ freebsd4_ia32_sendsig(catcher, sig, mask, code);
+ return;
+ }
+#endif
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_rsp);
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack.ss_sp = (uintptr_t)p->p_sigstk.ss_sp;
+ sf.sf_uc.uc_stack.ss_size = p->p_sigstk.ss_size;
+ sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
+ ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+ sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+ sf.sf_uc.uc_mcontext.mc_gs = rgs();
+ sf.sf_uc.uc_mcontext.mc_fs = rfs();
+ __asm __volatile("movl %%es,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_es));
+ __asm __volatile("movl %%ds,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_ds));
+ sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi;
+ sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi;
+ sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp;
+ sf.sf_uc.uc_mcontext.mc_isp = regs->tf_rsp; /* XXX */
+ sf.sf_uc.uc_mcontext.mc_ebx = regs->tf_rbx;
+ sf.sf_uc.uc_mcontext.mc_edx = regs->tf_rdx;
+ sf.sf_uc.uc_mcontext.mc_ecx = regs->tf_rcx;
+ sf.sf_uc.uc_mcontext.mc_eax = regs->tf_rax;
+ sf.sf_uc.uc_mcontext.mc_trapno = regs->tf_trapno;
+ sf.sf_uc.uc_mcontext.mc_err = regs->tf_err;
+ sf.sf_uc.uc_mcontext.mc_eip = regs->tf_rip;
+ sf.sf_uc.uc_mcontext.mc_cs = regs->tf_cs;
+ sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags;
+ sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp;
+ sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss;
+ sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
+ ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext);
+ fpstate_drop(td);
+
+ /* Allocate space for the signal handler context. */
+ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sp = p->p_sigstk.ss_sp +
+ p->p_sigstk.ss_size - sizeof(sf);
+ } else
+ sp = (char *)regs->tf_rsp - sizeof(sf);
+ /* Align to 16 bytes. */
+ sfp = (struct ia32_sigframe *)((uintptr_t)sp & ~0xF);
+ PROC_UNLOCK(p);
+
+ /* Translate the signal if appropriate. */
+ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
+ sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_ucontext = (register_t)&sfp->sf_uc;
+ PROC_LOCK(p);
+ if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ sf.sf_siginfo = (u_int32_t)(uintptr_t)&sfp->sf_si;
+ sf.sf_ah = (u_int32_t)(uintptr_t)catcher;
+
+ /* Fill in POSIX parts */
+ sf.sf_si.si_signo = sig;
+ sf.sf_si.si_code = code;
+ sf.sf_si.si_addr = regs->tf_addr;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_siginfo = code;
+ sf.sf_addr = regs->tf_err;
+ sf.sf_ah = (u_int32_t)(uintptr_t)catcher;
+ }
+ PROC_UNLOCK(p);
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+#ifdef DEBUG
+ printf("process %ld has trashed its stack\n", (long)p->p_pid);
+#endif
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_rsp = (uintptr_t)sfp;
+ regs->tf_rip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
+ regs->tf_rflags &= ~PSL_T;
+ regs->tf_cs = _ucode32sel;
+ regs->tf_ss = _udatasel;
+ load_ds(_udatasel);
+ td->td_pcb->pcb_ds = _udatasel;
+ load_es(_udatasel);
+ td->td_pcb->pcb_es = _udatasel;
+ /* leave user %fs and %gs untouched */
+ PROC_LOCK(p);
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * state to gain improper privileges.
+ */
+#ifdef COMPAT_FREEBSD4
+/*
+ * MPSAFE
+ */
+int
+freebsd4_ia32_sigreturn(td, uap)
+ struct thread *td;
+ struct freebsd4_ia32_sigreturn_args /* {
+ const struct freebsd4_ucontext *sigcntxp;
+ } */ *uap;
+{
+ struct ia32_ucontext4 uc;
+ struct proc *p = td->td_proc;
+ struct trapframe *regs;
+ const struct ia32_ucontext4 *ucp;
+ int cs, eflags, error;
+
+ error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+ if (error != 0)
+ return (error);
+ ucp = &uc;
+ regs = td->td_frame;
+ eflags = ucp->uc_mcontext.mc_eflags;
+ /*
+ * Don't allow users to change privileged or reserved flags.
+ */
+ /*
+ * XXX do allow users to change the privileged flag PSL_RF.
+ * The cpu sets PSL_RF in tf_eflags for faults. Debuggers
+ * should sometimes set it there too. tf_eflags is kept in
+ * the signal context during signal handling and there is no
+ * other place to remember it, so the PSL_RF bit may be
+ * corrupted by the signal handler without us knowing.
+ * Corruption of the PSL_RF bit at worst causes one more or
+ * one less debugger trap, so allowing it is fairly harmless.
+ */
+ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) {
+ printf("freebsd4_ia32_sigreturn: eflags = 0x%x\n", eflags);
+ return (EINVAL);
+ }
+
+ /*
+ * Don't allow users to load a valid privileged %cs. Let the
+ * hardware check for invalid selectors, excess privilege in
+ * other selectors, invalid %eip's and invalid %esp's.
+ */
+ cs = ucp->uc_mcontext.mc_cs;
+ if (!CS_SECURE(cs)) {
+ printf("freebsd4_sigreturn: cs = 0x%x\n", cs);
+ trapsignal(td, SIGBUS, T_PROTFLT);
+ return (EINVAL);
+ }
+
+ /* Segment selectors restored by sigtramp.S */
+ regs->tf_rdi = ucp->uc_mcontext.mc_edi;
+ regs->tf_rsi = ucp->uc_mcontext.mc_esi;
+ regs->tf_rbp = ucp->uc_mcontext.mc_ebp;
+ regs->tf_rbx = ucp->uc_mcontext.mc_ebx;
+ regs->tf_rdx = ucp->uc_mcontext.mc_edx;
+ regs->tf_rcx = ucp->uc_mcontext.mc_ecx;
+ regs->tf_rax = ucp->uc_mcontext.mc_eax;
+ regs->tf_trapno = ucp->uc_mcontext.mc_trapno;
+ regs->tf_err = ucp->uc_mcontext.mc_err;
+ regs->tf_rip = ucp->uc_mcontext.mc_eip;
+ regs->tf_cs = cs;
+ regs->tf_rflags = ucp->uc_mcontext.mc_eflags;
+ regs->tf_rsp = ucp->uc_mcontext.mc_esp;
+ regs->tf_ss = ucp->uc_mcontext.mc_ss;
+
+ PROC_LOCK(p);
+ td->td_sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(td->td_sigmask);
+ signotify(td);
+ PROC_UNLOCK(p);
+ return (EJUSTRETURN);
+}
+#endif /* COMPAT_FREEBSD4 */
+
+/*
+ * MPSAFE
+ */
+int
+ia32_sigreturn(td, uap)
+ struct thread *td;
+ struct ia32_sigreturn_args /* {
+ const struct ia32_ucontext *sigcntxp;
+ } */ *uap;
+{
+ struct ia32_ucontext uc;
+ struct proc *p = td->td_proc;
+ struct trapframe *regs;
+ const struct ia32_ucontext *ucp;
+ int cs, eflags, error, ret;
+
+ error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+ if (error != 0)
+ return (error);
+ ucp = &uc;
+ regs = td->td_frame;
+ eflags = ucp->uc_mcontext.mc_eflags;
+ /*
+ * Don't allow users to change privileged or reserved flags.
+ */
+ /*
+ * XXX do allow users to change the privileged flag PSL_RF.
+ * The cpu sets PSL_RF in tf_eflags for faults. Debuggers
+ * should sometimes set it there too. tf_eflags is kept in
+ * the signal context during signal handling and there is no
+ * other place to remember it, so the PSL_RF bit may be
+ * corrupted by the signal handler without us knowing.
+ * Corruption of the PSL_RF bit at worst causes one more or
+ * one less debugger trap, so allowing it is fairly harmless.
+ */
+ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) {
+ printf("ia32_sigreturn: eflags = 0x%x\n", eflags);
+ return (EINVAL);
+ }
+
+ /*
+ * Don't allow users to load a valid privileged %cs. Let the
+ * hardware check for invalid selectors, excess privilege in
+ * other selectors, invalid %eip's and invalid %esp's.
+ */
+ cs = ucp->uc_mcontext.mc_cs;
+ if (!CS_SECURE(cs)) {
+ printf("sigreturn: cs = 0x%x\n", cs);
+ trapsignal(td, SIGBUS, T_PROTFLT);
+ return (EINVAL);
+ }
+
+ ret = ia32_set_fpcontext(td, &ucp->uc_mcontext);
+ if (ret != 0)
+ return (ret);
+
+ /* Segment selectors restored by sigtramp.S */
+ regs->tf_rdi = ucp->uc_mcontext.mc_edi;
+ regs->tf_rsi = ucp->uc_mcontext.mc_esi;
+ regs->tf_rbp = ucp->uc_mcontext.mc_ebp;
+ regs->tf_rbx = ucp->uc_mcontext.mc_ebx;
+ regs->tf_rdx = ucp->uc_mcontext.mc_edx;
+ regs->tf_rcx = ucp->uc_mcontext.mc_ecx;
+ regs->tf_rax = ucp->uc_mcontext.mc_eax;
+ regs->tf_trapno = ucp->uc_mcontext.mc_trapno;
+ regs->tf_err = ucp->uc_mcontext.mc_err;
+ regs->tf_rip = ucp->uc_mcontext.mc_eip;
+ regs->tf_cs = cs;
+ regs->tf_rflags = ucp->uc_mcontext.mc_eflags;
+ regs->tf_rsp = ucp->uc_mcontext.mc_esp;
+ regs->tf_ss = ucp->uc_mcontext.mc_ss;
+
+ PROC_LOCK(p);
+ td->td_sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(td->td_sigmask);
+ signotify(td);
+ PROC_UNLOCK(p);
+ return (EJUSTRETURN);
+}
diff --git a/sys/amd64/ia32/ia32_signal.h b/sys/amd64/ia32/ia32_signal.h
new file mode 100644
index 000000000000..f251e72fb33c
--- /dev/null
+++ b/sys/amd64/ia32/ia32_signal.h
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1999 Marcel Moolenaar
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+struct ia32_sigaltstack {
+ u_int32_t ss_sp; /* signal stack base */
+ u_int32_t ss_size; /* signal stack length */
+ int ss_flags; /* SS_DISABLE and/or SS_ONSTACK */
+};
+
+/* XXX should be 640 bytes long; check and see if __packed is needed */
+struct ia32_mcontext {
+ int mc_onstack; /* XXX - sigcontext compat. */
+ int mc_gs; /* machine state (struct trapframe) */
+ int mc_fs;
+ int mc_es;
+ int mc_ds;
+ int mc_edi;
+ int mc_esi;
+ int mc_ebp;
+ int mc_isp;
+ int mc_ebx;
+ int mc_edx;
+ int mc_ecx;
+ int mc_eax;
+ int mc_trapno;
+ int mc_err;
+ int mc_eip;
+ int mc_cs;
+ int mc_eflags;
+ int mc_esp;
+ int mc_ss;
+ int mc_len; /* sizeof(struct ia32_mcontext) */
+ /* We use the same values for fpformat and ownedfp */
+ int mc_fpformat;
+ int mc_ownedfp;
+ int mc_spare1[1]; /* align next field to 16 bytes */
+ /*
+ * See <machine/npx.h> for the internals of mc_fpstate[].
+ */
+ int mc_fpstate[128] __aligned(16);
+ int mc_spare2[8];
+};
+
+/* XXX should be 704 bytes long; check and see if __packed is needed */
+struct ia32_ucontext {
+ sigset_t uc_sigmask;
+ struct ia32_mcontext uc_mcontext;
+ u_int32_t uc_link;
+ struct ia32_sigaltstack uc_stack;
+ int uc_flags;
+ int __spare__[4];
+};
+
+
+#if defined(COMPAT_FREEBSD4)
+struct ia32_mcontext4 {
+ int mc_onstack; /* XXX - sigcontext compat. */
+ int mc_gs; /* machine state (struct trapframe) */
+ int mc_fs;
+ int mc_es;
+ int mc_ds;
+ int mc_edi;
+ int mc_esi;
+ int mc_ebp;
+ int mc_isp;
+ int mc_ebx;
+ int mc_edx;
+ int mc_ecx;
+ int mc_eax;
+ int mc_trapno;
+ int mc_err;
+ int mc_eip;
+ int mc_cs;
+ int mc_eflags;
+ int mc_esp;
+ int mc_ss;
+ int mc_fpregs[28];
+ int __spare__[17];
+};
+
+struct ia32_ucontext4 {
+ sigset_t uc_sigmask;
+ struct ia32_mcontext4 uc_mcontext;
+ u_int32_t uc_link;
+ struct ia32_sigaltstack uc_stack;
+ int __spare__[8];
+};
+#endif
+
+/*
+ * Signal frames, arguments passed to application signal handlers.
+ */
+union ia32_sigval {
+ int sigval_int;
+ u_int32_t sigval_ptr;
+};
+struct ia32_siginfo {
+ int si_signo; /* signal number */
+ int si_errno; /* errno association */
+ int si_code; /* signal code */
+ int32_t si_pid; /* sending process */
+ u_int32_t si_uid; /* sender's ruid */
+ int si_status; /* exit value */
+ u_int32_t si_addr; /* faulting instruction */
+ union ia32_sigval si_value; /* signal value */
+ int32_t si_band; /* band event for SIGPOLL */
+ int __spare__[7]; /* gimme some slack */
+};
+
+#ifdef COMPAT_FREEBSD4
+struct ia32_sigframe4 {
+ u_int32_t sf_signum;
+ u_int32_t sf_siginfo; /* code or pointer to sf_si */
+ u_int32_t sf_ucontext; /* points to sf_uc */
+ u_int32_t sf_addr; /* undocumented 4th arg */
+ u_int32_t sf_ah; /* action/handler pointer */
+ struct ia32_ucontext4 sf_uc; /* = *sf_ucontext */
+ struct ia32_siginfo sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+};
+#endif
+
+struct ia32_sigframe {
+ u_int32_t sf_signum;
+ u_int32_t sf_siginfo; /* code or pointer to sf_si */
+ u_int32_t sf_ucontext; /* points to sf_uc */
+ u_int32_t sf_addr; /* undocumented 4th arg */
+ u_int32_t sf_ah; /* action/handler pointer */
+ struct ia32_ucontext sf_uc; /* = *sf_ucontext */
+ struct ia32_siginfo sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+};
+
+extern char ia32_sigcode[];
+extern char freebsd4_ia32_sigcode[];
+extern int sz_ia32_sigcode;
+extern int sz_freebsd4_ia32_sigcode;
+extern void ia32_sendsig(sig_t, int, sigset_t *, u_long);
diff --git a/sys/amd64/ia32/ia32_sigtramp.S b/sys/amd64/ia32/ia32_sigtramp.S
new file mode 100644
index 000000000000..2e9f73d41bce
--- /dev/null
+++ b/sys/amd64/ia32/ia32_sigtramp.S
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_compat.h"
+
+#include <machine/asmacros.h>
+#include <sys/syscall.h>
+
+#include "ia32_assym.h"
+
+ .text
+ .code32
+/*
+ * Signal trampoline, copied to top of user stack
+ */
+ ALIGN_TEXT
+ .globl ia32_sigcode
+ia32_sigcode:
+ calll *IA32_SIGF_HANDLER(%esp)
+ leal IA32_SIGF_UC(%esp),%eax /* get ucontext */
+ pushl %eax
+ movl IA32_UC_GS(%eax),%gs /* restore %gs */
+ movl IA32_UC_FS(%eax),%fs /* restore %fs */
+ movl IA32_UC_ES(%eax),%es /* restore %es */
+ movl IA32_UC_DS(%eax),%ds /* restore %ds */
+ movl $SYS_sigreturn,%eax
+ pushl %eax /* junk to fake return addr. */
+ int $0x80 /* enter kernel with args */
+ /* on stack */
+1:
+ jmp 1b
+
+#ifdef COMPAT_FREEBSD4
+ ALIGN_TEXT
+freebsd4_ia32_sigcode:
+ calll *IA32_SIGF_HANDLER(%esp)
+ leal IA32_SIGF_UC4(%esp),%eax/* get ucontext */
+ pushl %eax
+ movl IA32_UC4_GS(%eax),%gs /* restore %gs */
+ movl IA32_UC4_FS(%eax),%fs /* restore %fs */
+ movl IA32_UC4_ES(%eax),%es /* restore %es */
+ movl IA32_UC4_DS(%eax),%ds /* restore %ds */
+ movl $344,%eax /* 4.x SYS_sigreturn */
+ pushl %eax /* junk to fake return addr. */
+ int $0x80 /* enter kernel with args */
+ /* on stack */
+1:
+ jmp 1b
+#endif
+
+ ALIGN_TEXT
+esigcode:
+
+ .data
+ .globl sz_ia32_sigcode
+sz_ia32_sigcode:
+ .long esigcode-ia32_sigcode
+#ifdef COMPAT_FREEBSD4
+ .globl sz_freebsd4_ia32_sigcode
+sz_freebsd4_ia32_sigcode:
+ .long esigcode-freebsd4_ia32_sigcode
+#endif
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
new file mode 100644
index 000000000000..dee52b0e75ba
--- /dev/null
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -0,0 +1,275 @@
+/*-
+ * Copyright (C) 1994, David Greenman
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * 386 Trap and System call handling
+ */
+
+#include "opt_clock.h"
+#include "opt_cpu.h"
+#include "opt_isa.h"
+#include "opt_ktrace.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/pioctl.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/uio.h>
+#include <sys/vmmeter.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+
+#include <amd64/isa/icu.h>
+#include <amd64/isa/intr_machdep.h>
+
+#define IDTVEC(name) __CONCAT(X,name)
+
+extern inthand_t IDTVEC(int0x80_syscall), IDTVEC(rsvd);
+
+void ia32_syscall(struct trapframe frame); /* Called from asm code */
+
+void
+ia32_syscall(struct trapframe frame)
+{
+ caddr_t params;
+ int i;
+ struct sysent *callp;
+ struct thread *td = curthread;
+ struct proc *p = td->td_proc;
+ register_t orig_tf_rflags;
+ u_int sticks;
+ int error;
+ int narg;
+ u_int32_t args[8];
+ u_int64_t args64[8];
+ u_int code;
+
+ /*
+ * note: PCPU_LAZY_INC() can only be used if we can afford
+ * occassional inaccuracy in the count.
+ */
+ cnt.v_syscall++;
+
+ sticks = td->td_sticks;
+ td->td_frame = &frame;
+ if (td->td_ucred != p->p_ucred)
+ cred_update_thread(td);
+ params = (caddr_t)frame.tf_rsp + sizeof(u_int32_t);
+ code = frame.tf_rax;
+ orig_tf_rflags = frame.tf_rflags;
+
+ if (p->p_sysent->sv_prepsyscall) {
+ /*
+ * The prep code is MP aware.
+ */
+ (*p->p_sysent->sv_prepsyscall)(&frame, args, &code, &params);
+ } else {
+ /*
+ * Need to check if this is a 32 bit or 64 bit syscall.
+ * fuword is MP aware.
+ */
+ if (code == SYS_syscall) {
+ /*
+ * Code is first argument, followed by actual args.
+ */
+ code = fuword32(params);
+ params += sizeof(int);
+ } else if (code == SYS___syscall) {
+ /*
+ * Like syscall, but code is a quad, so as to maintain
+ * quad alignment for the rest of the arguments.
+ * We use a 32-bit fetch in case params is not
+ * aligned.
+ */
+ code = fuword32(params);
+ params += sizeof(quad_t);
+ }
+ }
+
+ if (p->p_sysent->sv_mask)
+ code &= p->p_sysent->sv_mask;
+
+ if (code >= p->p_sysent->sv_size)
+ callp = &p->p_sysent->sv_table[0];
+ else
+ callp = &p->p_sysent->sv_table[code];
+
+ narg = callp->sy_narg & SYF_ARGMASK;
+
+ /*
+ * copyin and the ktrsyscall()/ktrsysret() code is MP-aware
+ */
+ if (params != NULL && narg != 0)
+ error = copyin(params, (caddr_t)args,
+ (u_int)(narg * sizeof(int)));
+ else
+ error = 0;
+
+ for (i = 0; i < narg; i++)
+ args64[i] = args[i];
+
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_SYSCALL))
+ ktrsyscall(code, narg, args64);
+#endif
+ /*
+ * Try to run the syscall without Giant if the syscall
+ * is MP safe.
+ */
+ if ((callp->sy_narg & SYF_MPSAFE) == 0)
+ mtx_lock(&Giant);
+
+ if (error == 0) {
+ td->td_retval[0] = 0;
+ td->td_retval[1] = frame.tf_rdx;
+
+ STOPEVENT(p, S_SCE, narg);
+
+ error = (*callp->sy_call)(td, args64);
+ }
+
+ switch (error) {
+ case 0:
+ frame.tf_rax = td->td_retval[0];
+ frame.tf_rdx = td->td_retval[1];
+ frame.tf_rflags &= ~PSL_C;
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes,
+ * int 0x80 is 2 bytes. We saved this in tf_err.
+ */
+ frame.tf_rip -= frame.tf_err;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ if (p->p_sysent->sv_errsize) {
+ if (error >= p->p_sysent->sv_errsize)
+ error = -1; /* XXX */
+ else
+ error = p->p_sysent->sv_errtbl[error];
+ }
+ frame.tf_rax = error;
+ frame.tf_rflags |= PSL_C;
+ break;
+ }
+
+ /*
+ * Release Giant if we previously set it.
+ */
+ if ((callp->sy_narg & SYF_MPSAFE) == 0)
+ mtx_unlock(&Giant);
+
+ /*
+ * Traced syscall.
+ */
+ if (orig_tf_rflags & PSL_T) {
+ frame.tf_rflags &= ~PSL_T;
+ trapsignal(td, SIGTRAP, 0);
+ }
+
+ /*
+ * Handle reschedule and other end-of-syscall issues
+ */
+ userret(td, &frame, sticks);
+
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_SYSRET))
+ ktrsysret(code, error, td->td_retval[0]);
+#endif
+
+ /*
+ * This works because errno is findable through the
+ * register set. If we ever support an emulation where this
+ * is not the case, this code will need to be revisited.
+ */
+ STOPEVENT(p, S_SCX, code);
+
+#ifdef DIAGNOSTIC
+ cred_free_thread(td);
+#endif
+ WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
+ (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
+ mtx_assert(&sched_lock, MA_NOTOWNED);
+ mtx_assert(&Giant, MA_NOTOWNED);
+}
+
+
+static void
+ia32_syscall_enable(void *dummy)
+{
+
+ setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYSIGT, SEL_UPL, 0);
+}
+
+static void
+ia32_syscall_disable(void *dummy)
+{
+
+ setidt(0x80, &IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
+}
+
+SYSINIT(ia32_syscall, SI_SUB_EXEC, SI_ORDER_ANY, ia32_syscall_enable, NULL);
+SYSUNINIT(ia32_syscall, SI_SUB_EXEC, SI_ORDER_ANY, ia32_syscall_disable, NULL);
diff --git a/sys/amd64/ia32/ia32_sysvec.c b/sys/amd64/ia32/ia32_sysvec.c
index 18f4ee2fc78c..684677a7cf88 100644
--- a/sys/amd64/ia32/ia32_sysvec.c
+++ b/sys/amd64/ia32/ia32_sysvec.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2003 Peter Wemm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,6 +27,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#define __ELF_WORD_SIZE 32
#include <sys/param.h>
@@ -60,12 +63,16 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
-#include <ia64/ia32/ia32_util.h>
-#include <i386/include/psl.h>
-#include <i386/include/segments.h>
-#include <i386/include/specialreg.h>
+#include <amd64/ia32/ia32_util.h>
+#include <amd64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32_signal.h>
+#include <machine/psl.h>
+#include <machine/segments.h>
+#include <machine/specialreg.h>
#include <machine/frame.h>
#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cpufunc.h>
static register_t *ia32_copyout_strings(struct image_params *imgp);
static void ia32_setregs(struct thread *td, u_long entry, u_long stack,
@@ -73,21 +80,6 @@ static void ia32_setregs(struct thread *td, u_long entry, u_long stack,
extern struct sysent ia32_sysent[];
-static char ia32_sigcode[] = {
- 0xff, 0x54, 0x24, 0x10, /* call *SIGF_HANDLER(%esp) */
- 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC(%esp),%eax */
- 0x50, /* pushl %eax */
- 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x02, /* testl $PSL_VM,UC_EFLAGS(%eax) */
- 0x75, 0x03, /* jne 9f */
- 0x8e, 0x68, 0x14, /* movl UC_GS(%eax),%gs */
- 0xb8, 0x57, 0x01, 0x00, 0x00, /* 9: movl $SYS_sigreturn,%eax */
- 0x50, /* pushl %eax */
- 0xcd, 0x80, /* int $0x80 */
- 0xeb, 0xfe, /* 0: jmp 0b */
- 0, 0, 0, 0
-};
-static int ia32_szsigcode = sizeof(ia32_sigcode) & ~3;
-
struct sysentvec ia32_freebsd_sysvec = {
SYS_MAXSYSCALL,
ia32_sysent,
@@ -98,24 +90,26 @@ struct sysentvec ia32_freebsd_sysvec = {
NULL,
NULL,
elf32_freebsd_fixup,
- sendsig,
+ ia32_sendsig,
ia32_sigcode,
- &ia32_szsigcode,
+ &sz_ia32_sigcode,
NULL,
- "FreeBSD ELF",
+ "FreeBSD ELF32",
elf32_coredump,
NULL,
MINSIGSTKSZ,
- 4096,
+ PAGE_SIZE,
0,
- IA32_USRSTACK,
- IA32_USRSTACK,
- IA32_PS_STRINGS,
+ USRSTACK,
+ USRSTACK,
+ PS_STRINGS,
VM_PROT_ALL,
ia32_copyout_strings,
ia32_setregs
};
+
+
static Elf32_Brandinfo ia32_brand_info = {
ELFOSABI_FREEBSD,
EM_386,
@@ -129,6 +123,8 @@ SYSINIT(ia32, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf32_insert_brand_entry,
&ia32_brand_info);
+extern int _ucode32sel, _udatasel;
+
static register_t *
ia32_copyout_strings(struct image_params *imgp)
{
@@ -143,7 +139,7 @@ ia32_copyout_strings(struct image_params *imgp)
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
*/
- arginfo = (struct ia32_ps_strings *)IA32_PS_STRINGS;
+ arginfo = (struct ia32_ps_strings *)PS_STRINGS;
szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
roundup((ARG_MAX - imgp->stringspace), sizeof(char *));
@@ -190,7 +186,6 @@ ia32_copyout_strings(struct image_params *imgp)
stringp = imgp->stringbase;
argc = imgp->argc;
envc = imgp->envc;
-
/*
* Copy out strings - arguments and environment.
*/
@@ -234,135 +229,61 @@ ia32_copyout_strings(struct image_params *imgp)
return ((register_t *)stack_base);
}
-static void
-ia32_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings)
+/*
+ * Clear registers on exec
+ */
+void
+ia32_setregs(td, entry, stack, ps_strings)
+ struct thread *td;
+ u_long entry;
+ u_long stack;
+ u_long ps_strings;
{
- struct trapframe *frame = td->td_frame;
- vm_offset_t gdt, ldt;
- u_int64_t codesel, datasel, ldtsel;
- u_int64_t codeseg, dataseg, gdtseg, ldtseg;
- struct segment_descriptor desc;
- struct vmspace *vmspace = td->td_proc->p_vmspace;
+ struct trapframe *regs = td->td_frame;
+ struct pcb *pcb = td->td_pcb;
+ u_int64_t pc;
+ register_t s;
+
+ wrmsr(MSR_FSBASE, 0);
+ wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
+ pcb->pcb_fsbase = 0;
+ pcb->pcb_gsbase = 0;
+ pcb->pcb_kgsbase = rdmsr(MSR_GSBASE);
+ load_ds(_udatasel);
+ load_es(_udatasel);
+ load_fs(_udatasel);
+ s = intr_disable();
+ pc = rdmsr(MSR_GSBASE);
+ load_gs(_udatasel); /* Clobbers kernel %GS.base */
+ wrmsr(MSR_GSBASE, pc);
+ intr_restore(s);
+ pcb->pcb_ds = _udatasel;
+ pcb->pcb_es = _udatasel;
+ pcb->pcb_fs = _udatasel;
+ pcb->pcb_gs = _udatasel;
+
+ bzero((char *)regs, sizeof(struct trapframe));
+ regs->tf_rip = entry;
+ regs->tf_rsp = stack;
+ regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+ regs->tf_ss = _udatasel;
+ regs->tf_cs = _ucode32sel;
+ regs->tf_rbx = ps_strings;
/*
- * Make sure that we restore the entire trapframe after an
- * execve.
+ * Arrange to trap the next npx or `fwait' instruction (see npx.c
+ * for why fwait must be trapped at least if there is an npx or an
+ * emulator). This is mainly to handle the case where npx0 is not
+ * configured, since the npx routines normally set up the trap
+ * otherwise. It should be done only at boot time, but doing it
+ * here allows modifying `npx_exists' for testing the emulator on
+ * systems with an npx.
*/
- frame->tf_flags &= ~FRAME_SYSCALL;
-
- bzero(frame->tf_r, sizeof(frame->tf_r));
- bzero(frame->tf_f, sizeof(frame->tf_f));
-
- frame->tf_cr_iip = entry;
- frame->tf_cr_ipsr = (IA64_PSR_IC
- | IA64_PSR_I
- | IA64_PSR_IT
- | IA64_PSR_DT
- | IA64_PSR_RT
- | IA64_PSR_DFH
- | IA64_PSR_IS
- | IA64_PSR_BN
- | IA64_PSR_CPL_USER);
- frame->tf_r[FRAME_R12] = stack;
-
- codesel = LSEL(LUCODE_SEL, SEL_UPL);
- datasel = LSEL(LUDATA_SEL, SEL_UPL);
- ldtsel = GSEL(GLDT_SEL, SEL_UPL);
-
-#if 1
- frame->tf_r[FRAME_R16] = (datasel << 48) | (datasel << 32)
- | (datasel << 16) | datasel;
- frame->tf_r[FRAME_R17] = (ldtsel << 32) | (datasel << 16) | codesel;
-#else
- frame->tf_r[FRAME_R16] = datasel;
- frame->tf_r[FRAME_R17] = codesel;
- frame->tf_r[FRAME_R18] = datasel;
- frame->tf_r[FRAME_R19] = datasel;
- frame->tf_r[FRAME_R20] = datasel;
- frame->tf_r[FRAME_R21] = datasel;
- frame->tf_r[FRAME_R22] = ldtsel;
-#endif
+ load_cr0(rcr0() | CR0_MP | CR0_TS);
- /*
- * Build the GDT and LDT.
- */
- gdt = IA32_USRSTACK;
- vm_map_find(&vmspace->vm_map, 0, 0,
- &gdt, PAGE_SIZE, 0,
- VM_PROT_ALL, VM_PROT_ALL, 0);
- ldt = gdt + 4096;
-
- desc.sd_lolimit = 8*NLDT-1;
- desc.sd_lobase = ldt & 0xffffff;
- desc.sd_type = SDT_SYSLDT;
- desc.sd_dpl = SEL_UPL;
- desc.sd_p = 1;
- desc.sd_hilimit = 0;
- desc.sd_def32 = 0;
- desc.sd_gran = 0;
- desc.sd_hibase = ldt >> 24;
- copyout(&desc, (caddr_t) gdt + 8*GLDT_SEL, sizeof(desc));
-
- desc.sd_lolimit = ((IA32_USRSTACK >> 12) - 1) & 0xffff;
- desc.sd_lobase = 0;
- desc.sd_type = SDT_MEMERA;
- desc.sd_dpl = SEL_UPL;
- desc.sd_p = 1;
- desc.sd_hilimit = ((IA32_USRSTACK >> 12) - 1) >> 16;
- desc.sd_def32 = 1;
- desc.sd_gran = 1;
- desc.sd_hibase = 0;
- copyout(&desc, (caddr_t) ldt + 8*LUCODE_SEL, sizeof(desc));
- desc.sd_type = SDT_MEMRWA;
- copyout(&desc, (caddr_t) ldt + 8*LUDATA_SEL, sizeof(desc));
-
- codeseg = 0 /* base */
- + (((IA32_USRSTACK >> 12) - 1) << 32) /* limit */
- + ((long)SDT_MEMERA << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (1L << 62) /* 32 bits */
- + (1L << 63); /* page granularity */
- dataseg = 0 /* base */
- + (((IA32_USRSTACK >> 12) - 1) << 32) /* limit */
- + ((long)SDT_MEMRWA << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (1L << 62) /* 32 bits */
- + (1L << 63); /* page granularity */
- ia64_set_csd(codeseg);
- ia64_set_ssd(dataseg);
- frame->tf_r[FRAME_R24] = dataseg; /* ESD */
- frame->tf_r[FRAME_R27] = dataseg; /* DSD */
- frame->tf_r[FRAME_R28] = dataseg; /* FSD */
- frame->tf_r[FRAME_R29] = dataseg; /* GSD */
-
- gdtseg = gdt /* base */
- + ((8L*NGDT - 1) << 32) /* limit */
- + ((long)SDT_SYSNULL << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (0L << 62) /* 16 bits */
- + (0L << 63); /* byte granularity */
- ldtseg = ldt /* base */
- + ((8L*NLDT - 1) << 32) /* limit */
- + ((long)SDT_SYSLDT << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (0L << 62) /* 16 bits */
- + (0L << 63); /* byte granularity */
- frame->tf_r[FRAME_R30] = ldtseg; /* LDTD */
- frame->tf_r[FRAME_R31] = gdtseg; /* GDTD */
-
- ia64_set_eflag(PSL_USER);
-
- /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */
- frame->tf_r[FRAME_R11] = IA32_PS_STRINGS;
+ fpstate_drop(td);
- /*
- * XXX - Linux emulator
- * Make sure sure edx is 0x0 on entry. Linux binaries depend
- * on it.
- */
+ /* Return via doreti so that we can change to a different %cs */
+ pcb->pcb_flags |= PCB_FULLCTX;
td->td_retval[1] = 0;
}
diff --git a/sys/amd64/ia32/ia32_util.h b/sys/amd64/ia32/ia32_util.h
index 23f2abae1ab2..20a5b1e28416 100644
--- a/sys/amd64/ia32/ia32_util.h
+++ b/sys/amd64/ia32/ia32_util.h
@@ -44,7 +44,7 @@ struct ia32_ps_strings {
int ps_nenvstr; /* the number of environment strings */
};
-#define IA32_USRSTACK (4L*1024*1024*1024 - PAGE_SIZE)
+#define IA32_USRSTACK USRSTACK
#define IA32_PS_STRINGS (IA32_USRSTACK - sizeof(struct ia32_ps_strings))
static __inline caddr_t stackgap_init(void);
diff --git a/sys/amd64/ia32/syscalls.master b/sys/amd64/ia32/syscalls.master
index 508fdf78b8fb..042bf003b1c3 100644
--- a/sys/amd64/ia32/syscalls.master
+++ b/sys/amd64/ia32/syscalls.master
@@ -37,8 +37,8 @@
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/mount.h>
-#include <ia64/ia32/ia32.h>
-#include <ia64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32.h>
+#include <amd64/ia32/ia32_proto.h>
; Reserved/unimplemented system calls in the range 0-150 inclusive
; are reserved for use in future Berkeley releases.
@@ -484,11 +484,11 @@
340 MNOPROTO POSIX { int sigprocmask(int how, const sigset_t *set, \
sigset_t *oset); }
341 MNOPROTO POSIX { int sigsuspend(const sigset_t *sigmask); }
-342 STD POSIX { int ia32_sigaction(int sig, \
+342 COMPAT4 POSIX { int ia32_sigaction(int sig, \
struct sigaction32 *act, \
struct sigaction32 *oact); }
343 MNOPROTO POSIX { int sigpending(sigset_t *set); }
-344 MNOPROTO BSD { int sigreturn(const struct __ucontext *sigcntxp); }
+344 MCOMPAT4 BSD { int ia32_sigreturn(const struct __ucontext *sigcntxp); }
345 UNIMPL NOHIDE sigtimedwait
346 UNIMPL NOHIDE sigwaitinfo
347 MNOPROTO BSD { int __acl_get_file(const char *path, \
@@ -521,7 +521,7 @@
360 MNOPROTO BSD { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
361 MNOPROTO BSD { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
362 MNOPROTO BSD { int kqueue(void); }
-363 MNOPROTO BSD { int kevent(int fd, \
+363 MSTD BSD { int ia32_kevent(int fd, \
const struct kevent *changelist, int nchanges, \
struct kevent *eventlist, int nevents, \
const struct timespec *timeout); }
@@ -586,8 +586,10 @@
413 UNIMPL BSD extattr_get_link
414 UNIMPL BSD extattr_delete_link
415 UNIMPL BSD __mac_execve
-416 UNIMPL BSD newsigreturn
-417 UNIMPL BSD newsigaction
+416 MSTD BSD { int ia32_sigreturn(const struct ia32_ucontext *sigcntxp); }
+417 STD POSIX { int ia32_sigaction(int sig, \
+ struct sigaction32 *act, \
+ struct sigaction32 *oact); }
418 UNIMPL BSD __xstat
419 UNIMPL BSD __xfstat
420 UNIMPL BSD __xlstat
diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
index 1e1df330e841..21257dda301b 100644
--- a/sys/amd64/include/cpufunc.h
+++ b/sys/amd64/include/cpufunc.h
@@ -447,7 +447,6 @@ invlpg(u_long addr)
__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
}
-/* XXX these are replaced with rdmsr/wrmsr */
static __inline u_int
rfs(void)
{
@@ -465,6 +464,18 @@ rgs(void)
}
static __inline void
+load_ds(u_int sel)
+{
+ __asm __volatile("movl %0,%%ds" : : "rm" (sel));
+}
+
+static __inline void
+load_es(u_int sel)
+{
+ __asm __volatile("movl %0,%%es" : : "rm" (sel));
+}
+
+static __inline void
load_fs(u_int sel)
{
__asm __volatile("movl %0,%%fs" : : "rm" (sel));
diff --git a/sys/amd64/include/elf.h b/sys/amd64/include/elf.h
index 3883d49302c0..b675859553e9 100644
--- a/sys/amd64/include/elf.h
+++ b/sys/amd64/include/elf.h
@@ -33,9 +33,12 @@
* ELF definitions for the AMD64 architecture.
*/
-#include <sys/elf64.h> /* Definitions common to all 64 bit architectures. */
+#ifndef __ELF_WORD_SIZE
#define __ELF_WORD_SIZE 64 /* Used by <sys/elf_generic.h> */
+#endif
+#include <sys/elf32.h> /* Definitions common to all 32 bit architectures. */
+#include <sys/elf64.h> /* Definitions common to all 64 bit architectures. */
#include <sys/elf_generic.h>
#define ELF_ARCH EM_X86_64
@@ -48,6 +51,13 @@
* The i386 supplement to the SVR4 ABI specification names this "auxv_t",
* but POSIX lays claim to all symbols ending with "_t".
*/
+typedef struct { /* Auxiliary vector entry on initial stack */
+ int a_type; /* Entry type. */
+ union {
+ int a_val; /* Integer value. */
+ } a_un;
+} Elf32_Auxinfo;
+
typedef struct { /* Auxiliary vector entry on initial stack */
long a_type; /* Entry type. */
@@ -118,7 +128,11 @@ __ElfType(Auxinfo);
#define R_X86_64_COUNT 16 /* Count of defined relocation types. */
/* Define "machine" characteristics */
-#define ELF_TARG_CLASS ELFCLASS64
+#if __ELF_WORD_SIZE == 32
+#define ELF_TARG_CLASS ELFCLASS32
+#else
+#define ELF_TARG_CLASS ELFCLASS64
+#endif
#define ELF_TARG_DATA ELFDATA2LSB
#define ELF_TARG_MACH EM_X86_64
#define ELF_TARG_VER 1
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index ad35173a4a1a..63e9b2be4e9e 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -69,5 +69,6 @@ void pagezero(void *addr);
int is_physical_memory(vm_offset_t addr);
void setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int ist);
void swi_vm(void *);
+void fpstate_drop(struct thread *td);
#endif /* !_MACHINE_MD_VAR_H_ */
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
index c17709b225af..5bfb41f9e20e 100644
--- a/sys/amd64/include/pcb.h
+++ b/sys/amd64/include/pcb.h
@@ -59,6 +59,11 @@ struct pcb {
register_t pcb_rflags;
register_t pcb_fsbase;
register_t pcb_gsbase;
+ register_t pcb_kgsbase;
+ u_int32_t pcb_ds;
+ u_int32_t pcb_es;
+ u_int32_t pcb_fs;
+ u_int32_t pcb_gs;
struct savefpu pcb_save;
u_long pcb_flags;
diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h
index 0f9a59bd5f75..919eeff4023e 100644
--- a/sys/amd64/include/segments.h
+++ b/sys/amd64/include/segments.h
@@ -166,7 +166,7 @@ struct region_descriptor {
/*
* Size of IDT table
*/
-#define NIDT 129 /* 32 reserved, 16 h/w, 0 s/w, linux's 0x80 */
+#define NIDT 256 /* 32 reserved, 16 h/w, 0 s/w, linux's 0x80 */
#define NRSVIDT 32 /* reserved entries for cpu exceptions */
/*
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index c1cdd2037664..9ef02c5c2421 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -74,9 +74,9 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
-#include <ia64/ia32/ia32_util.h>
-#include <ia64/ia32/ia32.h>
-#include <ia64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32_util.h>
+#include <amd64/ia32/ia32.h>
+#include <amd64/ia32/ia32_proto.h>
static const char ia32_emul_path[] = "/compat/ia32";
/*
@@ -439,6 +439,7 @@ ia32_execve(struct thread *td, struct ia32_execve_args *uap)
return execve(td, &ap);
}
+#ifdef __ia64__
static int
ia32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
int prot, int fd, off_t pos)
@@ -485,6 +486,7 @@ ia32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
return (0);
}
}
+#endif
int
ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
@@ -497,6 +499,7 @@ ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
int fd = uap->fd;
off_t pos = (uap->poslo
| ((off_t)uap->poshi << 32));
+#ifdef __ia64__
vm_size_t pageoff;
int error;
@@ -567,6 +570,7 @@ ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
addr = start;
len = end - start;
}
+#endif
ap.addr = (void *) addr;
ap.len = len;
@@ -653,6 +657,83 @@ ia32_select(struct thread *td, struct ia32_select_args *uap)
return (select(td, (struct select_args *) uap));
}
+struct kevent32 {
+ u_int32_t ident; /* identifier for this event */
+ short filter; /* filter for event */
+ u_short flags;
+ u_int fflags;
+ int32_t data;
+ u_int32_t udata; /* opaque user data identifier */
+};
+
+int
+ia32_kevent(struct thread *td, struct ia32_kevent_args *uap)
+{
+ int error;
+ caddr_t sg;
+ struct timespec32 ts32;
+ struct timespec ts;
+ struct kevent32 ks32;
+ struct kevent *ks;
+ struct kevent_args a;
+ int i;
+
+ sg = stackgap_init();
+
+ a.fd = uap->fd;
+ a.changelist = uap->changelist;
+ a.nchanges = uap->nchanges;
+ a.eventlist = uap->eventlist;
+ a.nevents = uap->nevents;
+ a.timeout = NULL;
+
+ if (uap->timeout) {
+ a.timeout = stackgap_alloc(&sg, sizeof(struct timespec));
+ error = copyin(uap->timeout, &ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32, ts, tv_sec);
+ CP(ts32, ts, tv_nsec);
+ error = copyout(&ts, (void *)(uintptr_t)a.timeout, sizeof(ts));
+ if (error)
+ return (error);
+ }
+ if (uap->changelist) {
+ a.changelist = (struct kevent *)stackgap_alloc(&sg, uap->nchanges * sizeof(struct kevent));
+ for (i = 0; i < uap->nchanges; i++) {
+ error = copyin(&uap->changelist[i], &ks32, sizeof(ks32));
+ if (error)
+ return (error);
+ ks = (struct kevent *)(uintptr_t)&a.changelist[i];
+ CP(ks32, *ks, ident);
+ CP(ks32, *ks, filter);
+ CP(ks32, *ks, flags);
+ CP(ks32, *ks, fflags);
+ CP(ks32, *ks, data);
+ PTRIN_CP(ks32, *ks, udata);
+ }
+ }
+ if (uap->eventlist) {
+ a.eventlist = stackgap_alloc(&sg, uap->nevents * sizeof(struct kevent));
+ }
+ error = kevent(td, &a);
+ if (uap->eventlist && error > 0) {
+ for (i = 0; i < error; i++) {
+ ks = &a.eventlist[i];
+ CP(*ks, ks32, ident);
+ CP(*ks, ks32, filter);
+ CP(*ks, ks32, flags);
+ CP(*ks, ks32, fflags);
+ CP(*ks, ks32, data);
+ PTROUT_CP(*ks, ks32, udata);
+ error = copyout(&ks32, &uap->eventlist[i], sizeof(ks32));
+ if (error)
+ return (error);
+ }
+ }
+ return error;
+}
+
int
ia32_gettimeofday(struct thread *td, struct ia32_gettimeofday_args *uap)
{
@@ -1287,6 +1368,35 @@ ia32_sigaction(struct thread *td, struct ia32_sigaction_args *uap)
return (error);
}
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_ia32_sigaction(struct thread *td, struct freebsd4_ia32_sigaction_args *uap)
+{
+ struct sigaction32 s32;
+ struct sigaction sa, osa, *sap;
+ int error;
+
+ if (uap->act) {
+ error = copyin(uap->act, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ sa.sa_handler = PTRIN(s32.sa_u);
+ CP(s32, sa, sa_flags);
+ CP(s32, sa, sa_mask);
+ sap = &sa;
+ } else
+ sap = NULL;
+ error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
+ if (error != 0 && uap->oact != NULL) {
+ s32.sa_u = PTROUT(osa.sa_handler);
+ CP(osa, s32, sa_flags);
+ CP(osa, s32, sa_mask);
+ error = copyout(&s32, uap->oact, sizeof(s32));
+ }
+ return (error);
+}
+#endif
+
#if 0
int
diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h
index 23f2abae1ab2..20a5b1e28416 100644
--- a/sys/compat/freebsd32/freebsd32_util.h
+++ b/sys/compat/freebsd32/freebsd32_util.h
@@ -44,7 +44,7 @@ struct ia32_ps_strings {
int ps_nenvstr; /* the number of environment strings */
};
-#define IA32_USRSTACK (4L*1024*1024*1024 - PAGE_SIZE)
+#define IA32_USRSTACK USRSTACK
#define IA32_PS_STRINGS (IA32_USRSTACK - sizeof(struct ia32_ps_strings))
static __inline caddr_t stackgap_init(void);
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 508fdf78b8fb..042bf003b1c3 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -37,8 +37,8 @@
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/mount.h>
-#include <ia64/ia32/ia32.h>
-#include <ia64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32.h>
+#include <amd64/ia32/ia32_proto.h>
; Reserved/unimplemented system calls in the range 0-150 inclusive
; are reserved for use in future Berkeley releases.
@@ -484,11 +484,11 @@
340 MNOPROTO POSIX { int sigprocmask(int how, const sigset_t *set, \
sigset_t *oset); }
341 MNOPROTO POSIX { int sigsuspend(const sigset_t *sigmask); }
-342 STD POSIX { int ia32_sigaction(int sig, \
+342 COMPAT4 POSIX { int ia32_sigaction(int sig, \
struct sigaction32 *act, \
struct sigaction32 *oact); }
343 MNOPROTO POSIX { int sigpending(sigset_t *set); }
-344 MNOPROTO BSD { int sigreturn(const struct __ucontext *sigcntxp); }
+344 MCOMPAT4 BSD { int ia32_sigreturn(const struct __ucontext *sigcntxp); }
345 UNIMPL NOHIDE sigtimedwait
346 UNIMPL NOHIDE sigwaitinfo
347 MNOPROTO BSD { int __acl_get_file(const char *path, \
@@ -521,7 +521,7 @@
360 MNOPROTO BSD { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
361 MNOPROTO BSD { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
362 MNOPROTO BSD { int kqueue(void); }
-363 MNOPROTO BSD { int kevent(int fd, \
+363 MSTD BSD { int ia32_kevent(int fd, \
const struct kevent *changelist, int nchanges, \
struct kevent *eventlist, int nevents, \
const struct timespec *timeout); }
@@ -586,8 +586,10 @@
413 UNIMPL BSD extattr_get_link
414 UNIMPL BSD extattr_delete_link
415 UNIMPL BSD __mac_execve
-416 UNIMPL BSD newsigreturn
-417 UNIMPL BSD newsigaction
+416 MSTD BSD { int ia32_sigreturn(const struct ia32_ucontext *sigcntxp); }
+417 STD POSIX { int ia32_sigaction(int sig, \
+ struct sigaction32 *act, \
+ struct sigaction32 *oact); }
418 UNIMPL BSD __xstat
419 UNIMPL BSD __xfstat
420 UNIMPL BSD __xlstat
diff --git a/sys/compat/ia32/ia32_genassym.c b/sys/compat/ia32/ia32_genassym.c
new file mode 100644
index 000000000000..2134a4477c45
--- /dev/null
+++ b/sys/compat/ia32/ia32_genassym.c
@@ -0,0 +1,24 @@
+/* $FreeBSD$ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/assym.h>
+#include <sys/systm.h>
+#include <sys/signal.h>
+
+#include <amd64/ia32/ia32_signal.h>
+
+ASSYM(IA32_SIGF_HANDLER, offsetof(struct ia32_sigframe, sf_ah));
+ASSYM(IA32_SIGF_UC, offsetof(struct ia32_sigframe, sf_uc));
+ASSYM(IA32_UC_GS, offsetof(struct ia32_ucontext, uc_mcontext.mc_gs));
+ASSYM(IA32_UC_FS, offsetof(struct ia32_ucontext, uc_mcontext.mc_fs));
+ASSYM(IA32_UC_ES, offsetof(struct ia32_ucontext, uc_mcontext.mc_es));
+ASSYM(IA32_UC_DS, offsetof(struct ia32_ucontext, uc_mcontext.mc_ds));
+#ifdef COMPAT_FREEBSD4
+ASSYM(IA32_SIGF_UC4, offsetof(struct ia32_sigframe, sf_uc));
+ASSYM(IA32_UC4_GS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_gs));
+ASSYM(IA32_UC4_FS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_fs));
+ASSYM(IA32_UC4_ES, offsetof(struct ia32_ucontext4, uc_mcontext.mc_es));
+ASSYM(IA32_UC4_DS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_ds));
+#endif
diff --git a/sys/compat/ia32/ia32_signal.h b/sys/compat/ia32/ia32_signal.h
new file mode 100644
index 000000000000..f251e72fb33c
--- /dev/null
+++ b/sys/compat/ia32/ia32_signal.h
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1999 Marcel Moolenaar
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+struct ia32_sigaltstack {
+ u_int32_t ss_sp; /* signal stack base */
+ u_int32_t ss_size; /* signal stack length */
+ int ss_flags; /* SS_DISABLE and/or SS_ONSTACK */
+};
+
+/* XXX should be 640 bytes long; check and see if __packed is needed */
+struct ia32_mcontext {
+ int mc_onstack; /* XXX - sigcontext compat. */
+ int mc_gs; /* machine state (struct trapframe) */
+ int mc_fs;
+ int mc_es;
+ int mc_ds;
+ int mc_edi;
+ int mc_esi;
+ int mc_ebp;
+ int mc_isp;
+ int mc_ebx;
+ int mc_edx;
+ int mc_ecx;
+ int mc_eax;
+ int mc_trapno;
+ int mc_err;
+ int mc_eip;
+ int mc_cs;
+ int mc_eflags;
+ int mc_esp;
+ int mc_ss;
+ int mc_len; /* sizeof(struct ia32_mcontext) */
+ /* We use the same values for fpformat and ownedfp */
+ int mc_fpformat;
+ int mc_ownedfp;
+ int mc_spare1[1]; /* align next field to 16 bytes */
+ /*
+ * See <machine/npx.h> for the internals of mc_fpstate[].
+ */
+ int mc_fpstate[128] __aligned(16);
+ int mc_spare2[8];
+};
+
+/* XXX should be 704 bytes long; check and see if __packed is needed */
+struct ia32_ucontext {
+ sigset_t uc_sigmask;
+ struct ia32_mcontext uc_mcontext;
+ u_int32_t uc_link;
+ struct ia32_sigaltstack uc_stack;
+ int uc_flags;
+ int __spare__[4];
+};
+
+
+#if defined(COMPAT_FREEBSD4)
+struct ia32_mcontext4 {
+ int mc_onstack; /* XXX - sigcontext compat. */
+ int mc_gs; /* machine state (struct trapframe) */
+ int mc_fs;
+ int mc_es;
+ int mc_ds;
+ int mc_edi;
+ int mc_esi;
+ int mc_ebp;
+ int mc_isp;
+ int mc_ebx;
+ int mc_edx;
+ int mc_ecx;
+ int mc_eax;
+ int mc_trapno;
+ int mc_err;
+ int mc_eip;
+ int mc_cs;
+ int mc_eflags;
+ int mc_esp;
+ int mc_ss;
+ int mc_fpregs[28];
+ int __spare__[17];
+};
+
+struct ia32_ucontext4 {
+ sigset_t uc_sigmask;
+ struct ia32_mcontext4 uc_mcontext;
+ u_int32_t uc_link;
+ struct ia32_sigaltstack uc_stack;
+ int __spare__[8];
+};
+#endif
+
+/*
+ * Signal frames, arguments passed to application signal handlers.
+ */
+union ia32_sigval {
+ int sigval_int;
+ u_int32_t sigval_ptr;
+};
+struct ia32_siginfo {
+ int si_signo; /* signal number */
+ int si_errno; /* errno association */
+ int si_code; /* signal code */
+ int32_t si_pid; /* sending process */
+ u_int32_t si_uid; /* sender's ruid */
+ int si_status; /* exit value */
+ u_int32_t si_addr; /* faulting instruction */
+ union ia32_sigval si_value; /* signal value */
+ int32_t si_band; /* band event for SIGPOLL */
+ int __spare__[7]; /* gimme some slack */
+};
+
+#ifdef COMPAT_FREEBSD4
+struct ia32_sigframe4 {
+ u_int32_t sf_signum;
+ u_int32_t sf_siginfo; /* code or pointer to sf_si */
+ u_int32_t sf_ucontext; /* points to sf_uc */
+ u_int32_t sf_addr; /* undocumented 4th arg */
+ u_int32_t sf_ah; /* action/handler pointer */
+ struct ia32_ucontext4 sf_uc; /* = *sf_ucontext */
+ struct ia32_siginfo sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+};
+#endif
+
+struct ia32_sigframe {
+ u_int32_t sf_signum;
+ u_int32_t sf_siginfo; /* code or pointer to sf_si */
+ u_int32_t sf_ucontext; /* points to sf_uc */
+ u_int32_t sf_addr; /* undocumented 4th arg */
+ u_int32_t sf_ah; /* action/handler pointer */
+ struct ia32_ucontext sf_uc; /* = *sf_ucontext */
+ struct ia32_siginfo sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+};
+
+extern char ia32_sigcode[];
+extern char freebsd4_ia32_sigcode[];
+extern int sz_ia32_sigcode;
+extern int sz_freebsd4_ia32_sigcode;
+extern void ia32_sendsig(sig_t, int, sigset_t *, u_long);
diff --git a/sys/compat/ia32/ia32_sigtramp.S b/sys/compat/ia32/ia32_sigtramp.S
new file mode 100644
index 000000000000..2e9f73d41bce
--- /dev/null
+++ b/sys/compat/ia32/ia32_sigtramp.S
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_compat.h"
+
+#include <machine/asmacros.h>
+#include <sys/syscall.h>
+
+#include "ia32_assym.h"
+
+ .text
+ .code32
+/*
+ * Signal trampoline, copied to top of user stack
+ */
+ ALIGN_TEXT
+ .globl ia32_sigcode
+ia32_sigcode:
+ calll *IA32_SIGF_HANDLER(%esp)
+ leal IA32_SIGF_UC(%esp),%eax /* get ucontext */
+ pushl %eax
+ movl IA32_UC_GS(%eax),%gs /* restore %gs */
+ movl IA32_UC_FS(%eax),%fs /* restore %fs */
+ movl IA32_UC_ES(%eax),%es /* restore %es */
+ movl IA32_UC_DS(%eax),%ds /* restore %ds */
+ movl $SYS_sigreturn,%eax
+ pushl %eax /* junk to fake return addr. */
+ int $0x80 /* enter kernel with args */
+ /* on stack */
+1:
+ jmp 1b
+
+#ifdef COMPAT_FREEBSD4
+ ALIGN_TEXT
+freebsd4_ia32_sigcode:
+ calll *IA32_SIGF_HANDLER(%esp)
+ leal IA32_SIGF_UC4(%esp),%eax/* get ucontext */
+ pushl %eax
+ movl IA32_UC4_GS(%eax),%gs /* restore %gs */
+ movl IA32_UC4_FS(%eax),%fs /* restore %fs */
+ movl IA32_UC4_ES(%eax),%es /* restore %es */
+ movl IA32_UC4_DS(%eax),%ds /* restore %ds */
+ movl $344,%eax /* 4.x SYS_sigreturn */
+ pushl %eax /* junk to fake return addr. */
+ int $0x80 /* enter kernel with args */
+ /* on stack */
+1:
+ jmp 1b
+#endif
+
+ ALIGN_TEXT
+esigcode:
+
+ .data
+ .globl sz_ia32_sigcode
+sz_ia32_sigcode:
+ .long esigcode-ia32_sigcode
+#ifdef COMPAT_FREEBSD4
+ .globl sz_freebsd4_ia32_sigcode
+sz_freebsd4_ia32_sigcode:
+ .long esigcode-freebsd4_ia32_sigcode
+#endif
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 18f4ee2fc78c..684677a7cf88 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2003 Peter Wemm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,6 +27,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#define __ELF_WORD_SIZE 32
#include <sys/param.h>
@@ -60,12 +63,16 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
-#include <ia64/ia32/ia32_util.h>
-#include <i386/include/psl.h>
-#include <i386/include/segments.h>
-#include <i386/include/specialreg.h>
+#include <amd64/ia32/ia32_util.h>
+#include <amd64/ia32/ia32_proto.h>
+#include <amd64/ia32/ia32_signal.h>
+#include <machine/psl.h>
+#include <machine/segments.h>
+#include <machine/specialreg.h>
#include <machine/frame.h>
#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cpufunc.h>
static register_t *ia32_copyout_strings(struct image_params *imgp);
static void ia32_setregs(struct thread *td, u_long entry, u_long stack,
@@ -73,21 +80,6 @@ static void ia32_setregs(struct thread *td, u_long entry, u_long stack,
extern struct sysent ia32_sysent[];
-static char ia32_sigcode[] = {
- 0xff, 0x54, 0x24, 0x10, /* call *SIGF_HANDLER(%esp) */
- 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC(%esp),%eax */
- 0x50, /* pushl %eax */
- 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x02, /* testl $PSL_VM,UC_EFLAGS(%eax) */
- 0x75, 0x03, /* jne 9f */
- 0x8e, 0x68, 0x14, /* movl UC_GS(%eax),%gs */
- 0xb8, 0x57, 0x01, 0x00, 0x00, /* 9: movl $SYS_sigreturn,%eax */
- 0x50, /* pushl %eax */
- 0xcd, 0x80, /* int $0x80 */
- 0xeb, 0xfe, /* 0: jmp 0b */
- 0, 0, 0, 0
-};
-static int ia32_szsigcode = sizeof(ia32_sigcode) & ~3;
-
struct sysentvec ia32_freebsd_sysvec = {
SYS_MAXSYSCALL,
ia32_sysent,
@@ -98,24 +90,26 @@ struct sysentvec ia32_freebsd_sysvec = {
NULL,
NULL,
elf32_freebsd_fixup,
- sendsig,
+ ia32_sendsig,
ia32_sigcode,
- &ia32_szsigcode,
+ &sz_ia32_sigcode,
NULL,
- "FreeBSD ELF",
+ "FreeBSD ELF32",
elf32_coredump,
NULL,
MINSIGSTKSZ,
- 4096,
+ PAGE_SIZE,
0,
- IA32_USRSTACK,
- IA32_USRSTACK,
- IA32_PS_STRINGS,
+ USRSTACK,
+ USRSTACK,
+ PS_STRINGS,
VM_PROT_ALL,
ia32_copyout_strings,
ia32_setregs
};
+
+
static Elf32_Brandinfo ia32_brand_info = {
ELFOSABI_FREEBSD,
EM_386,
@@ -129,6 +123,8 @@ SYSINIT(ia32, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf32_insert_brand_entry,
&ia32_brand_info);
+extern int _ucode32sel, _udatasel;
+
static register_t *
ia32_copyout_strings(struct image_params *imgp)
{
@@ -143,7 +139,7 @@ ia32_copyout_strings(struct image_params *imgp)
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
*/
- arginfo = (struct ia32_ps_strings *)IA32_PS_STRINGS;
+ arginfo = (struct ia32_ps_strings *)PS_STRINGS;
szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
roundup((ARG_MAX - imgp->stringspace), sizeof(char *));
@@ -190,7 +186,6 @@ ia32_copyout_strings(struct image_params *imgp)
stringp = imgp->stringbase;
argc = imgp->argc;
envc = imgp->envc;
-
/*
* Copy out strings - arguments and environment.
*/
@@ -234,135 +229,61 @@ ia32_copyout_strings(struct image_params *imgp)
return ((register_t *)stack_base);
}
-static void
-ia32_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings)
+/*
+ * Clear registers on exec
+ */
+void
+ia32_setregs(td, entry, stack, ps_strings)
+ struct thread *td;
+ u_long entry;
+ u_long stack;
+ u_long ps_strings;
{
- struct trapframe *frame = td->td_frame;
- vm_offset_t gdt, ldt;
- u_int64_t codesel, datasel, ldtsel;
- u_int64_t codeseg, dataseg, gdtseg, ldtseg;
- struct segment_descriptor desc;
- struct vmspace *vmspace = td->td_proc->p_vmspace;
+ struct trapframe *regs = td->td_frame;
+ struct pcb *pcb = td->td_pcb;
+ u_int64_t pc;
+ register_t s;
+
+ wrmsr(MSR_FSBASE, 0);
+ wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
+ pcb->pcb_fsbase = 0;
+ pcb->pcb_gsbase = 0;
+ pcb->pcb_kgsbase = rdmsr(MSR_GSBASE);
+ load_ds(_udatasel);
+ load_es(_udatasel);
+ load_fs(_udatasel);
+ s = intr_disable();
+ pc = rdmsr(MSR_GSBASE);
+ load_gs(_udatasel); /* Clobbers kernel %GS.base */
+ wrmsr(MSR_GSBASE, pc);
+ intr_restore(s);
+ pcb->pcb_ds = _udatasel;
+ pcb->pcb_es = _udatasel;
+ pcb->pcb_fs = _udatasel;
+ pcb->pcb_gs = _udatasel;
+
+ bzero((char *)regs, sizeof(struct trapframe));
+ regs->tf_rip = entry;
+ regs->tf_rsp = stack;
+ regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+ regs->tf_ss = _udatasel;
+ regs->tf_cs = _ucode32sel;
+ regs->tf_rbx = ps_strings;
/*
- * Make sure that we restore the entire trapframe after an
- * execve.
+ * Arrange to trap the next npx or `fwait' instruction (see npx.c
+ * for why fwait must be trapped at least if there is an npx or an
+ * emulator). This is mainly to handle the case where npx0 is not
+ * configured, since the npx routines normally set up the trap
+ * otherwise. It should be done only at boot time, but doing it
+ * here allows modifying `npx_exists' for testing the emulator on
+ * systems with an npx.
*/
- frame->tf_flags &= ~FRAME_SYSCALL;
-
- bzero(frame->tf_r, sizeof(frame->tf_r));
- bzero(frame->tf_f, sizeof(frame->tf_f));
-
- frame->tf_cr_iip = entry;
- frame->tf_cr_ipsr = (IA64_PSR_IC
- | IA64_PSR_I
- | IA64_PSR_IT
- | IA64_PSR_DT
- | IA64_PSR_RT
- | IA64_PSR_DFH
- | IA64_PSR_IS
- | IA64_PSR_BN
- | IA64_PSR_CPL_USER);
- frame->tf_r[FRAME_R12] = stack;
-
- codesel = LSEL(LUCODE_SEL, SEL_UPL);
- datasel = LSEL(LUDATA_SEL, SEL_UPL);
- ldtsel = GSEL(GLDT_SEL, SEL_UPL);
-
-#if 1
- frame->tf_r[FRAME_R16] = (datasel << 48) | (datasel << 32)
- | (datasel << 16) | datasel;
- frame->tf_r[FRAME_R17] = (ldtsel << 32) | (datasel << 16) | codesel;
-#else
- frame->tf_r[FRAME_R16] = datasel;
- frame->tf_r[FRAME_R17] = codesel;
- frame->tf_r[FRAME_R18] = datasel;
- frame->tf_r[FRAME_R19] = datasel;
- frame->tf_r[FRAME_R20] = datasel;
- frame->tf_r[FRAME_R21] = datasel;
- frame->tf_r[FRAME_R22] = ldtsel;
-#endif
+ load_cr0(rcr0() | CR0_MP | CR0_TS);
- /*
- * Build the GDT and LDT.
- */
- gdt = IA32_USRSTACK;
- vm_map_find(&vmspace->vm_map, 0, 0,
- &gdt, PAGE_SIZE, 0,
- VM_PROT_ALL, VM_PROT_ALL, 0);
- ldt = gdt + 4096;
-
- desc.sd_lolimit = 8*NLDT-1;
- desc.sd_lobase = ldt & 0xffffff;
- desc.sd_type = SDT_SYSLDT;
- desc.sd_dpl = SEL_UPL;
- desc.sd_p = 1;
- desc.sd_hilimit = 0;
- desc.sd_def32 = 0;
- desc.sd_gran = 0;
- desc.sd_hibase = ldt >> 24;
- copyout(&desc, (caddr_t) gdt + 8*GLDT_SEL, sizeof(desc));
-
- desc.sd_lolimit = ((IA32_USRSTACK >> 12) - 1) & 0xffff;
- desc.sd_lobase = 0;
- desc.sd_type = SDT_MEMERA;
- desc.sd_dpl = SEL_UPL;
- desc.sd_p = 1;
- desc.sd_hilimit = ((IA32_USRSTACK >> 12) - 1) >> 16;
- desc.sd_def32 = 1;
- desc.sd_gran = 1;
- desc.sd_hibase = 0;
- copyout(&desc, (caddr_t) ldt + 8*LUCODE_SEL, sizeof(desc));
- desc.sd_type = SDT_MEMRWA;
- copyout(&desc, (caddr_t) ldt + 8*LUDATA_SEL, sizeof(desc));
-
- codeseg = 0 /* base */
- + (((IA32_USRSTACK >> 12) - 1) << 32) /* limit */
- + ((long)SDT_MEMERA << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (1L << 62) /* 32 bits */
- + (1L << 63); /* page granularity */
- dataseg = 0 /* base */
- + (((IA32_USRSTACK >> 12) - 1) << 32) /* limit */
- + ((long)SDT_MEMRWA << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (1L << 62) /* 32 bits */
- + (1L << 63); /* page granularity */
- ia64_set_csd(codeseg);
- ia64_set_ssd(dataseg);
- frame->tf_r[FRAME_R24] = dataseg; /* ESD */
- frame->tf_r[FRAME_R27] = dataseg; /* DSD */
- frame->tf_r[FRAME_R28] = dataseg; /* FSD */
- frame->tf_r[FRAME_R29] = dataseg; /* GSD */
-
- gdtseg = gdt /* base */
- + ((8L*NGDT - 1) << 32) /* limit */
- + ((long)SDT_SYSNULL << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (0L << 62) /* 16 bits */
- + (0L << 63); /* byte granularity */
- ldtseg = ldt /* base */
- + ((8L*NLDT - 1) << 32) /* limit */
- + ((long)SDT_SYSLDT << 52)
- + ((long)SEL_UPL << 57)
- + (1L << 59) /* present */
- + (0L << 62) /* 16 bits */
- + (0L << 63); /* byte granularity */
- frame->tf_r[FRAME_R30] = ldtseg; /* LDTD */
- frame->tf_r[FRAME_R31] = gdtseg; /* GDTD */
-
- ia64_set_eflag(PSL_USER);
-
- /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */
- frame->tf_r[FRAME_R11] = IA32_PS_STRINGS;
+ fpstate_drop(td);
- /*
- * XXX - Linux emulator
- * Make sure sure edx is 0x0 on entry. Linux binaries depend
- * on it.
- */
+ /* Return via doreti so that we can change to a different %cs */
+ pcb->pcb_flags |= PCB_FULLCTX;
td->td_retval[1] = 0;
}
diff --git a/sys/compat/ia32/ia32_util.h b/sys/compat/ia32/ia32_util.h
index 23f2abae1ab2..20a5b1e28416 100644
--- a/sys/compat/ia32/ia32_util.h
+++ b/sys/compat/ia32/ia32_util.h
@@ -44,7 +44,7 @@ struct ia32_ps_strings {
int ps_nenvstr; /* the number of environment strings */
};
-#define IA32_USRSTACK (4L*1024*1024*1024 - PAGE_SIZE)
+#define IA32_USRSTACK USRSTACK
#define IA32_PS_STRINGS (IA32_USRSTACK - sizeof(struct ia32_ps_strings))
static __inline caddr_t stackgap_init(void);
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index afa187dbf5f3..63425b636ea5 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -8,6 +8,19 @@
# dependency lines other than the first are silently ignored.
#
+ia32_genassym.o optional ia32 \
+ dependency "$S/amd64/ia32/ia32_genassym.c" \
+ compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \
+ no-obj no-implicit-rule \
+ clean "ia32_genassym.o"
+#
+ia32_assym.h optional ia32 \
+ dependency "$S/kern/genassym.sh ia32_genassym.o" \
+ compile-with "sh $S/kern/genassym.sh ia32_genassym.o > ${.TARGET}" \
+ no-obj no-implicit-rule before-depend \
+ clean "ia32_assym.h"
+#
+
dev/kbd/atkbd.c optional atkbd
dev/kbd/atkbdc.c optional atkbdc
dev/kbd/kbd.c optional atkbd
@@ -64,7 +77,14 @@ amd64/isa/npx.c standard
amd64/pci/pci_cfgreg.c optional pci
amd64/pci/pci_bus.c optional pci
-
+amd64/ia32/ia32_misc.c optional ia32
+amd64/ia32/ia32_sysent.c optional ia32
+amd64/ia32/ia32_sysvec.c optional ia32
+amd64/ia32/ia32_signal.c optional ia32
+amd64/ia32/ia32_sigtramp.S optional ia32
+amd64/ia32/ia32_exception.S optional ia32
+amd64/ia32/ia32_syscall.c optional ia32
+kern/imgact_elf32.c optional ia32
# This file tells config what files go into building a kernel,
# files marked standard are always included.
diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64
index ad735889b65a..79a887a256e4 100644
--- a/sys/conf/options.amd64
+++ b/sys/conf/options.amd64
@@ -59,3 +59,4 @@ PPC_DEBUG opt_ppc.h
PSM_HOOKRESUME opt_psm.h
PSM_RESETAFTERSUSPEND opt_psm.h
PSM_DEBUG opt_psm.h
+IA32