Date: Tue, 13 May 2003 18:24:11 -0700 (PDT) From: Peter Wemm <peter@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 31109 for review Message-ID: <200305140124.h4E1OBri066466@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=31109 Change 31109 by peter@peter_hammer on 2003/05/13 18:23:33 Implement i386 signals properly. This works for both the 4.x and 5.x signal interfaces. I have not done the 3.x syscall interface. We can't run a.out binaries anyway because the lcall syscall method isn't implemented, so this isn't much of a loss. The 3.x sigaction/sigreturn (for elf binaries) could be done with a bit more cut/paste though. Affected files ... .. //depot/projects/hammer/sys/amd64/amd64/machdep.c#31 edit .. //depot/projects/hammer/sys/amd64/conf/GENERIC#9 edit .. //depot/projects/hammer/sys/amd64/ia32/ia32_genassym.c#1 add .. //depot/projects/hammer/sys/amd64/ia32/ia32_misc.c#2 edit .. //depot/projects/hammer/sys/amd64/ia32/ia32_proto.h#2 edit .. //depot/projects/hammer/sys/amd64/ia32/ia32_signal.h#1 add .. //depot/projects/hammer/sys/amd64/ia32/ia32_sigtramp.S#1 add .. //depot/projects/hammer/sys/amd64/ia32/ia32_syscall.h#2 edit .. //depot/projects/hammer/sys/amd64/ia32/ia32_sysent.c#2 edit .. //depot/projects/hammer/sys/amd64/ia32/ia32_sysvec.c#2 edit .. //depot/projects/hammer/sys/amd64/ia32/syscalls.master#2 edit .. //depot/projects/hammer/sys/amd64/include/md_var.h#10 edit .. //depot/projects/hammer/sys/conf/files.amd64#10 edit Differences ... ==== //depot/projects/hammer/sys/amd64/amd64/machdep.c#31 (text+ko) ==== @@ -124,7 +124,6 @@ #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) @@ -389,6 +388,16 @@ 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 * @@ -1628,7 +1637,7 @@ return (0); } -static void +void fpstate_drop(struct thread *td) { register_t s; ==== //depot/projects/hammer/sys/amd64/conf/GENERIC#9 (text+ko) ==== @@ -24,6 +24,7 @@ maxusers 0 options NDA #Avoid accidental cut/paste of NDA'ed stuff options IA32 +options COMPAT_FREEBSD4 makeoptions NO_MODULES=not_yet ==== //depot/projects/hammer/sys/amd64/ia32/ia32_misc.c#2 (text+ko) ==== @@ -1170,40 +1170,31 @@ return (error); } -#if 0 - +#ifdef COMPAT_FREEBSD4 int -ia32_xxx(struct thread *td, struct ia32_xxx_args *uap) +freebsd4_ia32_sigaction(struct thread *td, struct freebsd4_ia32_sigaction_args *uap) { + struct sigaction32 s32; + struct sigaction sa, osa, *sap; int error; - caddr_t sg; - struct yyy32 *p32, s32; - struct yyy *p = NULL, s; - p32 = uap->zzz; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct yyy)); - uap->zzz = (struct yyy32 *)p; - error = copyin(p32, &s32, sizeof(s32)); + if (uap->act) { + error = copyin(uap->act, &s32, sizeof(s32)); if (error) return (error); - /* translate in */ - error = copyout(&s, p, sizeof(s)); - 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)); } - error = xxx(td, (struct xxx_args *) uap); - if (error) - return (error); - if (p32) { - error = copyin(p, &s, sizeof(s)); - if (error) - return (error); - /* translate out */ - error = copyout(&s32, p32, sizeof(s32)); - } return (error); } - #endif ==== //depot/projects/hammer/sys/amd64/ia32/ia32_proto.h#2 (text+ko) ==== @@ -201,11 +201,6 @@ char new_l_[PADL_(void *)]; void * new; char new_r_[PADR_(void *)]; char newlen_l_[PADL_(u_int32_t)]; u_int32_t newlen; char newlen_r_[PADR_(u_int32_t)]; }; -struct ia32_sigaction_args { - char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; - char act_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * act; char act_r_[PADR_(struct sigaction32 *)]; - char oact_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * oact; char oact_r_[PADR_(struct sigaction32 *)]; -}; struct ia32_sendfile_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; @@ -216,6 +211,14 @@ char sbytes_l_[PADL_(off_t *)]; off_t * sbytes; char sbytes_r_[PADR_(off_t *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; +struct ia32_sigreturn_args { + char sigcntxp_l_[PADL_(const struct ia32_ucontext *)]; const struct ia32_ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct ia32_ucontext *)]; +}; +struct ia32_sigaction_args { + char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; + char act_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * act; char act_r_[PADR_(struct sigaction32 *)]; + char oact_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * oact; char oact_r_[PADR_(struct sigaction32 *)]; +}; int ia32_open(struct thread *, struct ia32_open_args *); int ia32_wait4(struct thread *, struct ia32_wait4_args *); int ia32_getfsstat(struct thread *, struct ia32_getfsstat_args *); @@ -247,8 +250,9 @@ int ia32_truncate(struct thread *, struct ia32_truncate_args *); int ia32_ftruncate(struct thread *, struct ia32_ftruncate_args *); int ia32_sysctl(struct thread *, struct ia32_sysctl_args *); +int ia32_sendfile(struct thread *, struct ia32_sendfile_args *); +int ia32_sigreturn(struct thread *, struct ia32_sigreturn_args *); int ia32_sigaction(struct thread *, struct ia32_sigaction_args *); -int ia32_sendfile(struct thread *, struct ia32_sendfile_args *); #ifdef COMPAT_43 @@ -268,7 +272,17 @@ char sbytes_l_[PADL_(off_t *)]; off_t * sbytes; char sbytes_r_[PADR_(off_t *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; +struct freebsd4_ia32_sigaction_args { + char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; + char act_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * act; char act_r_[PADR_(struct sigaction32 *)]; + char oact_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * oact; char oact_r_[PADR_(struct sigaction32 *)]; +}; +struct freebsd4_ia32_sigreturn_args { + char sigcntxp_l_[PADL_(const struct __ucontext *)]; const struct __ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct __ucontext *)]; +}; int freebsd4_ia32_sendfile(struct thread *, struct freebsd4_ia32_sendfile_args *); +int freebsd4_ia32_sigaction(struct thread *, struct freebsd4_ia32_sigaction_args *); +int freebsd4_ia32_sigreturn(struct thread *, struct freebsd4_ia32_sigreturn_args *); #endif /* COMPAT_FREEBSD4 */ ==== //depot/projects/hammer/sys/amd64/ia32/ia32_syscall.h#2 (text+ko) ==== @@ -252,9 +252,9 @@ #define IA32_SYS_jail 338 #define IA32_SYS_sigprocmask 340 #define IA32_SYS_sigsuspend 341 -#define IA32_SYS_ia32_sigaction 342 + /* 342 is old ia32_sigaction */ #define IA32_SYS_sigpending 343 -#define IA32_SYS_sigreturn 344 + /* 344 is old ia32_sigreturn */ #define IA32_SYS___acl_get_file 347 #define IA32_SYS___acl_set_file 348 #define IA32_SYS___acl_get_fd 349 @@ -286,6 +286,8 @@ #define IA32_SYS_lchflags 391 #define IA32_SYS_uuidgen 392 #define IA32_SYS_ia32_sendfile 393 +#define IA32_SYS_ia32_sigreturn 416 +#define IA32_SYS_ia32_sigaction 417 #define IA32_SYS_thr_create 430 #define IA32_SYS_thr_exit 431 #define IA32_SYS_thr_self 432 ==== //depot/projects/hammer/sys/amd64/ia32/ia32_sysent.c#2 (text+ko) ==== @@ -367,9 +367,9 @@ { 0, (sy_call_t *)nosys }, /* 339 = pioctl */ { SYF_MPSAFE | AS(sigprocmask_args), (sy_call_t *)sigprocmask }, /* 340 = sigprocmask */ { SYF_MPSAFE | AS(sigsuspend_args), (sy_call_t *)sigsuspend }, /* 341 = sigsuspend */ - { AS(ia32_sigaction_args), (sy_call_t *)ia32_sigaction }, /* 342 = ia32_sigaction */ + { compat4(AS(freebsd4_ia32_sigaction_args),ia32_sigaction) }, /* 342 = old ia32_sigaction */ { SYF_MPSAFE | AS(sigpending_args), (sy_call_t *)sigpending }, /* 343 = sigpending */ - { SYF_MPSAFE | AS(sigreturn_args), (sy_call_t *)sigreturn }, /* 344 = sigreturn */ + { compat4(SYF_MPSAFE | AS(freebsd4_ia32_sigreturn_args),ia32_sigreturn) }, /* 344 = old ia32_sigreturn */ { 0, (sy_call_t *)nosys }, /* 345 = sigtimedwait */ { 0, (sy_call_t *)nosys }, /* 346 = sigwaitinfo */ { SYF_MPSAFE | AS(__acl_get_file_args), (sy_call_t *)__acl_get_file }, /* 347 = __acl_get_file */ @@ -441,8 +441,8 @@ { 0, (sy_call_t *)nosys }, /* 413 = extattr_get_link */ { 0, (sy_call_t *)nosys }, /* 414 = extattr_delete_link */ { 0, (sy_call_t *)nosys }, /* 415 = __mac_execve */ - { 0, (sy_call_t *)nosys }, /* 416 = newsigreturn */ - { 0, (sy_call_t *)nosys }, /* 417 = newsigaction */ + { SYF_MPSAFE | AS(ia32_sigreturn_args), (sy_call_t *)ia32_sigreturn }, /* 416 = ia32_sigreturn */ + { AS(ia32_sigaction_args), (sy_call_t *)ia32_sigaction }, /* 417 = ia32_sigaction */ { 0, (sy_call_t *)nosys }, /* 418 = __xstat */ { 0, (sy_call_t *)nosys }, /* 419 = __xfstat */ { 0, (sy_call_t *)nosys }, /* 420 = __xlstat */ ==== //depot/projects/hammer/sys/amd64/ia32/ia32_sysvec.c#2 (text+ko) ==== @@ -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: src/sys/ia64/ia32/ia32_sysvec.c,v 1.2 2002/09/01 21:41:23 jake Exp $ */ +#include "opt_compat.h" + #define __ELF_WORD_SIZE 32 #include <sys/param.h> @@ -61,33 +64,33 @@ #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> static register_t *ia32_copyout_strings(struct image_params *imgp); static void ia32_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings); +#ifdef COMPAT_FREEBSD4 +static void freebsd4_ia32_sendsig(sig_t, int, sigset_t *, u_long); +#endif +static void ia32_sendsig(sig_t, int, sigset_t *, u_long); +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 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; +extern char ia32_sigcode[]; +extern char freebsd4_ia32_sigcode[]; +extern int sz_ia32_sigcode; +extern int sz_freebsd4_ia32_sigcode; struct sysentvec ia32_freebsd_sysvec = { SYS_MAXSYSCALL, @@ -99,9 +102,9 @@ NULL, NULL, elf32_freebsd_fixup, - sendsig, + ia32_sendsig, ia32_sigcode, - &ia32_szsigcode, + &sz_ia32_sigcode, NULL, "FreeBSD ELF32", elf32_coredump, @@ -134,6 +137,9 @@ extern int _ucode32sel, _udatasel; +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) +#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) + static register_t * ia32_copyout_strings(struct image_params *imgp) { @@ -290,15 +296,485 @@ */ load_cr0(rcr0() | CR0_MP | CR0_TS); - /* Initialize the npx (if any) for the current process. */ - s = intr_disable(); - if (PCPU_GET(fpcurthread) == td) - npxdrop(); - pcb->pcb_flags &= ~PCB_NPXINITDONE; - intr_restore(s); + fpstate_drop(td); /* Return via doreti so that we can change to a different %cs */ pcb->pcb_flags |= PCB_FULLCTX; td->td_retval[1] = 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(catcher, sig, mask, code) + 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); + load_es(_udatasel); + load_fs(_udatasel); + PROC_LOCK(p); +} +#endif /* COMPAT_FREEBSD4 */ + +static void +ia32_sendsig(catcher, sig, mask, code) + 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); + load_es(_udatasel); + load_fs(_udatasel); + 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); + } + + /* mc_gs is done by sigtramp.S */ + load_fs(ucp->uc_mcontext.mc_fs); + load_es(ucp->uc_mcontext.mc_es); + load_ds(ucp->uc_mcontext.mc_ds); + 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); + + /* mc_gs is done by sigtramp.S */ + load_fs(ucp->uc_mcontext.mc_fs); + load_es(ucp->uc_mcontext.mc_es); + load_ds(ucp->uc_mcontext.mc_ds); + 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); +} ==== //depot/projects/hammer/sys/amd64/ia32/syscalls.master#2 (text+ko) ==== @@ -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, \ @@ -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 ==== //depot/projects/hammer/sys/amd64/include/md_var.h#10 (text+ko) ==== @@ -69,5 +69,6 @@ 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_ */ ==== //depot/projects/hammer/sys/conf/files.amd64#10 (text+ko) ==== @@ -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 @@ -67,6 +80,7 @@ amd64/ia32/ia32_misc.c optional ia32 amd64/ia32/ia32_sysent.c optional ia32 amd64/ia32/ia32_sysvec.c optional ia32 +amd64/ia32/ia32_sigtramp.S optional ia32 kern/imgact_elf32.c optional ia32 # This file tells config what files go into building a kernel,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200305140124.h4E1OBri066466>