summaryrefslogtreecommitdiffstats
path: root/sys/amd64/ia32/ia32_signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/ia32/ia32_signal.c')
-rw-r--r--sys/amd64/ia32/ia32_signal.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index 29dd01f..2f41870 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -300,6 +300,109 @@ freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
* frame pointer, it returns to the user
* specified pc, psl.
*/
+
+#ifdef COMPAT_43
+static void
+ia32_osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct ia32_sigframe3 sf, *fp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ struct trapframe *regs;
+ int sig;
+ int oonstack;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ sig = ksi->ksi_signo;
+ psp = p->p_sigacts;
+ mtx_assert(&psp->ps_mtx, MA_OWNED);
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_rsp);
+
+ /* Allocate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct ia32_sigframe3 *)(td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size - sizeof(sf));
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ } else
+ fp = (struct ia32_sigframe3 *)regs->tf_rsp - 1;
+
+ /* 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_scp = (register_t)&fp->sf_siginfo.si_sc;
+ if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ sf.sf_arg2 = (register_t)&fp->sf_siginfo;
+ sf.sf_siginfo.si_signo = sig;
+ sf.sf_siginfo.si_code = ksi->ksi_code;
+ sf.sf_ah = (uintptr_t)catcher;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_arg2 = ksi->ksi_code;
+ sf.sf_addr = (register_t)ksi->ksi_addr;
+ sf.sf_ah = (uintptr_t)catcher;
+ }
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(p);
+
+ /* Save most if not all of trap frame. */
+ sf.sf_siginfo.si_sc.sc_eax = regs->tf_rax;
+ sf.sf_siginfo.si_sc.sc_ebx = regs->tf_rbx;
+ sf.sf_siginfo.si_sc.sc_ecx = regs->tf_rcx;
+ sf.sf_siginfo.si_sc.sc_edx = regs->tf_rdx;
+ sf.sf_siginfo.si_sc.sc_esi = regs->tf_rsi;
+ sf.sf_siginfo.si_sc.sc_edi = regs->tf_rdi;
+ sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs;
+ sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds;
+ sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss;
+ sf.sf_siginfo.si_sc.sc_es = regs->tf_es;
+ sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs;
+ sf.sf_siginfo.si_sc.sc_gs = regs->tf_gs;
+ sf.sf_siginfo.si_sc.sc_isp = regs->tf_rsp;
+
+ /* Build the signal context to be used by osigreturn(). */
+ sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0;
+ SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask);
+ sf.sf_siginfo.si_sc.sc_esp = regs->tf_rsp;
+ sf.sf_siginfo.si_sc.sc_ebp = regs->tf_rbp;
+ sf.sf_siginfo.si_sc.sc_eip = regs->tf_rip;
+ sf.sf_siginfo.si_sc.sc_eflags = regs->tf_rflags;
+ sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
+ sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, fp, sizeof(*fp)) != 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)fp;
+ regs->tf_rip = p->p_sysent->sv_psstrings - sz_ia32_osigcode;
+ regs->tf_rflags &= ~(PSL_T | PSL_D);
+ regs->tf_cs = _ucode32sel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_ss = _udatasel;
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+#endif
+
#ifdef COMPAT_FREEBSD4
static void
freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
@@ -441,6 +544,12 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
return;
}
#endif
+#ifdef COMPAT_43
+ if (SIGISMEMBER(psp->ps_osigset, sig)) {
+ ia32_osendsig(catcher, ksi, mask);
+ return;
+ }
+#endif
mtx_assert(&psp->ps_mtx, MA_OWNED);
regs = td->td_frame;
oonstack = sigonstack(regs->tf_rsp);
@@ -547,6 +656,64 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
* make sure that the user has not modified the
* state to gain improper privileges.
*/
+
+#ifdef COMPAT_43
+int
+ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
+{
+ struct ia32_sigcontext3 sc, *scp;
+ struct trapframe *regs;
+ int eflags, error;
+ ksiginfo_t ksi;
+
+ regs = td->td_frame;
+ error = copyin(uap->sigcntxp, &sc, sizeof(sc));
+ if (error != 0)
+ return (error);
+ scp = &sc;
+ eflags = scp->sc_eflags;
+ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) {
+ return (EINVAL);
+ }
+ if (!CS_SECURE(scp->sc_cs)) {
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_trapno = T_PROTFLT;
+ ksi.ksi_addr = (void *)regs->tf_rip;
+ trapsignal(td, &ksi);
+ return (EINVAL);
+ }
+ regs->tf_ds = scp->sc_ds;
+ regs->tf_es = scp->sc_es;
+ regs->tf_fs = scp->sc_fs;
+ regs->tf_gs = scp->sc_gs;
+
+ regs->tf_rax = scp->sc_eax;
+ regs->tf_rbx = scp->sc_ebx;
+ regs->tf_rcx = scp->sc_ecx;
+ regs->tf_rdx = scp->sc_edx;
+ regs->tf_rsi = scp->sc_esi;
+ regs->tf_rdi = scp->sc_edi;
+ regs->tf_cs = scp->sc_cs;
+ regs->tf_ss = scp->sc_ss;
+ regs->tf_rbp = scp->sc_ebp;
+ regs->tf_rsp = scp->sc_esp;
+ regs->tf_rip = scp->sc_eip;
+ regs->tf_rflags = eflags;
+
+ if (scp->sc_onstack & 1)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+
+ kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL,
+ SIGPROCMASK_OLD);
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ return (EJUSTRETURN);
+}
+#endif
+
#ifdef COMPAT_FREEBSD4
/*
* MPSAFE
@@ -734,6 +901,9 @@ ia32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
user_ldt_free(td);
else
mtx_unlock(&dt_lock);
+#ifdef COMPAT_43
+ setup_lcall_gate();
+#endif
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
OpenPOWER on IntegriCloud