diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index d5976d4b232..3ca4ecd11bb 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 0469a9a4b04..282b427d7cf 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -217,40 +217,6 @@ IDTVEC(page) sti 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 @@ -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 cf431590548..b55ef085ca0 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 b7272566519..b0b6ce23344 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 8baa4560985..1abab3bd657 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 a4ebe9c4126..0b7f5104af8 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -76,7 +76,6 @@ #include 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 79083ef7a30..2e058e97f58 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 00000000000..aa901ef97bb --- /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 + +#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 00000000000..2134a4477c4 --- /dev/null +++ b/sys/amd64/ia32/ia32_genassym.c @@ -0,0 +1,24 @@ +/* $FreeBSD$ */ + +#include "opt_compat.h" + +#include +#include +#include +#include + +#include + +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 c1cdd203766..9ef02c5c242 100644 --- a/sys/amd64/ia32/ia32_misc.c +++ b/sys/amd64/ia32/ia32_misc.c @@ -74,9 +74,9 @@ #include #include -#include -#include -#include +#include +#include +#include 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 00000000000..ae966a53656 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 00000000000..f251e72fb33 --- /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 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 00000000000..2e9f73d41bc --- /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 +#include + +#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 00000000000..dee52b0e75b --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KTRACE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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, ¶ms); + } 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 18f4ee2fc78..684677a7cf8 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 @@ -60,12 +63,16 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include 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; + load_cr0(rcr0() | CR0_MP | CR0_TS); - bzero(frame->tf_r, sizeof(frame->tf_r)); - bzero(frame->tf_f, sizeof(frame->tf_f)); + fpstate_drop(td); - 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 - - /* - * 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; - - /* - * 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 23f2abae1ab..20a5b1e2841 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 508fdf78b8f..042bf003b1c 100644 --- a/sys/amd64/ia32/syscalls.master +++ b/sys/amd64/ia32/syscalls.master @@ -37,8 +37,8 @@ #include #include #include -#include -#include +#include +#include ; 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 1e1df330e84..21257dda301 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) { @@ -464,6 +463,18 @@ rgs(void) return (sel); } +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) { diff --git a/sys/amd64/include/elf.h b/sys/amd64/include/elf.h index 3883d49302c..b675859553e 100644 --- a/sys/amd64/include/elf.h +++ b/sys/amd64/include/elf.h @@ -33,9 +33,12 @@ * ELF definitions for the AMD64 architecture. */ -#include /* Definitions common to all 64 bit architectures. */ +#ifndef __ELF_WORD_SIZE #define __ELF_WORD_SIZE 64 /* Used by */ +#endif +#include /* Definitions common to all 32 bit architectures. */ +#include /* Definitions common to all 64 bit architectures. */ #include #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 ad35173a4a1..63e9b2be4e9 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 c17709b225a..5bfb41f9e20 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 0f9a59bd5f7..919eeff4023 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 c1cdd203766..9ef02c5c242 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -74,9 +74,9 @@ #include #include -#include -#include -#include +#include +#include +#include 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 23f2abae1ab..20a5b1e2841 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 508fdf78b8f..042bf003b1c 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -37,8 +37,8 @@ #include #include #include -#include -#include +#include +#include ; 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 00000000000..2134a4477c4 --- /dev/null +++ b/sys/compat/ia32/ia32_genassym.c @@ -0,0 +1,24 @@ +/* $FreeBSD$ */ + +#include "opt_compat.h" + +#include +#include +#include +#include + +#include + +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 00000000000..f251e72fb33 --- /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 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 00000000000..2e9f73d41bc --- /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 +#include + +#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 18f4ee2fc78..684677a7cf8 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 @@ -60,12 +63,16 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include 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; + load_cr0(rcr0() | CR0_MP | CR0_TS); - bzero(frame->tf_r, sizeof(frame->tf_r)); - bzero(frame->tf_f, sizeof(frame->tf_f)); + fpstate_drop(td); - 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 - - /* - * 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; - - /* - * 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 23f2abae1ab..20a5b1e2841 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 afa187dbf5f..63425b636ea 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 ad735889b65..79a887a256e 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