/* $NetBSD: freebsd_machdep.c,v 1.5 2021/09/07 11:43:03 riastradh Exp $ */ /*- * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ #include __KERNEL_RCSID(0, "$NetBSD: freebsd_machdep.c,v 1.5 2021/09/07 11:43:03 riastradh Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void freebsd_setregs(struct lwp *l, struct exec_package *epp, vaddr_t stack) { setregs(l, epp, stack); fpu_set_default_cw(l, __FreeBSD_NPXCW__); } /* * signal support */ /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * in u. 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. */ void freebsd_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { int sig = ksi->ksi_signo; u_long code = KSI_TRAPCODE(ksi); struct lwp *l = curlwp; struct proc *p = l->l_proc; int onstack, error; struct freebsd_sigframe *fp = getframe(l, sig, &onstack), frame; sig_t catcher = SIGACTION(p, sig).sa_handler; struct trapframe *tf = l->l_md.md_regs; fp--; memset(&frame, 0, sizeof(frame)); /* Build stack frame for signal trampoline. */ frame.sf_signum = sig; frame.sf_code = code; frame.sf_scp = &fp->sf_sc; frame.sf_addr = (char *)rcr2(); frame.sf_handler = catcher; /* Save context. */ frame.sf_sc.sc_gs = tf->tf_gs; frame.sf_sc.sc_fs = tf->tf_fs; frame.sf_sc.sc_es = tf->tf_es; frame.sf_sc.sc_ds = tf->tf_ds; frame.sf_sc.sc_efl = tf->tf_eflags; frame.sf_sc.sc_edi = tf->tf_edi; frame.sf_sc.sc_esi = tf->tf_esi; frame.sf_sc.sc_ebp = tf->tf_ebp; frame.sf_sc.sc_isp = 0; /* don't have to pass kernel sp to user. */ frame.sf_sc.sc_ebx = tf->tf_ebx; frame.sf_sc.sc_edx = tf->tf_edx; frame.sf_sc.sc_ecx = tf->tf_ecx; frame.sf_sc.sc_eax = tf->tf_eax; frame.sf_sc.sc_eip = tf->tf_eip; frame.sf_sc.sc_cs = tf->tf_cs; frame.sf_sc.sc_esp = tf->tf_esp; frame.sf_sc.sc_ss = tf->tf_ss; /* Save signal stack. */ frame.sf_sc.sc_onstack = l->l_sigstk.ss_flags & SS_ONSTACK; /* Save signal mask. */ /* XXX freebsd_osigcontext compat? */ frame.sf_sc.sc_mask = *mask; sendsig_reset(l, sig); mutex_exit(p->p_lock); error = copyout(&frame, fp, sizeof(frame)); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } buildcontext(l, GUCODEBIG_SEL, p->p_sigctx.ps_sigcode, fp); /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; } /* * 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 * psl to gain improper privileges or to cause * a machine fault. */ int freebsd_sys_sigreturn(struct lwp *l, const struct freebsd_sys_sigreturn_args *uap, register_t *retval) { /* { syscallarg(struct freebsd_sigcontext *) scp; } */ struct proc *p = l->l_proc; struct freebsd_sigcontext *scp, context; struct trapframe *tf; sigset_t mask; /* * The trampoline code hands us the context. * It is unsafe to keep track of it ourselves, in the event that a * program jumps out of a signal handler. */ scp = SCARG(uap, scp); if (copyin((void *)scp, &context, sizeof(*scp)) != 0) return (EFAULT); /* Restore register context. */ tf = l->l_md.md_regs; /* * Check for security violations. If we're returning to * protected mode, the CPU will validate the segment registers * automatically and generate a trap on violations. We handle * the trap, rather than doing all of the checking here. */ if (((context.sc_efl ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || !USERMODE(context.sc_cs)) return (EINVAL); tf->tf_gs = context.sc_gs; tf->tf_fs = context.sc_fs; tf->tf_es = context.sc_es; tf->tf_ds = context.sc_ds; tf->tf_eflags &= ~PSL_USER; tf->tf_eflags |= context.sc_efl & PSL_USER; tf->tf_edi = context.sc_edi; tf->tf_esi = context.sc_esi; tf->tf_ebp = context.sc_ebp; /* FreeBSD's context.sc_isp is useless. (`popal' ignores it.) */ tf->tf_ebx = context.sc_ebx; tf->tf_edx = context.sc_edx; tf->tf_ecx = context.sc_ecx; tf->tf_eax = context.sc_eax; tf->tf_eip = context.sc_eip; tf->tf_cs = context.sc_cs; tf->tf_esp = context.sc_esp; tf->tf_ss = context.sc_ss; mutex_enter(p->p_lock); /* Restore signal stack. */ if (context.sc_onstack & SS_ONSTACK) l->l_sigstk.ss_flags |= SS_ONSTACK; else l->l_sigstk.ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ /* XXX freebsd_osigcontext compat? */ mask = context.sc_mask; (void) sigprocmask1(l, SIG_SETMASK, &mask, 0); mutex_exit(p->p_lock); return (EJUSTRETURN); }