diff options
| author | Peter Wemm <peter@FreeBSD.org> | 2002-10-25 19:10:58 +0000 |
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 2002-10-25 19:10:58 +0000 |
| commit | 23eeeff7bee66bd81fa2d7ec9d648339bd0d041f (patch) | |
| tree | 96a1089f558875f808b1fd36f885179cd78f55de /sys/amd64 | |
| parent | fb3a308a4ac3ca2c6fcd097a2990d7ea52ab230f (diff) | |
Notes
Diffstat (limited to 'sys/amd64')
| -rw-r--r-- | sys/amd64/amd64/genassym.c | 9 | ||||
| -rw-r--r-- | sys/amd64/amd64/locore.S | 26 | ||||
| -rw-r--r-- | sys/amd64/amd64/locore.s | 26 | ||||
| -rw-r--r-- | sys/amd64/amd64/machdep.c | 276 | ||||
| -rw-r--r-- | sys/amd64/include/md_var.h | 8 | ||||
| -rw-r--r-- | sys/amd64/include/sigframe.h | 18 | ||||
| -rw-r--r-- | sys/amd64/include/signal.h | 4 | ||||
| -rw-r--r-- | sys/amd64/include/ucontext.h | 28 |
8 files changed, 363 insertions, 32 deletions
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index d4aa9e3da060..5a8cf704dd22 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -37,6 +37,7 @@ * $FreeBSD$ */ +#include "opt_compat.h" #include "opt_kstack_pages.h" #include <sys/param.h> @@ -151,12 +152,20 @@ ASSYM(TF_ERR, offsetof(struct trapframe, tf_err)); ASSYM(TF_CS, offsetof(struct trapframe, tf_cs)); ASSYM(TF_EFLAGS, offsetof(struct trapframe, tf_eflags)); ASSYM(SIGF_HANDLER, offsetof(struct sigframe, sf_ahu.sf_handler)); +#ifdef COMPAT_43 ASSYM(SIGF_SC, offsetof(struct osigframe, sf_siginfo.si_sc)); +#endif ASSYM(SIGF_UC, offsetof(struct sigframe, sf_uc)); +#ifdef COMPAT_43 ASSYM(SC_PS, offsetof(struct osigcontext, sc_ps)); ASSYM(SC_FS, offsetof(struct osigcontext, sc_fs)); ASSYM(SC_GS, offsetof(struct osigcontext, sc_gs)); ASSYM(SC_TRAPNO, offsetof(struct osigcontext, sc_trapno)); +#endif +#ifdef COMPAT_FREEBSD4 +ASSYM(UC4_EFLAGS, offsetof(struct ucontext4, uc_mcontext.mc_eflags)); +ASSYM(UC4_GS, offsetof(struct ucontext4, uc_mcontext.mc_gs)); +#endif ASSYM(UC_EFLAGS, offsetof(ucontext_t, uc_mcontext.mc_eflags)); ASSYM(UC_GS, offsetof(ucontext_t, uc_mcontext.mc_gs)); ASSYM(ENOENT, ENOENT); diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S index 5d5b39ed5fd9..8f1d801268b3 100644 --- a/sys/amd64/amd64/locore.S +++ b/sys/amd64/amd64/locore.S @@ -406,6 +406,22 @@ NON_GPROF_ENTRY(sigcode) int $0x80 /* enter kernel with args */ 0: jmp 0b +#ifdef COMPAT_FREEBSD4 + ALIGN_TEXT +freebsd4_sigcode: + call *SIGF_HANDLER(%esp) /* call signal handler */ + lea SIGF_UC(%esp),%eax /* get ucontext_t */ + pushl %eax + testl $PSL_VM,UC4_EFLAGS(%eax) + jne 9f + movl UC4_GS(%eax),%gs /* restore %gs */ +9: + movl $344,%eax /* 4.x SYS_sigreturn */ + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ +0: jmp 0b +#endif + #ifdef COMPAT_43 ALIGN_TEXT osigcode: @@ -416,7 +432,7 @@ osigcode: jne 9f movl SC_GS(%eax),%gs /* restore %gs */ 9: - movl $SYS_osigreturn,%eax + movl $103,%eax /* 3.x SYS_sigreturn */ pushl %eax /* junk to fake return addr. */ int $0x80 /* enter kernel with args */ 0: jmp 0b @@ -426,10 +442,16 @@ osigcode: esigcode: .data - .globl szsigcode, szosigcode + .globl szsigcode szsigcode: .long esigcode-sigcode +#ifdef COMPAT_FREEBSD4 + .globl szfreebsd4_sigcode +szfreebsd4_sigcode: + .long esigcode-freebsd4_sigcode +#endif #ifdef COMPAT_43 + .globl szosigcode szosigcode: .long esigcode-osigcode #endif diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s index 5d5b39ed5fd9..8f1d801268b3 100644 --- a/sys/amd64/amd64/locore.s +++ b/sys/amd64/amd64/locore.s @@ -406,6 +406,22 @@ NON_GPROF_ENTRY(sigcode) int $0x80 /* enter kernel with args */ 0: jmp 0b +#ifdef COMPAT_FREEBSD4 + ALIGN_TEXT +freebsd4_sigcode: + call *SIGF_HANDLER(%esp) /* call signal handler */ + lea SIGF_UC(%esp),%eax /* get ucontext_t */ + pushl %eax + testl $PSL_VM,UC4_EFLAGS(%eax) + jne 9f + movl UC4_GS(%eax),%gs /* restore %gs */ +9: + movl $344,%eax /* 4.x SYS_sigreturn */ + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ +0: jmp 0b +#endif + #ifdef COMPAT_43 ALIGN_TEXT osigcode: @@ -416,7 +432,7 @@ osigcode: jne 9f movl SC_GS(%eax),%gs /* restore %gs */ 9: - movl $SYS_osigreturn,%eax + movl $103,%eax /* 3.x SYS_sigreturn */ pushl %eax /* junk to fake return addr. */ int $0x80 /* enter kernel with args */ 0: jmp 0b @@ -426,10 +442,16 @@ osigcode: esigcode: .data - .globl szsigcode, szosigcode + .globl szsigcode szsigcode: .long esigcode-sigcode +#ifdef COMPAT_FREEBSD4 + .globl szfreebsd4_sigcode +szfreebsd4_sigcode: + .long esigcode-freebsd4_sigcode +#endif #ifdef COMPAT_43 + .globl szosigcode szosigcode: .long esigcode-osigcode #endif diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 80805a2048c5..ff69b568be79 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -165,6 +165,10 @@ int cold = 1; #ifdef COMPAT_43 static void osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code); #endif +#ifdef COMPAT_FREEBSD4 +static void freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask, + u_long code); +#endif static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) @@ -286,8 +290,7 @@ osendsig(catcher, sig, mask, code) sigset_t *mask; u_long code; { - struct osigframe sf; - struct osigframe *fp; + struct osigframe sf, *fp; struct proc *p; struct thread *td; struct sigacts *psp; @@ -408,6 +411,129 @@ osendsig(catcher, sig, mask, code) } #endif /* COMPAT_43 */ +#ifdef COMPAT_FREEBSD4 +static void +freebsd4_sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig; + sigset_t *mask; + u_long code; +{ + struct 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_esp); + + /* Save user context. */ + bzero(&sf, sizeof(sf)); + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = p->p_sigstk; + 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(); + bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); + + /* Allocate space for the signal handler context. */ + if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe4 *)(p->p_sigstk.ss_sp + + p->p_sigstk.ss_size - sizeof(struct sigframe4)); +#if defined(COMPAT_43) || defined(COMPAT_SUNOS) + p->p_sigstk.ss_flags |= SS_ONSTACK; +#endif + } else + sfp = (struct sigframe4 *)regs->tf_esp - 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 = (register_t)&sfp->sf_si; + sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + + /* Fill in POSIX parts */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + sf.sf_si.si_addr = (void *)regs->tf_err; + sf.sf_si.si_pid = p->p_pid; + sf.sf_si.si_uid = p->p_ucred->cr_uid; + } else { + /* Old FreeBSD-style arguments. */ + sf.sf_siginfo = code; + sf.sf_addr = regs->tf_err; + sf.sf_ahu.sf_handler = catcher; + } + PROC_UNLOCK(p); + + /* + * If we're a vm86 process, we want to save the segment registers. + * We also change eflags to be our emulated eflags, not the actual + * eflags. + */ + if (regs->tf_eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86; + + sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; + sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; + sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; + sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; + + if (vm86->vm86_has_vme == 0) + sf.sf_uc.uc_mcontext.mc_eflags = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | + (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); + + /* + * Clear PSL_NT to inhibit T_TSSFLT faults on return from + * syscalls made by the signal handler. This just avoids + * wasting time for our lazy fixup of such faults. PSL_NT + * does nothing in vm86 mode, but vm86 programs can set it + * almost legitimately in probes for old cpu types. + */ + tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP); + } + + /* + * 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_esp = (int)sfp; + regs->tf_eip = PS_STRINGS - szfreebsd4_sigcode; + regs->tf_eflags &= ~PSL_T; + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_ss = _udatasel; + PROC_LOCK(p); +} +#endif /* COMPAT_FREEBSD4 */ + void sendsig(catcher, sig, mask, code) sig_t catcher; @@ -415,18 +541,23 @@ sendsig(catcher, sig, mask, code) sigset_t *mask; u_long code; { - struct sigframe sf; + struct sigframe sf, *sfp; struct proc *p; struct thread *td; struct sigacts *psp; struct trapframe *regs; - struct sigframe *sfp; 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_sendsig(catcher, sig, mask, code); + return; + } +#endif #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { osendsig(catcher, sig, mask, code); @@ -550,6 +681,7 @@ sendsig(catcher, sig, mask, code) * * MPSAFE */ +#ifdef COMPAT_43 int osigreturn(td, uap) struct thread *td; @@ -557,7 +689,6 @@ osigreturn(td, uap) struct osigcontext *sigcntxp; } */ *uap; { -#ifdef COMPAT_43 struct osigcontext sc; struct trapframe *regs; struct osigcontext *scp; @@ -662,10 +793,116 @@ osigreturn(td, uap) signotify(p); PROC_UNLOCK(p); return (EJUSTRETURN); -#else /* !COMPAT_43 */ - return (ENOSYS); +} #endif /* COMPAT_43 */ + +#ifdef COMPAT_FREEBSD4 +/* + * MPSAFE + */ +int +freebsd4_sigreturn(td, uap) + struct thread *td; + struct freebsd4_sigreturn_args /* { + const ucontext4 *sigcntxp; + } */ *uap; +{ + struct ucontext4 uc; + struct proc *p = td->td_proc; + struct trapframe *regs; + const struct 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; + if (eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86; + + /* + * if pcb_ext == 0 or vm86_inited == 0, the user hasn't + * set up the vm86 area, and we can't enter vm86 mode. + */ + if (td->td_pcb->pcb_ext == 0) + return (EINVAL); + vm86 = &td->td_pcb->pcb_ext->ext_vm86; + if (vm86->vm86_inited == 0) + return (EINVAL); + + /* Go back to user mode if both flags are set. */ + if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) + trapsignal(p, SIGBUS, 0); + + if (vm86->vm86_has_vme) { + eflags = (tf->tf_eflags & ~VME_USERCHANGE) | + (eflags & VME_USERCHANGE) | PSL_VM; + } else { + vm86->vm86_eflags = eflags; /* save VIF, VIP */ + eflags = (tf->tf_eflags & ~VM_USERCHANGE) | + (eflags & VM_USERCHANGE) | PSL_VM; + } + bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); + tf->tf_eflags = eflags; + tf->tf_vm86_ds = tf->tf_ds; + tf->tf_vm86_es = tf->tf_es; + tf->tf_vm86_fs = tf->tf_fs; + tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; + tf->tf_ds = _udatasel; + tf->tf_es = _udatasel; + tf->tf_fs = _udatasel; + } else { + /* + * 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_eflags & ~PSL_RF)) { + printf("freebsd4_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(p, SIGBUS, T_PROTFLT); + return (EINVAL); + } + + bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); + } + + PROC_LOCK(p); +#if defined(COMPAT_43) || defined(COMPAT_SUNOS) + if (ucp->uc_mcontext.mc_onstack & 1) + p->p_sigstk.ss_flags |= SS_ONSTACK; + else + p->p_sigstk.ss_flags &= ~SS_ONSTACK; +#endif + + p->p_sigmask = ucp->uc_sigmask; + SIG_CANTMASK(p->p_sigmask); + signotify(p); + PROC_UNLOCK(p); + return (EJUSTRETURN); } +#endif /* COMPAT_FREEBSD4 */ /* * MPSAFE @@ -2162,7 +2399,7 @@ get_fpcontext(struct thread *td, mcontext_t *mcp) #ifndef DEV_NPX mcp->mc_fpformat = _MC_FPFMT_NODEV; mcp->mc_ownedfp = _MC_FPOWNED_NONE; -#else /* DEV_NPX */ +#else union savefpu *addr; /* @@ -2192,9 +2429,8 @@ get_fpcontext(struct thread *td, mcontext_t *mcp) bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate)); bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2)); } - bcopy(&mcp->mc_fpstate, &td->td_pcb->pcb_save, sizeof(mcp->mc_fpstate)); mcp->mc_fpformat = npxformat(); -#endif /* !DEV_NPX */ +#endif } static int @@ -2204,7 +2440,10 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp) if (mcp->mc_fpformat == _MC_FPFMT_NODEV) return (0); - if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) + else if (mcp->mc_fpformat != _MC_FPFMT_387 && + 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 || @@ -2227,25 +2466,14 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp) * be called with interrupts disabled. */ npxsetregs(td, addr); +#endif /* * 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 { - /* - * There is no valid FPU state in *mcp, so use the saved - * state in the PCB if there is one. XXX the test for - * whether there is one seems to be quite broken. We - * forcibly drop the state in sendsig(). - */ - if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) != 0) - npxsetregs(td, &td->td_pcb->pcb_save); -#endif -#if !defined(COMPAT_FREEBSD4) && !defined(COMPAT_43) + } else return (EINVAL); -#endif - } return (0); } diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index f449c045d459..9fa396876854 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -56,7 +56,13 @@ extern int need_post_dma_flush; #endif extern void (*ovbcopy_vector)(const void *from, void *to, size_t len); extern char sigcode[]; -extern int szsigcode, szosigcode; +extern int szsigcode; +#ifdef COMPAT_FREEBSD4 +extern int szfreebsd4_sigcode; +#endif +#ifdef COMPAT_43 +extern int szosigcode; +#endif typedef void alias_for_inthand_t(u_int cs, u_int ef, u_int esp, u_int ss); struct thread; diff --git a/sys/amd64/include/sigframe.h b/sys/amd64/include/sigframe.h index 947743d2c0c0..98be731d8f10 100644 --- a/sys/amd64/include/sigframe.h +++ b/sys/amd64/include/sigframe.h @@ -35,6 +35,7 @@ * Signal frames, arguments passed to application signal handlers. */ #ifdef _KERNEL +#ifdef COMPAT_43 struct osigframe { /* * The first four members may be used by applications. @@ -70,6 +71,23 @@ struct osigframe { osiginfo_t sf_siginfo; }; #endif +#ifdef COMPAT_FREEBSD4 +/* FreeBSD 4.x */ +struct sigframe4 { + register_t sf_signum; + register_t sf_siginfo; /* code or pointer to sf_si */ + register_t sf_ucontext; /* points to sf_uc */ + register_t sf_addr; /* undocumented 4th arg */ + + union { + __siginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + struct ucontext4 sf_uc; /* = *sf_ucontext */ + siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ +}; +#endif +#endif struct sigframe { /* diff --git a/sys/amd64/include/signal.h b/sys/amd64/include/signal.h index 9fcca63f1aab..29a97767cc69 100644 --- a/sys/amd64/include/signal.h +++ b/sys/amd64/include/signal.h @@ -60,7 +60,7 @@ typedef int sig_atomic_t; /* * Only the kernel should need these old type definitions. */ -#ifdef _KERNEL +#if defined(_KERNEL) && defined(COMPAT_43) /* * Information pushed on stack when a signal is delivered. * This is used by the kernel to restore state following @@ -68,8 +68,6 @@ typedef int sig_atomic_t; * to the handler to allow it to restore state properly if * a non-standard exit is performed. */ -typedef unsigned int osigset_t; - struct osigcontext { int sc_onstack; /* sigstack state to restore */ osigset_t sc_mask; /* signal mask to restore */ diff --git a/sys/amd64/include/ucontext.h b/sys/amd64/include/ucontext.h index d02959c232d3..af9b4fd3e732 100644 --- a/sys/amd64/include/ucontext.h +++ b/sys/amd64/include/ucontext.h @@ -73,6 +73,34 @@ typedef struct __mcontext { } mcontext_t; #ifdef _KERNEL +#ifdef COMPAT_FREEBSD4 +/* For 4.x binaries */ +struct mcontext4 { + int mc_onstack; /* XXX - sigcontext compat. */ + int mc_gs; + 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; /* machine state */ + int mc_ss; + int mc_fpregs[28]; /* env87 + fpacc87 + u_long */ + int __spare__[17]; +}; +#endif + struct thread; void get_mcontext(struct thread *td, mcontext_t *mcp); |
