Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F111633279
D32310.id96322.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
156 KB
Referenced Files
None
Subscribers
None
D32310.id96322.diff
View Options
diff --git a/sys/arm/arm/exec_machdep.c b/sys/arm/arm/exec_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/arm/exec_machdep.c
@@ -0,0 +1,379 @@
+/* $NetBSD: arm32_machdep.c,v 1.44 2004/03/24 15:34:47 atatat Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2004 Olivier Houchard
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may 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 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/vmmeter.h>
+
+#include <machine/asm.h>
+#include <machine/machdep.h>
+#include <machine/pcb.h>
+#include <machine/sysarch.h>
+#include <machine/vfp.h>
+#include <machine/vmparam.h>
+
+/*
+ * Clear registers on exec
+ */
+void
+exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
+{
+ struct trapframe *tf = td->td_frame;
+
+ memset(tf, 0, sizeof(*tf));
+ tf->tf_usr_sp = stack;
+ tf->tf_usr_lr = imgp->entry_addr;
+ tf->tf_svc_lr = 0x77777777;
+ tf->tf_pc = imgp->entry_addr;
+ tf->tf_spsr = PSR_USR32_MODE;
+ if ((register_t)imgp->entry_addr & 1)
+ tf->tf_spsr |= PSR_T;
+}
+
+#ifdef VFP
+/*
+ * Get machine VFP context.
+ */
+void
+get_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
+{
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+ if (td == curthread) {
+ critical_enter();
+ vfp_store(&pcb->pcb_vfpstate, false);
+ critical_exit();
+ } else
+ MPASS(TD_IS_SUSPENDED(td));
+ memcpy(vfp->mcv_reg, pcb->pcb_vfpstate.reg,
+ sizeof(vfp->mcv_reg));
+ vfp->mcv_fpscr = pcb->pcb_vfpstate.fpscr;
+}
+
+/*
+ * Set machine VFP context.
+ */
+void
+set_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
+{
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+ if (td == curthread) {
+ critical_enter();
+ vfp_discard(td);
+ critical_exit();
+ } else
+ MPASS(TD_IS_SUSPENDED(td));
+ memcpy(pcb->pcb_vfpstate.reg, vfp->mcv_reg,
+ sizeof(pcb->pcb_vfpstate.reg));
+ pcb->pcb_vfpstate.fpscr = vfp->mcv_fpscr;
+}
+#endif
+
+int
+arm_get_vfpstate(struct thread *td, void *args)
+{
+ int rv;
+ struct arm_get_vfpstate_args ua;
+ mcontext_vfp_t mcontext_vfp;
+
+ rv = copyin(args, &ua, sizeof(ua));
+ if (rv != 0)
+ return (rv);
+ if (ua.mc_vfp_size != sizeof(mcontext_vfp_t))
+ return (EINVAL);
+#ifdef VFP
+ get_vfpcontext(td, &mcontext_vfp);
+#else
+ bzero(&mcontext_vfp, sizeof(mcontext_vfp));
+#endif
+
+ rv = copyout(&mcontext_vfp, ua.mc_vfp, sizeof(mcontext_vfp));
+ if (rv != 0)
+ return (rv);
+ return (0);
+}
+
+/*
+ * Get machine context.
+ */
+int
+get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
+{
+ struct trapframe *tf = td->td_frame;
+ __greg_t *gr = mcp->__gregs;
+
+ if (clear_ret & GET_MC_CLEAR_RET) {
+ gr[_REG_R0] = 0;
+ gr[_REG_CPSR] = tf->tf_spsr & ~PSR_C;
+ } else {
+ gr[_REG_R0] = tf->tf_r0;
+ gr[_REG_CPSR] = tf->tf_spsr;
+ }
+ gr[_REG_R1] = tf->tf_r1;
+ gr[_REG_R2] = tf->tf_r2;
+ gr[_REG_R3] = tf->tf_r3;
+ gr[_REG_R4] = tf->tf_r4;
+ gr[_REG_R5] = tf->tf_r5;
+ gr[_REG_R6] = tf->tf_r6;
+ gr[_REG_R7] = tf->tf_r7;
+ gr[_REG_R8] = tf->tf_r8;
+ gr[_REG_R9] = tf->tf_r9;
+ gr[_REG_R10] = tf->tf_r10;
+ gr[_REG_R11] = tf->tf_r11;
+ gr[_REG_R12] = tf->tf_r12;
+ gr[_REG_SP] = tf->tf_usr_sp;
+ gr[_REG_LR] = tf->tf_usr_lr;
+ gr[_REG_PC] = tf->tf_pc;
+
+ mcp->mc_vfp_size = 0;
+ mcp->mc_vfp_ptr = NULL;
+ memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
+
+ return (0);
+}
+
+/*
+ * Set machine context.
+ *
+ * However, we don't set any but the user modifiable flags, and we won't
+ * touch the cs selector.
+ */
+int
+set_mcontext(struct thread *td, mcontext_t *mcp)
+{
+ mcontext_vfp_t mc_vfp, *vfp;
+ struct trapframe *tf = td->td_frame;
+ const __greg_t *gr = mcp->__gregs;
+ int spsr;
+
+ /*
+ * Make sure the processor mode has not been tampered with and
+ * interrupts have not been disabled.
+ */
+ spsr = gr[_REG_CPSR];
+ if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
+ (spsr & (PSR_I | PSR_F)) != 0)
+ return (EINVAL);
+
+#ifdef WITNESS
+ if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(mc_vfp)) {
+ printf("%s: %s: Malformed mc_vfp_size: %d (0x%08X)\n",
+ td->td_proc->p_comm, __func__,
+ mcp->mc_vfp_size, mcp->mc_vfp_size);
+ } else if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr == NULL) {
+ printf("%s: %s: c_vfp_size != 0 but mc_vfp_ptr == NULL\n",
+ td->td_proc->p_comm, __func__);
+ }
+#endif
+
+ if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != NULL) {
+ if (copyin(mcp->mc_vfp_ptr, &mc_vfp, sizeof(mc_vfp)) != 0)
+ return (EFAULT);
+ vfp = &mc_vfp;
+ } else {
+ vfp = NULL;
+ }
+
+ tf->tf_r0 = gr[_REG_R0];
+ tf->tf_r1 = gr[_REG_R1];
+ tf->tf_r2 = gr[_REG_R2];
+ tf->tf_r3 = gr[_REG_R3];
+ tf->tf_r4 = gr[_REG_R4];
+ tf->tf_r5 = gr[_REG_R5];
+ tf->tf_r6 = gr[_REG_R6];
+ tf->tf_r7 = gr[_REG_R7];
+ tf->tf_r8 = gr[_REG_R8];
+ tf->tf_r9 = gr[_REG_R9];
+ tf->tf_r10 = gr[_REG_R10];
+ tf->tf_r11 = gr[_REG_R11];
+ tf->tf_r12 = gr[_REG_R12];
+ tf->tf_usr_sp = gr[_REG_SP];
+ tf->tf_usr_lr = gr[_REG_LR];
+ tf->tf_pc = gr[_REG_PC];
+ tf->tf_spsr = gr[_REG_CPSR];
+#ifdef VFP
+ if (vfp != NULL)
+ set_vfpcontext(td, vfp);
+#endif
+ return (0);
+}
+
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct thread *td;
+ struct proc *p;
+ struct trapframe *tf;
+ struct sigframe *fp, frame;
+ struct sigacts *psp;
+ struct sysentvec *sysent;
+ int onstack;
+ int sig;
+ int code;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ sig = ksi->ksi_signo;
+ code = ksi->ksi_code;
+ psp = p->p_sigacts;
+ mtx_assert(&psp->ps_mtx, MA_OWNED);
+ tf = td->td_frame;
+ onstack = sigonstack(tf->tf_usr_sp);
+
+ CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
+ catcher, sig);
+
+ /* Allocate and validate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size);
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ fp = (struct sigframe *)td->td_frame->tf_usr_sp;
+
+ /* make room on the stack */
+ fp--;
+
+ /* make the stack aligned */
+ fp = (struct sigframe *)STACKALIGN(fp);
+ /* Populate the siginfo frame. */
+ bzero(&frame, sizeof(frame));
+ get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+#ifdef VFP
+ get_vfpcontext(td, &frame.sf_vfp);
+ frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
+ frame.sf_uc.uc_mcontext.mc_vfp_ptr = &fp->sf_vfp;
+#else
+ frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
+ frame.sf_uc.uc_mcontext.mc_vfp_ptr = NULL;
+#endif
+ frame.sf_si = ksi->ksi_info;
+ frame.sf_uc.uc_sigmask = *mask;
+ frame.sf_uc.uc_stack = td->td_sigstk;
+ frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
+ (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(td->td_proc);
+
+ /* Copy the sigframe out to the user's stack. */
+ if (copyout(&frame, fp, sizeof(*fp)) != 0) {
+ /* Process has trashed its stack. Kill it. */
+ CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ /*
+ * Build context to run handler in. We invoke the handler
+ * directly, only returning via the trampoline. Note the
+ * trampoline version numbers are coordinated with machine-
+ * dependent code in libc.
+ */
+
+ tf->tf_r0 = sig;
+ tf->tf_r1 = (register_t)&fp->sf_si;
+ tf->tf_r2 = (register_t)&fp->sf_uc;
+
+ /* the trampoline uses r5 as the uc address */
+ tf->tf_r5 = (register_t)&fp->sf_uc;
+ tf->tf_pc = (register_t)catcher;
+ tf->tf_usr_sp = (register_t)fp;
+ sysent = p->p_sysent;
+ if (sysent->sv_sigcode_base != 0)
+ tf->tf_usr_lr = (register_t)sysent->sv_sigcode_base;
+ else
+ tf->tf_usr_lr = (register_t)(sysent->sv_psstrings -
+ *(sysent->sv_szsigcode));
+ /* Set the mode to enter in the signal handler */
+#if __ARM_ARCH >= 7
+ if ((register_t)catcher & 1)
+ tf->tf_spsr |= PSR_T;
+ else
+ tf->tf_spsr &= ~PSR_T;
+#endif
+
+ CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr,
+ tf->tf_usr_sp);
+
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+ ucontext_t uc;
+ int error;
+
+ if (uap == NULL)
+ return (EFAULT);
+ if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
+ return (EFAULT);
+ /* Restore register context. */
+ error = set_mcontext(td, &uc.uc_mcontext);
+ if (error != 0)
+ return (error);
+
+ /* Restore signal mask. */
+ kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
+
+ return (EJUSTRETURN);
+}
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -332,328 +332,6 @@
}
}
-/*
- * Clear registers on exec
- */
-void
-exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
-{
- struct trapframe *tf = td->td_frame;
-
- memset(tf, 0, sizeof(*tf));
- tf->tf_usr_sp = stack;
- tf->tf_usr_lr = imgp->entry_addr;
- tf->tf_svc_lr = 0x77777777;
- tf->tf_pc = imgp->entry_addr;
- tf->tf_spsr = PSR_USR32_MODE;
- if ((register_t)imgp->entry_addr & 1)
- tf->tf_spsr |= PSR_T;
-}
-
-#ifdef VFP
-/*
- * Get machine VFP context.
- */
-void
-get_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
-{
- struct pcb *pcb;
-
- pcb = td->td_pcb;
- if (td == curthread) {
- critical_enter();
- vfp_store(&pcb->pcb_vfpstate, false);
- critical_exit();
- } else
- MPASS(TD_IS_SUSPENDED(td));
- memcpy(vfp->mcv_reg, pcb->pcb_vfpstate.reg,
- sizeof(vfp->mcv_reg));
- vfp->mcv_fpscr = pcb->pcb_vfpstate.fpscr;
-}
-
-/*
- * Set machine VFP context.
- */
-void
-set_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
-{
- struct pcb *pcb;
-
- pcb = td->td_pcb;
- if (td == curthread) {
- critical_enter();
- vfp_discard(td);
- critical_exit();
- } else
- MPASS(TD_IS_SUSPENDED(td));
- memcpy(pcb->pcb_vfpstate.reg, vfp->mcv_reg,
- sizeof(pcb->pcb_vfpstate.reg));
- pcb->pcb_vfpstate.fpscr = vfp->mcv_fpscr;
-}
-#endif
-
-int
-arm_get_vfpstate(struct thread *td, void *args)
-{
- int rv;
- struct arm_get_vfpstate_args ua;
- mcontext_vfp_t mcontext_vfp;
-
- rv = copyin(args, &ua, sizeof(ua));
- if (rv != 0)
- return (rv);
- if (ua.mc_vfp_size != sizeof(mcontext_vfp_t))
- return (EINVAL);
-#ifdef VFP
- get_vfpcontext(td, &mcontext_vfp);
-#else
- bzero(&mcontext_vfp, sizeof(mcontext_vfp));
-#endif
-
- rv = copyout(&mcontext_vfp, ua.mc_vfp, sizeof(mcontext_vfp));
- if (rv != 0)
- return (rv);
- return (0);
-}
-
-/*
- * Get machine context.
- */
-int
-get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
-{
- struct trapframe *tf = td->td_frame;
- __greg_t *gr = mcp->__gregs;
-
- if (clear_ret & GET_MC_CLEAR_RET) {
- gr[_REG_R0] = 0;
- gr[_REG_CPSR] = tf->tf_spsr & ~PSR_C;
- } else {
- gr[_REG_R0] = tf->tf_r0;
- gr[_REG_CPSR] = tf->tf_spsr;
- }
- gr[_REG_R1] = tf->tf_r1;
- gr[_REG_R2] = tf->tf_r2;
- gr[_REG_R3] = tf->tf_r3;
- gr[_REG_R4] = tf->tf_r4;
- gr[_REG_R5] = tf->tf_r5;
- gr[_REG_R6] = tf->tf_r6;
- gr[_REG_R7] = tf->tf_r7;
- gr[_REG_R8] = tf->tf_r8;
- gr[_REG_R9] = tf->tf_r9;
- gr[_REG_R10] = tf->tf_r10;
- gr[_REG_R11] = tf->tf_r11;
- gr[_REG_R12] = tf->tf_r12;
- gr[_REG_SP] = tf->tf_usr_sp;
- gr[_REG_LR] = tf->tf_usr_lr;
- gr[_REG_PC] = tf->tf_pc;
-
- mcp->mc_vfp_size = 0;
- mcp->mc_vfp_ptr = NULL;
- memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
-
- return (0);
-}
-
-/*
- * Set machine context.
- *
- * However, we don't set any but the user modifiable flags, and we won't
- * touch the cs selector.
- */
-int
-set_mcontext(struct thread *td, mcontext_t *mcp)
-{
- mcontext_vfp_t mc_vfp, *vfp;
- struct trapframe *tf = td->td_frame;
- const __greg_t *gr = mcp->__gregs;
- int spsr;
-
- /*
- * Make sure the processor mode has not been tampered with and
- * interrupts have not been disabled.
- */
- spsr = gr[_REG_CPSR];
- if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
- (spsr & (PSR_I | PSR_F)) != 0)
- return (EINVAL);
-
-#ifdef WITNESS
- if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(mc_vfp)) {
- printf("%s: %s: Malformed mc_vfp_size: %d (0x%08X)\n",
- td->td_proc->p_comm, __func__,
- mcp->mc_vfp_size, mcp->mc_vfp_size);
- } else if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr == NULL) {
- printf("%s: %s: c_vfp_size != 0 but mc_vfp_ptr == NULL\n",
- td->td_proc->p_comm, __func__);
- }
-#endif
-
- if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != NULL) {
- if (copyin(mcp->mc_vfp_ptr, &mc_vfp, sizeof(mc_vfp)) != 0)
- return (EFAULT);
- vfp = &mc_vfp;
- } else {
- vfp = NULL;
- }
-
- tf->tf_r0 = gr[_REG_R0];
- tf->tf_r1 = gr[_REG_R1];
- tf->tf_r2 = gr[_REG_R2];
- tf->tf_r3 = gr[_REG_R3];
- tf->tf_r4 = gr[_REG_R4];
- tf->tf_r5 = gr[_REG_R5];
- tf->tf_r6 = gr[_REG_R6];
- tf->tf_r7 = gr[_REG_R7];
- tf->tf_r8 = gr[_REG_R8];
- tf->tf_r9 = gr[_REG_R9];
- tf->tf_r10 = gr[_REG_R10];
- tf->tf_r11 = gr[_REG_R11];
- tf->tf_r12 = gr[_REG_R12];
- tf->tf_usr_sp = gr[_REG_SP];
- tf->tf_usr_lr = gr[_REG_LR];
- tf->tf_pc = gr[_REG_PC];
- tf->tf_spsr = gr[_REG_CPSR];
-#ifdef VFP
- if (vfp != NULL)
- set_vfpcontext(td, vfp);
-#endif
- return (0);
-}
-
-void
-sendsig(catcher, ksi, mask)
- sig_t catcher;
- ksiginfo_t *ksi;
- sigset_t *mask;
-{
- struct thread *td;
- struct proc *p;
- struct trapframe *tf;
- struct sigframe *fp, frame;
- struct sigacts *psp;
- struct sysentvec *sysent;
- int onstack;
- int sig;
- int code;
-
- td = curthread;
- p = td->td_proc;
- PROC_LOCK_ASSERT(p, MA_OWNED);
- sig = ksi->ksi_signo;
- code = ksi->ksi_code;
- psp = p->p_sigacts;
- mtx_assert(&psp->ps_mtx, MA_OWNED);
- tf = td->td_frame;
- onstack = sigonstack(tf->tf_usr_sp);
-
- CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
- catcher, sig);
-
- /* Allocate and validate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
- td->td_sigstk.ss_size);
-#if defined(COMPAT_43)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
- } else
- fp = (struct sigframe *)td->td_frame->tf_usr_sp;
-
- /* make room on the stack */
- fp--;
-
- /* make the stack aligned */
- fp = (struct sigframe *)STACKALIGN(fp);
- /* Populate the siginfo frame. */
- bzero(&frame, sizeof(frame));
- get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
-#ifdef VFP
- get_vfpcontext(td, &frame.sf_vfp);
- frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
- frame.sf_uc.uc_mcontext.mc_vfp_ptr = &fp->sf_vfp;
-#else
- frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
- frame.sf_uc.uc_mcontext.mc_vfp_ptr = NULL;
-#endif
- frame.sf_si = ksi->ksi_info;
- frame.sf_uc.uc_sigmask = *mask;
- frame.sf_uc.uc_stack = td->td_sigstk;
- frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
- (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
- mtx_unlock(&psp->ps_mtx);
- PROC_UNLOCK(td->td_proc);
-
- /* Copy the sigframe out to the user's stack. */
- if (copyout(&frame, fp, sizeof(*fp)) != 0) {
- /* Process has trashed its stack. Kill it. */
- CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- /*
- * Build context to run handler in. We invoke the handler
- * directly, only returning via the trampoline. Note the
- * trampoline version numbers are coordinated with machine-
- * dependent code in libc.
- */
-
- tf->tf_r0 = sig;
- tf->tf_r1 = (register_t)&fp->sf_si;
- tf->tf_r2 = (register_t)&fp->sf_uc;
-
- /* the trampoline uses r5 as the uc address */
- tf->tf_r5 = (register_t)&fp->sf_uc;
- tf->tf_pc = (register_t)catcher;
- tf->tf_usr_sp = (register_t)fp;
- sysent = p->p_sysent;
- if (sysent->sv_sigcode_base != 0)
- tf->tf_usr_lr = (register_t)sysent->sv_sigcode_base;
- else
- tf->tf_usr_lr = (register_t)(sysent->sv_psstrings -
- *(sysent->sv_szsigcode));
- /* Set the mode to enter in the signal handler */
-#if __ARM_ARCH >= 7
- if ((register_t)catcher & 1)
- tf->tf_spsr |= PSR_T;
- else
- tf->tf_spsr &= ~PSR_T;
-#endif
-
- CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr,
- tf->tf_usr_sp);
-
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-
-int
-sys_sigreturn(td, uap)
- struct thread *td;
- struct sigreturn_args /* {
- const struct __ucontext *sigcntxp;
- } */ *uap;
-{
- ucontext_t uc;
- int error;
-
- if (uap == NULL)
- return (EFAULT);
- if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
- return (EFAULT);
- /* Restore register context. */
- error = set_mcontext(td, &uc.uc_mcontext);
- if (error != 0)
- return (error);
-
- /* Restore signal mask. */
- kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
-
- return (EJUSTRETURN);
-}
-
/*
* Construct a PCB from a trapframe. This is called from kdb_trap() where
* we want to start a backtrace from the function that caused us to enter
diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/arm64/exec_machdep.c
@@ -0,0 +1,617 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+#include <sys/rwlock.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/armreg.h>
+#include <machine/kdb.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+
+#ifdef VFP
+#include <machine/vfp.h>
+#endif
+
+static void get_fpcontext(struct thread *td, mcontext_t *mcp);
+static void set_fpcontext(struct thread *td, mcontext_t *mcp);
+
+int
+fill_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+ regs->sp = frame->tf_sp;
+ regs->lr = frame->tf_lr;
+ regs->elr = frame->tf_elr;
+ regs->spsr = frame->tf_spsr;
+
+ memcpy(regs->x, frame->tf_x, sizeof(regs->x));
+
+#ifdef COMPAT_FREEBSD32
+ /*
+ * We may be called here for a 32bits process, if we're using a
+ * 64bits debugger. If so, put PC and SPSR where it expects it.
+ */
+ if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
+ regs->x[15] = frame->tf_elr;
+ regs->x[16] = frame->tf_spsr;
+ }
+#endif
+ return (0);
+}
+
+int
+set_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+ frame->tf_sp = regs->sp;
+ frame->tf_lr = regs->lr;
+ frame->tf_spsr &= ~PSR_FLAGS;
+
+ memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
+
+#ifdef COMPAT_FREEBSD32
+ if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
+ /*
+ * We may be called for a 32bits process if we're using
+ * a 64bits debugger. If so, get PC and SPSR from where
+ * it put it.
+ */
+ frame->tf_elr = regs->x[15];
+ frame->tf_spsr |= regs->x[16] & PSR_FLAGS;
+ } else
+#endif
+ {
+ frame->tf_elr = regs->elr;
+ frame->tf_spsr |= regs->spsr & PSR_FLAGS;
+ }
+ return (0);
+}
+
+int
+fill_fpregs(struct thread *td, struct fpreg *regs)
+{
+#ifdef VFP
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+ if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running VFP instructions we will
+ * need to save the state to memcpy it below.
+ */
+ if (td == curthread)
+ vfp_save_state(td, pcb);
+
+ KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
+ ("Called fill_fpregs while the kernel is using the VFP"));
+ memcpy(regs->fp_q, pcb->pcb_fpustate.vfp_regs,
+ sizeof(regs->fp_q));
+ regs->fp_cr = pcb->pcb_fpustate.vfp_fpcr;
+ regs->fp_sr = pcb->pcb_fpustate.vfp_fpsr;
+ } else
+#endif
+ memset(regs, 0, sizeof(*regs));
+ return (0);
+}
+
+int
+set_fpregs(struct thread *td, struct fpreg *regs)
+{
+#ifdef VFP
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+ KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
+ ("Called set_fpregs while the kernel is using the VFP"));
+ memcpy(pcb->pcb_fpustate.vfp_regs, regs->fp_q, sizeof(regs->fp_q));
+ pcb->pcb_fpustate.vfp_fpcr = regs->fp_cr;
+ pcb->pcb_fpustate.vfp_fpsr = regs->fp_sr;
+#endif
+ return (0);
+}
+
+int
+fill_dbregs(struct thread *td, struct dbreg *regs)
+{
+ struct debug_monitor_state *monitor;
+ int i;
+ uint8_t debug_ver, nbkpts, nwtpts;
+
+ memset(regs, 0, sizeof(*regs));
+
+ extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_DebugVer_SHIFT,
+ &debug_ver);
+ extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_BRPs_SHIFT,
+ &nbkpts);
+ extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_WRPs_SHIFT,
+ &nwtpts);
+
+ /*
+ * The BRPs field contains the number of breakpoints - 1. Armv8-A
+ * allows the hardware to provide 2-16 breakpoints so this won't
+ * overflow an 8 bit value. The same applies to the WRPs field.
+ */
+ nbkpts++;
+ nwtpts++;
+
+ regs->db_debug_ver = debug_ver;
+ regs->db_nbkpts = nbkpts;
+ regs->db_nwtpts = nwtpts;
+
+ monitor = &td->td_pcb->pcb_dbg_regs;
+ if ((monitor->dbg_flags & DBGMON_ENABLED) != 0) {
+ for (i = 0; i < nbkpts; i++) {
+ regs->db_breakregs[i].dbr_addr = monitor->dbg_bvr[i];
+ regs->db_breakregs[i].dbr_ctrl = monitor->dbg_bcr[i];
+ }
+ for (i = 0; i < nwtpts; i++) {
+ regs->db_watchregs[i].dbw_addr = monitor->dbg_wvr[i];
+ regs->db_watchregs[i].dbw_ctrl = monitor->dbg_wcr[i];
+ }
+ }
+
+ return (0);
+}
+
+int
+set_dbregs(struct thread *td, struct dbreg *regs)
+{
+ struct debug_monitor_state *monitor;
+ uint64_t addr;
+ uint32_t ctrl;
+ int count;
+ int i;
+
+ monitor = &td->td_pcb->pcb_dbg_regs;
+ count = 0;
+ monitor->dbg_enable_count = 0;
+
+ for (i = 0; i < DBG_BRP_MAX; i++) {
+ addr = regs->db_breakregs[i].dbr_addr;
+ ctrl = regs->db_breakregs[i].dbr_ctrl;
+
+ /*
+ * Don't let the user set a breakpoint on a kernel or
+ * non-canonical user address.
+ */
+ if (addr >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+
+ /*
+ * The lowest 2 bits are ignored, so record the effective
+ * address.
+ */
+ addr = rounddown2(addr, 4);
+
+ /*
+ * Some control fields are ignored, and other bits reserved.
+ * Only unlinked, address-matching breakpoints are supported.
+ *
+ * XXX: fields that appear unvalidated, such as BAS, have
+ * constrained undefined behaviour. If the user mis-programs
+ * these, there is no risk to the system.
+ */
+ ctrl &= DBG_BCR_EN | DBG_BCR_PMC | DBG_BCR_BAS;
+ if ((ctrl & DBG_BCR_EN) != 0) {
+ /* Only target EL0. */
+ if ((ctrl & DBG_BCR_PMC) != DBG_BCR_PMC_EL0)
+ return (EINVAL);
+
+ monitor->dbg_enable_count++;
+ }
+
+ monitor->dbg_bvr[i] = addr;
+ monitor->dbg_bcr[i] = ctrl;
+ }
+
+ for (i = 0; i < DBG_WRP_MAX; i++) {
+ addr = regs->db_watchregs[i].dbw_addr;
+ ctrl = regs->db_watchregs[i].dbw_ctrl;
+
+ /*
+ * Don't let the user set a watchpoint on a kernel or
+ * non-canonical user address.
+ */
+ if (addr >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+
+ /*
+ * Some control fields are ignored, and other bits reserved.
+ * Only unlinked watchpoints are supported.
+ */
+ ctrl &= DBG_WCR_EN | DBG_WCR_PAC | DBG_WCR_LSC | DBG_WCR_BAS |
+ DBG_WCR_MASK;
+
+ if ((ctrl & DBG_WCR_EN) != 0) {
+ /* Only target EL0. */
+ if ((ctrl & DBG_WCR_PAC) != DBG_WCR_PAC_EL0)
+ return (EINVAL);
+
+ /* Must set at least one of the load/store bits. */
+ if ((ctrl & DBG_WCR_LSC) == 0)
+ return (EINVAL);
+
+ /*
+ * When specifying the address range with BAS, the MASK
+ * field must be zero.
+ */
+ if ((ctrl & DBG_WCR_BAS) != DBG_WCR_BAS_MASK &&
+ (ctrl & DBG_WCR_MASK) != 0)
+ return (EINVAL);
+
+ monitor->dbg_enable_count++;
+ }
+ monitor->dbg_wvr[i] = addr;
+ monitor->dbg_wcr[i] = ctrl;
+ }
+
+ if (monitor->dbg_enable_count > 0)
+ monitor->dbg_flags |= DBGMON_ENABLED;
+
+ return (0);
+}
+
+#ifdef COMPAT_FREEBSD32
+int
+fill_regs32(struct thread *td, struct reg32 *regs)
+{
+ int i;
+ struct trapframe *tf;
+
+ tf = td->td_frame;
+ for (i = 0; i < 13; i++)
+ regs->r[i] = tf->tf_x[i];
+ /* For arm32, SP is r13 and LR is r14 */
+ regs->r_sp = tf->tf_x[13];
+ regs->r_lr = tf->tf_x[14];
+ regs->r_pc = tf->tf_elr;
+ regs->r_cpsr = tf->tf_spsr;
+
+ return (0);
+}
+
+int
+set_regs32(struct thread *td, struct reg32 *regs)
+{
+ int i;
+ struct trapframe *tf;
+
+ tf = td->td_frame;
+ for (i = 0; i < 13; i++)
+ tf->tf_x[i] = regs->r[i];
+ /* For arm 32, SP is r13 an LR is r14 */
+ tf->tf_x[13] = regs->r_sp;
+ tf->tf_x[14] = regs->r_lr;
+ tf->tf_elr = regs->r_pc;
+ tf->tf_spsr &= ~PSR_FLAGS;
+ tf->tf_spsr |= regs->r_cpsr & PSR_FLAGS;
+
+ return (0);
+}
+
+/* XXX fill/set dbregs/fpregs are stubbed on 32-bit arm. */
+int
+fill_fpregs32(struct thread *td, struct fpreg32 *regs)
+{
+
+ memset(regs, 0, sizeof(*regs));
+ return (0);
+}
+
+int
+set_fpregs32(struct thread *td, struct fpreg32 *regs)
+{
+
+ return (0);
+}
+
+int
+fill_dbregs32(struct thread *td, struct dbreg32 *regs)
+{
+
+ memset(regs, 0, sizeof(*regs));
+ return (0);
+}
+
+int
+set_dbregs32(struct thread *td, struct dbreg32 *regs)
+{
+
+ return (0);
+}
+#endif
+
+void
+exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
+{
+ struct trapframe *tf = td->td_frame;
+ struct pcb *pcb = td->td_pcb;
+
+ memset(tf, 0, sizeof(struct trapframe));
+
+ tf->tf_x[0] = stack;
+ tf->tf_sp = STACKALIGN(stack);
+ tf->tf_lr = imgp->entry_addr;
+ tf->tf_elr = imgp->entry_addr;
+
+ td->td_pcb->pcb_tpidr_el0 = 0;
+ td->td_pcb->pcb_tpidrro_el0 = 0;
+ WRITE_SPECIALREG(tpidrro_el0, 0);
+ WRITE_SPECIALREG(tpidr_el0, 0);
+
+#ifdef VFP
+ vfp_reset_state(td, pcb);
+#endif
+
+ /*
+ * Clear debug register state. It is not applicable to the new process.
+ */
+ bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
+}
+
+/* Sanity check these are the same size, they will be memcpy'd to and from */
+CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
+ sizeof((struct gpregs *)0)->gp_x);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
+ sizeof((struct reg *)0)->x);
+
+int
+get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
+{
+ struct trapframe *tf = td->td_frame;
+
+ if (clear_ret & GET_MC_CLEAR_RET) {
+ mcp->mc_gpregs.gp_x[0] = 0;
+ mcp->mc_gpregs.gp_spsr = tf->tf_spsr & ~PSR_C;
+ } else {
+ mcp->mc_gpregs.gp_x[0] = tf->tf_x[0];
+ mcp->mc_gpregs.gp_spsr = tf->tf_spsr;
+ }
+
+ memcpy(&mcp->mc_gpregs.gp_x[1], &tf->tf_x[1],
+ sizeof(mcp->mc_gpregs.gp_x[1]) * (nitems(mcp->mc_gpregs.gp_x) - 1));
+
+ mcp->mc_gpregs.gp_sp = tf->tf_sp;
+ mcp->mc_gpregs.gp_lr = tf->tf_lr;
+ mcp->mc_gpregs.gp_elr = tf->tf_elr;
+ get_fpcontext(td, mcp);
+
+ return (0);
+}
+
+int
+set_mcontext(struct thread *td, mcontext_t *mcp)
+{
+ struct trapframe *tf = td->td_frame;
+ uint32_t spsr;
+
+ spsr = mcp->mc_gpregs.gp_spsr;
+ if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
+ (spsr & PSR_AARCH32) != 0 ||
+ (spsr & PSR_DAIF) != (td->td_frame->tf_spsr & PSR_DAIF))
+ return (EINVAL);
+
+ memcpy(tf->tf_x, mcp->mc_gpregs.gp_x, sizeof(tf->tf_x));
+
+ tf->tf_sp = mcp->mc_gpregs.gp_sp;
+ tf->tf_lr = mcp->mc_gpregs.gp_lr;
+ tf->tf_elr = mcp->mc_gpregs.gp_elr;
+ tf->tf_spsr = mcp->mc_gpregs.gp_spsr;
+ set_fpcontext(td, mcp);
+
+ return (0);
+}
+
+static void
+get_fpcontext(struct thread *td, mcontext_t *mcp)
+{
+#ifdef VFP
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ curpcb = curthread->td_pcb;
+
+ if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running VFP instructions we will
+ * need to save the state to memcpy it below.
+ */
+ vfp_save_state(td, curpcb);
+
+ KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
+ ("Called get_fpcontext while the kernel is using the VFP"));
+ KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
+ ("Non-userspace FPU flags set in get_fpcontext"));
+ memcpy(mcp->mc_fpregs.fp_q, curpcb->pcb_fpustate.vfp_regs,
+ sizeof(mcp->mc_fpregs.fp_q));
+ mcp->mc_fpregs.fp_cr = curpcb->pcb_fpustate.vfp_fpcr;
+ mcp->mc_fpregs.fp_sr = curpcb->pcb_fpustate.vfp_fpsr;
+ mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
+ mcp->mc_flags |= _MC_FP_VALID;
+ }
+
+ critical_exit();
+#endif
+}
+
+static void
+set_fpcontext(struct thread *td, mcontext_t *mcp)
+{
+#ifdef VFP
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
+ curpcb = curthread->td_pcb;
+
+ /*
+ * Discard any vfp state for the current thread, we
+ * are about to override it.
+ */
+ vfp_discard(td);
+
+ KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
+ ("Called set_fpcontext while the kernel is using the VFP"));
+ memcpy(curpcb->pcb_fpustate.vfp_regs, mcp->mc_fpregs.fp_q,
+ sizeof(mcp->mc_fpregs.fp_q));
+ curpcb->pcb_fpustate.vfp_fpcr = mcp->mc_fpregs.fp_cr;
+ curpcb->pcb_fpustate.vfp_fpsr = mcp->mc_fpregs.fp_sr;
+ curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
+ }
+
+ critical_exit();
+#endif
+}
+
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+ ucontext_t uc;
+ int error;
+
+ if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
+ return (EFAULT);
+
+ error = set_mcontext(td, &uc.uc_mcontext);
+ if (error != 0)
+ return (error);
+
+ /* Restore signal mask. */
+ kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
+
+ return (EJUSTRETURN);
+}
+
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct thread *td;
+ struct proc *p;
+ struct trapframe *tf;
+ struct sigframe *fp, frame;
+ struct sigacts *psp;
+ struct sysentvec *sysent;
+ int onstack, sig;
+
+ 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);
+
+ tf = td->td_frame;
+ onstack = sigonstack(tf->tf_sp);
+
+ CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
+ catcher, sig);
+
+ /* Allocate and validate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size);
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else {
+ fp = (struct sigframe *)td->td_frame->tf_sp;
+ }
+
+ /* Make room, keeping the stack aligned */
+ fp--;
+ fp = (struct sigframe *)STACKALIGN(fp);
+
+ /* Fill in the frame to copy out */
+ bzero(&frame, sizeof(frame));
+ get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+ frame.sf_si = ksi->ksi_info;
+ frame.sf_uc.uc_sigmask = *mask;
+ frame.sf_uc.uc_stack = td->td_sigstk;
+ frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
+ (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(td->td_proc);
+
+ /* Copy the sigframe out to the user's stack. */
+ if (copyout(&frame, fp, sizeof(*fp)) != 0) {
+ /* Process has trashed its stack. Kill it. */
+ CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ tf->tf_x[0]= sig;
+ tf->tf_x[1] = (register_t)&fp->sf_si;
+ tf->tf_x[2] = (register_t)&fp->sf_uc;
+
+ tf->tf_elr = (register_t)catcher;
+ tf->tf_sp = (register_t)fp;
+ sysent = p->p_sysent;
+ if (sysent->sv_sigcode_base != 0)
+ tf->tf_lr = (register_t)sysent->sv_sigcode_base;
+ else
+ tf->tf_lr = (register_t)(sysent->sv_psstrings -
+ *(sysent->sv_szsigcode));
+
+ CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
+ tf->tf_sp);
+
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -100,9 +100,6 @@
#include <dev/ofw/openfirm.h>
#endif
-static void get_fpcontext(struct thread *td, mcontext_t *mcp);
-static void set_fpcontext(struct thread *td, mcontext_t *mcp);
-
enum arm64_bus arm64_bus_method = ARM64_BUS_NONE;
struct pcpu __pcpu[MAXCPU];
@@ -220,486 +217,6 @@
return (0);
}
-int
-fill_regs(struct thread *td, struct reg *regs)
-{
- struct trapframe *frame;
-
- frame = td->td_frame;
- regs->sp = frame->tf_sp;
- regs->lr = frame->tf_lr;
- regs->elr = frame->tf_elr;
- regs->spsr = frame->tf_spsr;
-
- memcpy(regs->x, frame->tf_x, sizeof(regs->x));
-
-#ifdef COMPAT_FREEBSD32
- /*
- * We may be called here for a 32bits process, if we're using a
- * 64bits debugger. If so, put PC and SPSR where it expects it.
- */
- if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
- regs->x[15] = frame->tf_elr;
- regs->x[16] = frame->tf_spsr;
- }
-#endif
- return (0);
-}
-
-int
-set_regs(struct thread *td, struct reg *regs)
-{
- struct trapframe *frame;
-
- frame = td->td_frame;
- frame->tf_sp = regs->sp;
- frame->tf_lr = regs->lr;
- frame->tf_spsr &= ~PSR_FLAGS;
-
- memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
-
-#ifdef COMPAT_FREEBSD32
- if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
- /*
- * We may be called for a 32bits process if we're using
- * a 64bits debugger. If so, get PC and SPSR from where
- * it put it.
- */
- frame->tf_elr = regs->x[15];
- frame->tf_spsr |= regs->x[16] & PSR_FLAGS;
- } else
-#endif
- {
- frame->tf_elr = regs->elr;
- frame->tf_spsr |= regs->spsr & PSR_FLAGS;
- }
- return (0);
-}
-
-int
-fill_fpregs(struct thread *td, struct fpreg *regs)
-{
-#ifdef VFP
- struct pcb *pcb;
-
- pcb = td->td_pcb;
- if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
- /*
- * If we have just been running VFP instructions we will
- * need to save the state to memcpy it below.
- */
- if (td == curthread)
- vfp_save_state(td, pcb);
-
- KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
- ("Called fill_fpregs while the kernel is using the VFP"));
- memcpy(regs->fp_q, pcb->pcb_fpustate.vfp_regs,
- sizeof(regs->fp_q));
- regs->fp_cr = pcb->pcb_fpustate.vfp_fpcr;
- regs->fp_sr = pcb->pcb_fpustate.vfp_fpsr;
- } else
-#endif
- memset(regs, 0, sizeof(*regs));
- return (0);
-}
-
-int
-set_fpregs(struct thread *td, struct fpreg *regs)
-{
-#ifdef VFP
- struct pcb *pcb;
-
- pcb = td->td_pcb;
- KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
- ("Called set_fpregs while the kernel is using the VFP"));
- memcpy(pcb->pcb_fpustate.vfp_regs, regs->fp_q, sizeof(regs->fp_q));
- pcb->pcb_fpustate.vfp_fpcr = regs->fp_cr;
- pcb->pcb_fpustate.vfp_fpsr = regs->fp_sr;
-#endif
- return (0);
-}
-
-int
-fill_dbregs(struct thread *td, struct dbreg *regs)
-{
- struct debug_monitor_state *monitor;
- int i;
- uint8_t debug_ver, nbkpts, nwtpts;
-
- memset(regs, 0, sizeof(*regs));
-
- extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_DebugVer_SHIFT,
- &debug_ver);
- extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_BRPs_SHIFT,
- &nbkpts);
- extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_WRPs_SHIFT,
- &nwtpts);
-
- /*
- * The BRPs field contains the number of breakpoints - 1. Armv8-A
- * allows the hardware to provide 2-16 breakpoints so this won't
- * overflow an 8 bit value. The same applies to the WRPs field.
- */
- nbkpts++;
- nwtpts++;
-
- regs->db_debug_ver = debug_ver;
- regs->db_nbkpts = nbkpts;
- regs->db_nwtpts = nwtpts;
-
- monitor = &td->td_pcb->pcb_dbg_regs;
- if ((monitor->dbg_flags & DBGMON_ENABLED) != 0) {
- for (i = 0; i < nbkpts; i++) {
- regs->db_breakregs[i].dbr_addr = monitor->dbg_bvr[i];
- regs->db_breakregs[i].dbr_ctrl = monitor->dbg_bcr[i];
- }
- for (i = 0; i < nwtpts; i++) {
- regs->db_watchregs[i].dbw_addr = monitor->dbg_wvr[i];
- regs->db_watchregs[i].dbw_ctrl = monitor->dbg_wcr[i];
- }
- }
-
- return (0);
-}
-
-int
-set_dbregs(struct thread *td, struct dbreg *regs)
-{
- struct debug_monitor_state *monitor;
- uint64_t addr;
- uint32_t ctrl;
- int count;
- int i;
-
- monitor = &td->td_pcb->pcb_dbg_regs;
- count = 0;
- monitor->dbg_enable_count = 0;
-
- for (i = 0; i < DBG_BRP_MAX; i++) {
- addr = regs->db_breakregs[i].dbr_addr;
- ctrl = regs->db_breakregs[i].dbr_ctrl;
-
- /*
- * Don't let the user set a breakpoint on a kernel or
- * non-canonical user address.
- */
- if (addr >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
-
- /*
- * The lowest 2 bits are ignored, so record the effective
- * address.
- */
- addr = rounddown2(addr, 4);
-
- /*
- * Some control fields are ignored, and other bits reserved.
- * Only unlinked, address-matching breakpoints are supported.
- *
- * XXX: fields that appear unvalidated, such as BAS, have
- * constrained undefined behaviour. If the user mis-programs
- * these, there is no risk to the system.
- */
- ctrl &= DBG_BCR_EN | DBG_BCR_PMC | DBG_BCR_BAS;
- if ((ctrl & DBG_BCR_EN) != 0) {
- /* Only target EL0. */
- if ((ctrl & DBG_BCR_PMC) != DBG_BCR_PMC_EL0)
- return (EINVAL);
-
- monitor->dbg_enable_count++;
- }
-
- monitor->dbg_bvr[i] = addr;
- monitor->dbg_bcr[i] = ctrl;
- }
-
- for (i = 0; i < DBG_WRP_MAX; i++) {
- addr = regs->db_watchregs[i].dbw_addr;
- ctrl = regs->db_watchregs[i].dbw_ctrl;
-
- /*
- * Don't let the user set a watchpoint on a kernel or
- * non-canonical user address.
- */
- if (addr >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
-
- /*
- * Some control fields are ignored, and other bits reserved.
- * Only unlinked watchpoints are supported.
- */
- ctrl &= DBG_WCR_EN | DBG_WCR_PAC | DBG_WCR_LSC | DBG_WCR_BAS |
- DBG_WCR_MASK;
-
- if ((ctrl & DBG_WCR_EN) != 0) {
- /* Only target EL0. */
- if ((ctrl & DBG_WCR_PAC) != DBG_WCR_PAC_EL0)
- return (EINVAL);
-
- /* Must set at least one of the load/store bits. */
- if ((ctrl & DBG_WCR_LSC) == 0)
- return (EINVAL);
-
- /*
- * When specifying the address range with BAS, the MASK
- * field must be zero.
- */
- if ((ctrl & DBG_WCR_BAS) != DBG_WCR_BAS_MASK &&
- (ctrl & DBG_WCR_MASK) != 0)
- return (EINVAL);
-
- monitor->dbg_enable_count++;
- }
- monitor->dbg_wvr[i] = addr;
- monitor->dbg_wcr[i] = ctrl;
- }
-
- if (monitor->dbg_enable_count > 0)
- monitor->dbg_flags |= DBGMON_ENABLED;
-
- return (0);
-}
-
-#ifdef COMPAT_FREEBSD32
-int
-fill_regs32(struct thread *td, struct reg32 *regs)
-{
- int i;
- struct trapframe *tf;
-
- tf = td->td_frame;
- for (i = 0; i < 13; i++)
- regs->r[i] = tf->tf_x[i];
- /* For arm32, SP is r13 and LR is r14 */
- regs->r_sp = tf->tf_x[13];
- regs->r_lr = tf->tf_x[14];
- regs->r_pc = tf->tf_elr;
- regs->r_cpsr = tf->tf_spsr;
-
- return (0);
-}
-
-int
-set_regs32(struct thread *td, struct reg32 *regs)
-{
- int i;
- struct trapframe *tf;
-
- tf = td->td_frame;
- for (i = 0; i < 13; i++)
- tf->tf_x[i] = regs->r[i];
- /* For arm 32, SP is r13 an LR is r14 */
- tf->tf_x[13] = regs->r_sp;
- tf->tf_x[14] = regs->r_lr;
- tf->tf_elr = regs->r_pc;
- tf->tf_spsr &= ~PSR_FLAGS;
- tf->tf_spsr |= regs->r_cpsr & PSR_FLAGS;
-
- return (0);
-}
-
-/* XXX fill/set dbregs/fpregs are stubbed on 32-bit arm. */
-int
-fill_fpregs32(struct thread *td, struct fpreg32 *regs)
-{
-
- memset(regs, 0, sizeof(*regs));
- return (0);
-}
-
-int
-set_fpregs32(struct thread *td, struct fpreg32 *regs)
-{
-
- return (0);
-}
-
-int
-fill_dbregs32(struct thread *td, struct dbreg32 *regs)
-{
-
- memset(regs, 0, sizeof(*regs));
- return (0);
-}
-
-int
-set_dbregs32(struct thread *td, struct dbreg32 *regs)
-{
-
- return (0);
-}
-#endif
-
-int
-ptrace_set_pc(struct thread *td, u_long addr)
-{
-
- td->td_frame->tf_elr = addr;
- return (0);
-}
-
-int
-ptrace_single_step(struct thread *td)
-{
-
- td->td_frame->tf_spsr |= PSR_SS;
- td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
- return (0);
-}
-
-int
-ptrace_clear_single_step(struct thread *td)
-{
-
- td->td_frame->tf_spsr &= ~PSR_SS;
- td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
- return (0);
-}
-
-void
-exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
-{
- struct trapframe *tf = td->td_frame;
- struct pcb *pcb = td->td_pcb;
-
- memset(tf, 0, sizeof(struct trapframe));
-
- tf->tf_x[0] = stack;
- tf->tf_sp = STACKALIGN(stack);
- tf->tf_lr = imgp->entry_addr;
- tf->tf_elr = imgp->entry_addr;
-
- td->td_pcb->pcb_tpidr_el0 = 0;
- td->td_pcb->pcb_tpidrro_el0 = 0;
- WRITE_SPECIALREG(tpidrro_el0, 0);
- WRITE_SPECIALREG(tpidr_el0, 0);
-
-#ifdef VFP
- vfp_reset_state(td, pcb);
-#endif
-
- /*
- * Clear debug register state. It is not applicable to the new process.
- */
- bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
-}
-
-/* Sanity check these are the same size, they will be memcpy'd to and fro */
-CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
- sizeof((struct gpregs *)0)->gp_x);
-CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
- sizeof((struct reg *)0)->x);
-
-int
-get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
-{
- struct trapframe *tf = td->td_frame;
-
- if (clear_ret & GET_MC_CLEAR_RET) {
- mcp->mc_gpregs.gp_x[0] = 0;
- mcp->mc_gpregs.gp_spsr = tf->tf_spsr & ~PSR_C;
- } else {
- mcp->mc_gpregs.gp_x[0] = tf->tf_x[0];
- mcp->mc_gpregs.gp_spsr = tf->tf_spsr;
- }
-
- memcpy(&mcp->mc_gpregs.gp_x[1], &tf->tf_x[1],
- sizeof(mcp->mc_gpregs.gp_x[1]) * (nitems(mcp->mc_gpregs.gp_x) - 1));
-
- mcp->mc_gpregs.gp_sp = tf->tf_sp;
- mcp->mc_gpregs.gp_lr = tf->tf_lr;
- mcp->mc_gpregs.gp_elr = tf->tf_elr;
- get_fpcontext(td, mcp);
-
- return (0);
-}
-
-int
-set_mcontext(struct thread *td, mcontext_t *mcp)
-{
- struct trapframe *tf = td->td_frame;
- uint32_t spsr;
-
- spsr = mcp->mc_gpregs.gp_spsr;
- if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
- (spsr & PSR_AARCH32) != 0 ||
- (spsr & PSR_DAIF) != (td->td_frame->tf_spsr & PSR_DAIF))
- return (EINVAL);
-
- memcpy(tf->tf_x, mcp->mc_gpregs.gp_x, sizeof(tf->tf_x));
-
- tf->tf_sp = mcp->mc_gpregs.gp_sp;
- tf->tf_lr = mcp->mc_gpregs.gp_lr;
- tf->tf_elr = mcp->mc_gpregs.gp_elr;
- tf->tf_spsr = mcp->mc_gpregs.gp_spsr;
- set_fpcontext(td, mcp);
-
- return (0);
-}
-
-static void
-get_fpcontext(struct thread *td, mcontext_t *mcp)
-{
-#ifdef VFP
- struct pcb *curpcb;
-
- critical_enter();
-
- curpcb = curthread->td_pcb;
-
- if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
- /*
- * If we have just been running VFP instructions we will
- * need to save the state to memcpy it below.
- */
- vfp_save_state(td, curpcb);
-
- KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
- ("Called get_fpcontext while the kernel is using the VFP"));
- KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
- ("Non-userspace FPU flags set in get_fpcontext"));
- memcpy(mcp->mc_fpregs.fp_q, curpcb->pcb_fpustate.vfp_regs,
- sizeof(mcp->mc_fpregs.fp_q));
- mcp->mc_fpregs.fp_cr = curpcb->pcb_fpustate.vfp_fpcr;
- mcp->mc_fpregs.fp_sr = curpcb->pcb_fpustate.vfp_fpsr;
- mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
- mcp->mc_flags |= _MC_FP_VALID;
- }
-
- critical_exit();
-#endif
-}
-
-static void
-set_fpcontext(struct thread *td, mcontext_t *mcp)
-{
-#ifdef VFP
- struct pcb *curpcb;
-
- critical_enter();
-
- if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
- curpcb = curthread->td_pcb;
-
- /*
- * Discard any vfp state for the current thread, we
- * are about to override it.
- */
- vfp_discard(td);
-
- KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
- ("Called set_fpcontext while the kernel is using the VFP"));
- memcpy(curpcb->pcb_fpustate.vfp_regs, mcp->mc_fpregs.fp_q,
- sizeof(mcp->mc_fpregs.fp_q));
- curpcb->pcb_fpustate.vfp_fpcr = mcp->mc_fpregs.fp_cr;
- curpcb->pcb_fpustate.vfp_fpsr = mcp->mc_fpregs.fp_sr;
- curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
- }
-
- critical_exit();
-#endif
-}
-
void
cpu_idle(int busy)
{
@@ -794,31 +311,6 @@
}
}
-#ifndef _SYS_SYSPROTO_H_
-struct sigreturn_args {
- ucontext_t *ucp;
-};
-#endif
-
-int
-sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
-{
- ucontext_t uc;
- int error;
-
- if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
- return (EFAULT);
-
- error = set_mcontext(td, &uc.uc_mcontext);
- if (error != 0)
- return (error);
-
- /* Restore signal mask. */
- kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
-
- return (EJUSTRETURN);
-}
-
/*
* Construct a PCB from a trapframe. This is called from kdb_trap() where
* we want to start a backtrace from the function that caused us to enter
@@ -839,86 +331,6 @@
pcb->pcb_sp = tf->tf_sp;
}
-void
-sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
-{
- struct thread *td;
- struct proc *p;
- struct trapframe *tf;
- struct sigframe *fp, frame;
- struct sigacts *psp;
- struct sysentvec *sysent;
- int onstack, sig;
-
- 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);
-
- tf = td->td_frame;
- onstack = sigonstack(tf->tf_sp);
-
- CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
- catcher, sig);
-
- /* Allocate and validate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
- td->td_sigstk.ss_size);
-#if defined(COMPAT_43)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
- } else {
- fp = (struct sigframe *)td->td_frame->tf_sp;
- }
-
- /* Make room, keeping the stack aligned */
- fp--;
- fp = (struct sigframe *)STACKALIGN(fp);
-
- /* Fill in the frame to copy out */
- bzero(&frame, sizeof(frame));
- get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
- frame.sf_si = ksi->ksi_info;
- frame.sf_uc.uc_sigmask = *mask;
- frame.sf_uc.uc_stack = td->td_sigstk;
- frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
- (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
- mtx_unlock(&psp->ps_mtx);
- PROC_UNLOCK(td->td_proc);
-
- /* Copy the sigframe out to the user's stack. */
- if (copyout(&frame, fp, sizeof(*fp)) != 0) {
- /* Process has trashed its stack. Kill it. */
- CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- tf->tf_x[0]= sig;
- tf->tf_x[1] = (register_t)&fp->sf_si;
- tf->tf_x[2] = (register_t)&fp->sf_uc;
-
- tf->tf_elr = (register_t)catcher;
- tf->tf_sp = (register_t)fp;
- sysent = p->p_sysent;
- if (sysent->sv_sigcode_base != 0)
- tf->tf_lr = (register_t)sysent->sv_sigcode_base;
- else
- tf->tf_lr = (register_t)(sysent->sv_psstrings -
- *(sysent->sv_szsigcode));
-
- CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
- tf->tf_sp);
-
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-
static void
init_proc0(vm_offset_t kstack)
{
diff --git a/sys/arm64/arm64/ptrace_machdep.c b/sys/arm64/arm64/ptrace_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/arm64/ptrace_machdep.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+#include <sys/rwlock.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+
+#include <machine/armreg.h>
+
+int
+ptrace_set_pc(struct thread *td, u_long addr)
+{
+
+ td->td_frame->tf_elr = addr;
+ return (0);
+}
+
+int
+ptrace_single_step(struct thread *td)
+{
+
+ td->td_frame->tf_spsr |= PSR_SS;
+ td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
+ return (0);
+}
+
+int
+ptrace_clear_single_step(struct thread *td)
+{
+
+ td->td_frame->tf_spsr &= ~PSR_SS;
+ td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
+ return (0);
+}
+
diff --git a/sys/conf/files.arm b/sys/conf/files.arm
--- a/sys/conf/files.arm
+++ b/sys/conf/files.arm
@@ -25,6 +25,7 @@
arm/arm/elf_machdep.c standard
arm/arm/elf_note.S standard
arm/arm/exception.S standard
+arm/arm/exec_machdep.c standard
arm/arm/fiq.c standard
arm/arm/fiq_subr.S standard
arm/arm/fusu.S standard
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -47,6 +47,7 @@
arm64/arm64/elf32_machdep.c optional compat_freebsd32
arm64/arm64/elf_machdep.c standard
arm64/arm64/exception.S standard
+arm64/arm64/exec_machdep.c standard
arm64/arm64/freebsd32_machdep.c optional compat_freebsd32
arm64/arm64/gdb_machdep.c optional gdb
arm64/arm64/gicv3_its.c optional intrng fdt
@@ -66,6 +67,7 @@
arm64/arm64/nexus.c standard
arm64/arm64/ofw_machdep.c optional fdt
arm64/arm64/pmap.c standard
+arm64/arm64/ptrace_machdep.c standard
arm64/arm64/stack_machdep.c optional ddb | stack
arm64/arm64/support.S standard
arm64/arm64/swtch.S standard
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -104,6 +104,7 @@
i386/i386/db_disasm.c optional ddb
i386/i386/db_interface.c optional ddb
i386/i386/db_trace.c optional ddb
+i386/i386/exec_machdep.c standard
i386/i386/elan-mmcr.c optional cpu_elan | cpu_soekris
i386/i386/elf_machdep.c standard
i386/i386/exception.s standard
diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv
--- a/sys/conf/files.riscv
+++ b/sys/conf/files.riscv
@@ -45,6 +45,7 @@
riscv/riscv/dump_machdep.c standard
riscv/riscv/elf_machdep.c standard
riscv/riscv/exception.S standard
+riscv/riscv/exec_machdep.c standard
riscv/riscv/intr_machdep.c standard
riscv/riscv/in_cksum.c optional inet | inet6
riscv/riscv/identcpu.c standard
@@ -57,6 +58,7 @@
riscv/riscv/ofw_machdep.c optional fdt
riscv/riscv/plic.c standard
riscv/riscv/pmap.c standard
+riscv/riscv/ptrace_machdep.c standard
riscv/riscv/riscv_console.c optional rcons
riscv/riscv/riscv_syscon.c optional ext_resources syscon riscv_syscon fdt
riscv/riscv/sbi.c standard
diff --git a/sys/i386/i386/exec_machdep.c b/sys/i386/i386/exec_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/i386/i386/exec_machdep.c
@@ -0,0 +1,1443 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2018 The FreeBSD Foundation
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * 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.
+ *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
+ * 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.
+ *
+ * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_cpu.h"
+#include "opt_ddb.h"
+#include "opt_kstack_pages.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+#include <sys/rwlock.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#ifdef DDB
+#ifndef KDB
+#error KDB must be enabled in order for DDB to work!
+#endif
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/cputypes.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/pcb_ext.h>
+#include <machine/proc.h>
+#include <machine/sigframe.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+#include <machine/trap.h>
+
+static void fpstate_drop(struct thread *td);
+static void get_fpcontext(struct thread *td, mcontext_t *mcp,
+ char *xfpusave, size_t xfpusave_len);
+static int set_fpcontext(struct thread *td, mcontext_t *mcp,
+ char *xfpustate, size_t xfpustate_len);
+#ifdef COMPAT_43
+static void osendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
+#endif
+#ifdef COMPAT_FREEBSD4
+static void freebsd4_sendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
+#endif
+
+extern struct sysentvec elf32_freebsd_sysvec;
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored at top to call routine,
+ * followed by call 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_43
+static void
+osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct osigframe 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_esp);
+
+ /* Allocate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct osigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size - sizeof(struct osigframe));
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ fp = (struct osigframe *)regs->tf_esp - 1;
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
+ bzero(&sf.sf_siginfo, sizeof(sf.sf_siginfo));
+ 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_ahu.sf_action = (__osiginfohandler_t *)catcher;
+ sf.sf_addr = 0;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_arg2 = ksi->ksi_code;
+ sf.sf_addr = (register_t)ksi->ksi_addr;
+ sf.sf_ahu.sf_handler = 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_eax;
+ sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx;
+ sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx;
+ sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx;
+ sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi;
+ sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi;
+ 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 = rgs();
+ sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp;
+
+ /* 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_sp = regs->tf_esp;
+ sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp;
+ sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip;
+ sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags;
+ sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
+ sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
+
+ /*
+ * 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) {
+ /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */
+ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+ struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+
+ sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs;
+ sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs;
+ sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es;
+ sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds;
+
+ if (vm86->vm86_has_vme == 0)
+ sf.sf_siginfo.si_sc.sc_ps =
+ (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+ (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+ /* See sendsig() for comments. */
+ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+ }
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, fp, sizeof(*fp)) != 0) {
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_esp = (int)fp;
+ if (p->p_sysent->sv_sigcode_base != 0) {
+ regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
+ szosigcode;
+ } else {
+ /* a.out sysentvec does not use shared page */
+ regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode;
+ }
+ regs->tf_eflags &= ~(PSL_T | PSL_D);
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ load_gs(_udatasel);
+ regs->tf_ss = _udatasel;
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+#endif /* COMPAT_43 */
+
+#ifdef COMPAT_FREEBSD4
+static void
+freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct sigframe4 sf, *sfp;
+ 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_esp);
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack = td->td_sigstk;
+ sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_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));
+ bzero(sf.sf_uc.uc_mcontext.mc_fpregs,
+ sizeof(sf.sf_uc.uc_mcontext.mc_fpregs));
+ bzero(sf.sf_uc.uc_mcontext.__spare__,
+ sizeof(sf.sf_uc.uc_mcontext.__spare__));
+ bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__));
+
+ /* Allocate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sfp = (struct sigframe4 *)((uintptr_t)td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size - sizeof(struct sigframe4));
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ sfp = (struct sigframe4 *)regs->tf_esp - 1;
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_ucontext = (register_t)&sfp->sf_uc;
+ bzero(&sf.sf_si, sizeof(sf.sf_si));
+ if (SIGISMEMBER(psp->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 = ksi->ksi_code;
+ sf.sf_si.si_addr = ksi->ksi_addr;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_siginfo = ksi->ksi_code;
+ sf.sf_addr = (register_t)ksi->ksi_addr;
+ sf.sf_ahu.sf_handler = catcher;
+ }
+ mtx_unlock(&psp->ps_mtx);
+ 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) {
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_esp = (int)sfp;
+ regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
+ szfreebsd4_sigcode;
+ regs->tf_eflags &= ~(PSL_T | PSL_D);
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_ss = _udatasel;
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+#endif /* COMPAT_FREEBSD4 */
+
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct sigframe sf, *sfp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ char *sp;
+ struct trapframe *regs;
+ struct segment_descriptor *sdp;
+ char *xfpusave;
+ size_t xfpusave_len;
+ 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);
+#ifdef COMPAT_FREEBSD4
+ if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
+ freebsd4_sendsig(catcher, ksi, mask);
+ return;
+ }
+#endif
+#ifdef COMPAT_43
+ if (SIGISMEMBER(psp->ps_osigset, sig)) {
+ osendsig(catcher, ksi, mask);
+ return;
+ }
+#endif
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_esp);
+
+ if (cpu_max_ext_state_size > sizeof(union savefpu) && use_xsave) {
+ xfpusave_len = cpu_max_ext_state_size - sizeof(union savefpu);
+ xfpusave = __builtin_alloca(xfpusave_len);
+ } else {
+ xfpusave_len = 0;
+ xfpusave = NULL;
+ }
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack = td->td_sigstk;
+ sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_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));
+ sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
+ get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
+ fpstate_drop(td);
+ /*
+ * Unconditionally fill the fsbase and gsbase into the mcontext.
+ */
+ sdp = &td->td_pcb->pcb_fsd;
+ sf.sf_uc.uc_mcontext.mc_fsbase = sdp->sd_hibase << 24 |
+ sdp->sd_lobase;
+ sdp = &td->td_pcb->pcb_gsd;
+ sf.sf_uc.uc_mcontext.mc_gsbase = sdp->sd_hibase << 24 |
+ sdp->sd_lobase;
+ bzero(sf.sf_uc.uc_mcontext.mc_spare2,
+ sizeof(sf.sf_uc.uc_mcontext.mc_spare2));
+
+ /* Allocate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ sp = (char *)regs->tf_esp - 128;
+ if (xfpusave != NULL) {
+ sp -= xfpusave_len;
+ sp = (char *)((unsigned int)sp & ~0x3F);
+ sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
+ }
+ sp -= sizeof(struct sigframe);
+
+ /* Align to 16 bytes. */
+ sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_ucontext = (register_t)&sfp->sf_uc;
+ bzero(&sf.sf_si, sizeof(sf.sf_si));
+ if (SIGISMEMBER(psp->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 = ksi->ksi_info;
+ sf.sf_si.si_signo = sig; /* maybe a translated signal */
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_siginfo = ksi->ksi_code;
+ sf.sf_addr = (register_t)ksi->ksi_addr;
+ sf.sf_ahu.sf_handler = catcher;
+ }
+ mtx_unlock(&psp->ps_mtx);
+ 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 ||
+ (xfpusave != NULL && copyout(xfpusave,
+ (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
+ != 0)) {
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_esp = (int)sfp;
+ regs->tf_eip = p->p_sysent->sv_sigcode_base;
+ if (regs->tf_eip == 0)
+ regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode;
+ regs->tf_eflags &= ~(PSL_T | PSL_D);
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_ss = _udatasel;
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+
+/*
+ * 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_43
+int
+osigreturn(struct thread *td, struct osigreturn_args *uap)
+{
+ struct osigcontext sc;
+ struct trapframe *regs;
+ struct osigcontext *scp;
+ int eflags, error;
+ ksiginfo_t ksi;
+
+ regs = td->td_frame;
+ error = copyin(uap->sigcntxp, &sc, sizeof(sc));
+ if (error != 0)
+ return (error);
+ scp = ≻
+ eflags = scp->sc_ps;
+ 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)) {
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_addr = (void *)regs->tf_eip;
+ trapsignal(td, &ksi);
+ }
+
+ 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;
+ }
+ tf->tf_vm86_ds = scp->sc_ds;
+ tf->tf_vm86_es = scp->sc_es;
+ tf->tf_vm86_fs = scp->sc_fs;
+ tf->tf_vm86_gs = scp->sc_gs;
+ tf->tf_ds = _udatasel;
+ tf->tf_es = _udatasel;
+ tf->tf_fs = _udatasel;
+ } else {
+ /*
+ * Don't allow users to change privileged or reserved flags.
+ */
+ if (!EFL_SECURE(eflags, regs->tf_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.
+ */
+ 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_eip;
+ trapsignal(td, &ksi);
+ return (EINVAL);
+ }
+ regs->tf_ds = scp->sc_ds;
+ regs->tf_es = scp->sc_es;
+ regs->tf_fs = scp->sc_fs;
+ }
+
+ /* Restore remaining registers. */
+ regs->tf_eax = scp->sc_eax;
+ regs->tf_ebx = scp->sc_ebx;
+ regs->tf_ecx = scp->sc_ecx;
+ regs->tf_edx = scp->sc_edx;
+ regs->tf_esi = scp->sc_esi;
+ regs->tf_edi = scp->sc_edi;
+ regs->tf_cs = scp->sc_cs;
+ regs->tf_ss = scp->sc_ss;
+ regs->tf_isp = scp->sc_isp;
+ regs->tf_ebp = scp->sc_fp;
+ regs->tf_esp = scp->sc_sp;
+ regs->tf_eip = scp->sc_pc;
+ regs->tf_eflags = eflags;
+
+#if defined(COMPAT_43)
+ if (scp->sc_onstack & 1)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+ kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL,
+ SIGPROCMASK_OLD);
+ return (EJUSTRETURN);
+}
+#endif /* COMPAT_43 */
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
+{
+ struct ucontext4 uc;
+ struct trapframe *regs;
+ struct ucontext4 *ucp;
+ int cs, eflags, error;
+ ksiginfo_t ksi;
+
+ 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)) {
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_addr = (void *)regs->tf_eip;
+ trapsignal(td, &ksi);
+ }
+ 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.
+ */
+ if (!EFL_SECURE(eflags, regs->tf_eflags)) {
+ uprintf(
+ "pid %d (%s): freebsd4_sigreturn eflags = 0x%x\n",
+ td->td_proc->p_pid, td->td_name, 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)) {
+ uprintf("pid %d (%s): freebsd4_sigreturn cs = 0x%x\n",
+ td->td_proc->p_pid, td->td_name, 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_eip;
+ trapsignal(td, &ksi);
+ return (EINVAL);
+ }
+
+ bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
+ }
+
+#if defined(COMPAT_43)
+ if (ucp->uc_mcontext.mc_onstack & 1)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+ kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
+ return (EJUSTRETURN);
+}
+#endif /* COMPAT_FREEBSD4 */
+
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+ ucontext_t uc;
+ struct proc *p;
+ struct trapframe *regs;
+ ucontext_t *ucp;
+ char *xfpustate;
+ size_t xfpustate_len;
+ int cs, eflags, error, ret;
+ ksiginfo_t ksi;
+
+ p = td->td_proc;
+
+ error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+ if (error != 0)
+ return (error);
+ ucp = &uc;
+ if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) {
+ uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid,
+ td->td_name, ucp->uc_mcontext.mc_flags);
+ return (EINVAL);
+ }
+ 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)) {
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_addr = (void *)regs->tf_eip;
+ trapsignal(td, &ksi);
+ }
+
+ 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.
+ */
+ if (!EFL_SECURE(eflags, regs->tf_eflags)) {
+ uprintf("pid %d (%s): sigreturn eflags = 0x%x\n",
+ td->td_proc->p_pid, td->td_name, 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)) {
+ uprintf("pid %d (%s): sigreturn cs = 0x%x\n",
+ td->td_proc->p_pid, td->td_name, 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_eip;
+ trapsignal(td, &ksi);
+ return (EINVAL);
+ }
+
+ if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
+ xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
+ if (xfpustate_len > cpu_max_ext_state_size -
+ sizeof(union savefpu)) {
+ uprintf(
+ "pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
+ p->p_pid, td->td_name, xfpustate_len);
+ return (EINVAL);
+ }
+ xfpustate = __builtin_alloca(xfpustate_len);
+ error = copyin(
+ (const void *)uc.uc_mcontext.mc_xfpustate,
+ xfpustate, xfpustate_len);
+ if (error != 0) {
+ uprintf(
+ "pid %d (%s): sigreturn copying xfpustate failed\n",
+ p->p_pid, td->td_name);
+ return (error);
+ }
+ } else {
+ xfpustate = NULL;
+ xfpustate_len = 0;
+ }
+ ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate,
+ xfpustate_len);
+ if (ret != 0)
+ return (ret);
+ bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
+ }
+
+#if defined(COMPAT_43)
+ if (ucp->uc_mcontext.mc_onstack & 1)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+
+ kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
+ return (EJUSTRETURN);
+}
+
+/*
+ * Reset the hardware debug registers if they were in use.
+ * They won't have any meaning for the newly exec'd process.
+ */
+void
+x86_clear_dbregs(struct pcb *pcb)
+{
+ if ((pcb->pcb_flags & PCB_DBREGS) == 0)
+ return;
+
+ pcb->pcb_dr0 = 0;
+ pcb->pcb_dr1 = 0;
+ pcb->pcb_dr2 = 0;
+ pcb->pcb_dr3 = 0;
+ pcb->pcb_dr6 = 0;
+ pcb->pcb_dr7 = 0;
+
+ if (pcb == curpcb) {
+ /*
+ * Clear the debug registers on the running CPU,
+ * otherwise they will end up affecting the next
+ * process we switch to.
+ */
+ reset_dbregs();
+ }
+ pcb->pcb_flags &= ~PCB_DBREGS;
+}
+
+#ifdef COMPAT_43
+static void
+setup_priv_lcall_gate(struct proc *p)
+{
+ struct i386_ldt_args uap;
+ union descriptor desc;
+ u_int lcall_addr;
+
+ bzero(&uap, sizeof(uap));
+ uap.start = 0;
+ uap.num = 1;
+ lcall_addr = p->p_sysent->sv_psstrings - sz_lcall_tramp;
+ bzero(&desc, sizeof(desc));
+ desc.sd.sd_type = SDT_MEMERA;
+ desc.sd.sd_dpl = SEL_UPL;
+ desc.sd.sd_p = 1;
+ desc.sd.sd_def32 = 1;
+ desc.sd.sd_gran = 1;
+ desc.sd.sd_lolimit = 0xffff;
+ desc.sd.sd_hilimit = 0xf;
+ desc.sd.sd_lobase = lcall_addr;
+ desc.sd.sd_hibase = lcall_addr >> 24;
+ i386_set_ldt(curthread, &uap, &desc);
+}
+#endif
+
+/*
+ * Reset registers to default values on exec.
+ */
+void
+exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
+{
+ struct trapframe *regs;
+ struct pcb *pcb;
+ register_t saved_eflags;
+
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
+ /* Reset pc->pcb_gs and %gs before possibly invalidating it. */
+ pcb->pcb_gs = _udatasel;
+ load_gs(_udatasel);
+
+ mtx_lock_spin(&dt_lock);
+ if (td->td_proc->p_md.md_ldt != NULL)
+ user_ldt_free(td);
+ else
+ mtx_unlock_spin(&dt_lock);
+
+#ifdef COMPAT_43
+ if (td->td_proc->p_sysent->sv_psstrings !=
+ elf32_freebsd_sysvec.sv_psstrings)
+ setup_priv_lcall_gate(td->td_proc);
+#endif
+
+ /*
+ * Reset the fs and gs bases. The values from the old address
+ * space do not make sense for the new program. In particular,
+ * gsbase might be the TLS base for the old program but the new
+ * program has no TLS now.
+ */
+ set_fsbase(td, 0);
+ set_gsbase(td, 0);
+
+ /* Make sure edx is 0x0 on entry. Linux binaries depend on it. */
+ saved_eflags = regs->tf_eflags & PSL_T;
+ bzero((char *)regs, sizeof(struct trapframe));
+ regs->tf_eip = imgp->entry_addr;
+ regs->tf_esp = stack;
+ regs->tf_eflags = PSL_USER | saved_eflags;
+ regs->tf_ss = _udatasel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_cs = _ucodesel;
+
+ /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */
+ regs->tf_ebx = (register_t)imgp->ps_strings;
+
+ x86_clear_dbregs(pcb);
+
+ pcb->pcb_initial_npxcw = __INITIAL_NPXCW__;
+
+ /*
+ * Drop the FP state if we hold it, so that the process gets a
+ * clean FP state if it uses the FPU again.
+ */
+ fpstate_drop(td);
+}
+
+int
+fill_regs(struct thread *td, struct reg *regs)
+{
+ struct pcb *pcb;
+ struct trapframe *tp;
+
+ tp = td->td_frame;
+ pcb = td->td_pcb;
+ regs->r_gs = pcb->pcb_gs;
+ return (fill_frame_regs(tp, regs));
+}
+
+int
+fill_frame_regs(struct trapframe *tp, struct reg *regs)
+{
+
+ regs->r_fs = tp->tf_fs;
+ regs->r_es = tp->tf_es;
+ regs->r_ds = tp->tf_ds;
+ regs->r_edi = tp->tf_edi;
+ regs->r_esi = tp->tf_esi;
+ regs->r_ebp = tp->tf_ebp;
+ regs->r_ebx = tp->tf_ebx;
+ regs->r_edx = tp->tf_edx;
+ regs->r_ecx = tp->tf_ecx;
+ regs->r_eax = tp->tf_eax;
+ regs->r_eip = tp->tf_eip;
+ regs->r_cs = tp->tf_cs;
+ regs->r_eflags = tp->tf_eflags;
+ regs->r_esp = tp->tf_esp;
+ regs->r_ss = tp->tf_ss;
+ regs->r_err = 0;
+ regs->r_trapno = 0;
+ return (0);
+}
+
+int
+set_regs(struct thread *td, struct reg *regs)
+{
+ struct pcb *pcb;
+ struct trapframe *tp;
+
+ tp = td->td_frame;
+ if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) ||
+ !CS_SECURE(regs->r_cs))
+ return (EINVAL);
+ pcb = td->td_pcb;
+ tp->tf_fs = regs->r_fs;
+ tp->tf_es = regs->r_es;
+ tp->tf_ds = regs->r_ds;
+ tp->tf_edi = regs->r_edi;
+ tp->tf_esi = regs->r_esi;
+ tp->tf_ebp = regs->r_ebp;
+ tp->tf_ebx = regs->r_ebx;
+ tp->tf_edx = regs->r_edx;
+ tp->tf_ecx = regs->r_ecx;
+ tp->tf_eax = regs->r_eax;
+ tp->tf_eip = regs->r_eip;
+ tp->tf_cs = regs->r_cs;
+ tp->tf_eflags = regs->r_eflags;
+ tp->tf_esp = regs->r_esp;
+ tp->tf_ss = regs->r_ss;
+ pcb->pcb_gs = regs->r_gs;
+ return (0);
+}
+
+int
+fill_fpregs(struct thread *td, struct fpreg *fpregs)
+{
+
+ KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
+ P_SHOULDSTOP(td->td_proc),
+ ("not suspended thread %p", td));
+ npxgetregs(td);
+ if (cpu_fxsr)
+ npx_fill_fpregs_xmm(&get_pcb_user_save_td(td)->sv_xmm,
+ (struct save87 *)fpregs);
+ else
+ bcopy(&get_pcb_user_save_td(td)->sv_87, fpregs,
+ sizeof(*fpregs));
+ return (0);
+}
+
+int
+set_fpregs(struct thread *td, struct fpreg *fpregs)
+{
+
+ critical_enter();
+ if (cpu_fxsr)
+ npx_set_fpregs_xmm((struct save87 *)fpregs,
+ &get_pcb_user_save_td(td)->sv_xmm);
+ else
+ bcopy(fpregs, &get_pcb_user_save_td(td)->sv_87,
+ sizeof(*fpregs));
+ npxuserinited(td);
+ critical_exit();
+ return (0);
+}
+
+/*
+ * Get machine context.
+ */
+int
+get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
+{
+ struct trapframe *tp;
+ struct segment_descriptor *sdp;
+
+ tp = td->td_frame;
+
+ PROC_LOCK(curthread->td_proc);
+ mcp->mc_onstack = sigonstack(tp->tf_esp);
+ PROC_UNLOCK(curthread->td_proc);
+ mcp->mc_gs = td->td_pcb->pcb_gs;
+ mcp->mc_fs = tp->tf_fs;
+ mcp->mc_es = tp->tf_es;
+ mcp->mc_ds = tp->tf_ds;
+ mcp->mc_edi = tp->tf_edi;
+ mcp->mc_esi = tp->tf_esi;
+ mcp->mc_ebp = tp->tf_ebp;
+ mcp->mc_isp = tp->tf_isp;
+ mcp->mc_eflags = tp->tf_eflags;
+ if (flags & GET_MC_CLEAR_RET) {
+ mcp->mc_eax = 0;
+ mcp->mc_edx = 0;
+ mcp->mc_eflags &= ~PSL_C;
+ } else {
+ mcp->mc_eax = tp->tf_eax;
+ mcp->mc_edx = tp->tf_edx;
+ }
+ mcp->mc_ebx = tp->tf_ebx;
+ mcp->mc_ecx = tp->tf_ecx;
+ mcp->mc_eip = tp->tf_eip;
+ mcp->mc_cs = tp->tf_cs;
+ mcp->mc_esp = tp->tf_esp;
+ mcp->mc_ss = tp->tf_ss;
+ mcp->mc_len = sizeof(*mcp);
+ get_fpcontext(td, mcp, NULL, 0);
+ sdp = &td->td_pcb->pcb_fsd;
+ mcp->mc_fsbase = sdp->sd_hibase << 24 | sdp->sd_lobase;
+ sdp = &td->td_pcb->pcb_gsd;
+ mcp->mc_gsbase = sdp->sd_hibase << 24 | sdp->sd_lobase;
+ mcp->mc_flags = 0;
+ mcp->mc_xfpustate = 0;
+ mcp->mc_xfpustate_len = 0;
+ bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2));
+ return (0);
+}
+
+/*
+ * Set machine context.
+ *
+ * However, we don't set any but the user modifiable flags, and we won't
+ * touch the cs selector.
+ */
+int
+set_mcontext(struct thread *td, mcontext_t *mcp)
+{
+ struct trapframe *tp;
+ char *xfpustate;
+ int eflags, ret;
+
+ tp = td->td_frame;
+ if (mcp->mc_len != sizeof(*mcp) ||
+ (mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
+ return (EINVAL);
+ eflags = (mcp->mc_eflags & PSL_USERCHANGE) |
+ (tp->tf_eflags & ~PSL_USERCHANGE);
+ if (mcp->mc_flags & _MC_HASFPXSTATE) {
+ if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
+ sizeof(union savefpu))
+ return (EINVAL);
+ xfpustate = __builtin_alloca(mcp->mc_xfpustate_len);
+ ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
+ mcp->mc_xfpustate_len);
+ if (ret != 0)
+ return (ret);
+ } else
+ xfpustate = NULL;
+ ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
+ if (ret != 0)
+ return (ret);
+ tp->tf_fs = mcp->mc_fs;
+ tp->tf_es = mcp->mc_es;
+ tp->tf_ds = mcp->mc_ds;
+ tp->tf_edi = mcp->mc_edi;
+ tp->tf_esi = mcp->mc_esi;
+ tp->tf_ebp = mcp->mc_ebp;
+ tp->tf_ebx = mcp->mc_ebx;
+ tp->tf_edx = mcp->mc_edx;
+ tp->tf_ecx = mcp->mc_ecx;
+ tp->tf_eax = mcp->mc_eax;
+ tp->tf_eip = mcp->mc_eip;
+ tp->tf_eflags = eflags;
+ tp->tf_esp = mcp->mc_esp;
+ tp->tf_ss = mcp->mc_ss;
+ td->td_pcb->pcb_gs = mcp->mc_gs;
+ return (0);
+}
+
+static void
+get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
+ size_t xfpusave_len)
+{
+ size_t max_len, len;
+
+ mcp->mc_ownedfp = npxgetregs(td);
+ bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
+ sizeof(mcp->mc_fpstate));
+ mcp->mc_fpformat = npxformat();
+ if (!use_xsave || xfpusave_len == 0)
+ return;
+ max_len = cpu_max_ext_state_size - sizeof(union savefpu);
+ len = xfpusave_len;
+ if (len > max_len) {
+ len = max_len;
+ bzero(xfpusave + max_len, len - max_len);
+ }
+ mcp->mc_flags |= _MC_HASFPXSTATE;
+ mcp->mc_xfpustate_len = len;
+ bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
+}
+
+static int
+set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate,
+ size_t xfpustate_len)
+{
+ int error;
+
+ if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
+ return (0);
+ 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);
+ error = 0;
+ } else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
+ mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
+ error = npxsetregs(td, (union savefpu *)&mcp->mc_fpstate,
+ xfpustate, xfpustate_len);
+ } else
+ return (EINVAL);
+ return (error);
+}
+
+static void
+fpstate_drop(struct thread *td)
+{
+
+ KASSERT(PCB_USER_FPU(td->td_pcb), ("fpstate_drop: kernel-owned fpu"));
+ critical_enter();
+ if (PCPU_GET(fpcurthread) == td)
+ npxdrop();
+ /*
+ * XXX force a full drop of the npx. The above only drops it if we
+ * owned it. npxgetregs() has the same bug in the !cpu_fxsr case.
+ *
+ * XXX I don't much like npxgetregs()'s semantics of doing a full
+ * drop. Dropping only to the pcb matches fnsave's behaviour.
+ * We only need to drop to !PCB_INITDONE in sendsig(). But
+ * sendsig() is the only caller of npxgetregs()... perhaps we just
+ * have too many layers.
+ */
+ curthread->td_pcb->pcb_flags &= ~(PCB_NPXINITDONE |
+ PCB_NPXUSERINITDONE);
+ critical_exit();
+}
+
+int
+fill_dbregs(struct thread *td, struct dbreg *dbregs)
+{
+ struct pcb *pcb;
+
+ if (td == NULL) {
+ dbregs->dr[0] = rdr0();
+ dbregs->dr[1] = rdr1();
+ dbregs->dr[2] = rdr2();
+ dbregs->dr[3] = rdr3();
+ dbregs->dr[6] = rdr6();
+ dbregs->dr[7] = rdr7();
+ } else {
+ pcb = td->td_pcb;
+ dbregs->dr[0] = pcb->pcb_dr0;
+ dbregs->dr[1] = pcb->pcb_dr1;
+ dbregs->dr[2] = pcb->pcb_dr2;
+ dbregs->dr[3] = pcb->pcb_dr3;
+ dbregs->dr[6] = pcb->pcb_dr6;
+ dbregs->dr[7] = pcb->pcb_dr7;
+ }
+ dbregs->dr[4] = 0;
+ dbregs->dr[5] = 0;
+ return (0);
+}
+
+int
+set_dbregs(struct thread *td, struct dbreg *dbregs)
+{
+ struct pcb *pcb;
+ int i;
+
+ if (td == NULL) {
+ load_dr0(dbregs->dr[0]);
+ load_dr1(dbregs->dr[1]);
+ load_dr2(dbregs->dr[2]);
+ load_dr3(dbregs->dr[3]);
+ load_dr6(dbregs->dr[6]);
+ load_dr7(dbregs->dr[7]);
+ } else {
+ /*
+ * Don't let an illegal value for dr7 get set. Specifically,
+ * check for undefined settings. Setting these bit patterns
+ * result in undefined behaviour and can lead to an unexpected
+ * TRCTRAP.
+ */
+ for (i = 0; i < 4; i++) {
+ if (DBREG_DR7_ACCESS(dbregs->dr[7], i) == 0x02)
+ return (EINVAL);
+ if (DBREG_DR7_LEN(dbregs->dr[7], i) == 0x02)
+ return (EINVAL);
+ }
+
+ pcb = td->td_pcb;
+
+ /*
+ * Don't let a process set a breakpoint that is not within the
+ * process's address space. If a process could do this, it
+ * could halt the system by setting a breakpoint in the kernel
+ * (if ddb was enabled). Thus, we need to check to make sure
+ * that no breakpoints are being enabled for addresses outside
+ * process's address space.
+ *
+ * XXX - what about when the watched area of the user's
+ * address space is written into from within the kernel
+ * ... wouldn't that still cause a breakpoint to be generated
+ * from within kernel mode?
+ */
+
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 0)) {
+ /* dr0 is enabled */
+ if (dbregs->dr[0] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 1)) {
+ /* dr1 is enabled */
+ if (dbregs->dr[1] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 2)) {
+ /* dr2 is enabled */
+ if (dbregs->dr[2] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 3)) {
+ /* dr3 is enabled */
+ if (dbregs->dr[3] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+
+ pcb->pcb_dr0 = dbregs->dr[0];
+ pcb->pcb_dr1 = dbregs->dr[1];
+ pcb->pcb_dr2 = dbregs->dr[2];
+ pcb->pcb_dr3 = dbregs->dr[3];
+ pcb->pcb_dr6 = dbregs->dr[6];
+ pcb->pcb_dr7 = dbregs->dr[7];
+
+ pcb->pcb_flags |= PCB_DBREGS;
+ }
+
+ return (0);
+}
+
+/*
+ * Return > 0 if a hardware breakpoint has been hit, and the
+ * breakpoint was in user space. Return 0, otherwise.
+ */
+int
+user_dbreg_trap(register_t dr6)
+{
+ u_int32_t dr7;
+ u_int32_t bp; /* breakpoint bits extracted from dr6 */
+ int nbp; /* number of breakpoints that triggered */
+ caddr_t addr[4]; /* breakpoint addresses */
+ int i;
+
+ bp = dr6 & DBREG_DR6_BMASK;
+ if (bp == 0) {
+ /*
+ * None of the breakpoint bits are set meaning this
+ * trap was not caused by any of the debug registers
+ */
+ return (0);
+ }
+
+ dr7 = rdr7();
+ if ((dr7 & 0x000000ff) == 0) {
+ /*
+ * all GE and LE bits in the dr7 register are zero,
+ * thus the trap couldn't have been caused by the
+ * hardware debug registers
+ */
+ return (0);
+ }
+
+ nbp = 0;
+
+ /*
+ * at least one of the breakpoints were hit, check to see
+ * which ones and if any of them are user space addresses
+ */
+
+ if (bp & 0x01) {
+ addr[nbp++] = (caddr_t)rdr0();
+ }
+ if (bp & 0x02) {
+ addr[nbp++] = (caddr_t)rdr1();
+ }
+ if (bp & 0x04) {
+ addr[nbp++] = (caddr_t)rdr2();
+ }
+ if (bp & 0x08) {
+ addr[nbp++] = (caddr_t)rdr3();
+ }
+
+ for (i = 0; i < nbp; i++) {
+ if (addr[i] < (caddr_t)VM_MAXUSER_ADDRESS) {
+ /*
+ * addr[i] is in user space
+ */
+ return (nbp);
+ }
+ }
+
+ /*
+ * None of the breakpoints are in user space.
+ */
+ return (0);
+}
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -163,11 +163,6 @@
void identify_cpu(void);
static void cpu_startup(void *);
-static void fpstate_drop(struct thread *td);
-static void get_fpcontext(struct thread *td, mcontext_t *mcp,
- char *xfpusave, size_t xfpusave_len);
-static int set_fpcontext(struct thread *td, mcontext_t *mcp,
- char *xfpustate, size_t xfpustate_len);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
/* Intel ICH registers */
@@ -181,13 +176,6 @@
int cold = 1;
-#ifdef COMPAT_43
-static void osendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
-#endif
-#ifdef COMPAT_FREEBSD4
-static void freebsd4_sendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
-#endif
-
long Maxmem = 0;
long realmem = 0;
@@ -304,912 +292,6 @@
cpu_setregs();
}
-/*
- * Send an interrupt to process.
- *
- * Stack is set up to allow sigcode stored
- * at top to call routine, followed by call
- * 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_43
-static void
-osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
-{
- struct osigframe 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_esp);
-
- /* Allocate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- fp = (struct osigframe *)((uintptr_t)td->td_sigstk.ss_sp +
- td->td_sigstk.ss_size - sizeof(struct osigframe));
-#if defined(COMPAT_43)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
- } else
- fp = (struct osigframe *)regs->tf_esp - 1;
-
- /* Build the argument list for the signal handler. */
- sf.sf_signum = sig;
- sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
- bzero(&sf.sf_siginfo, sizeof(sf.sf_siginfo));
- 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_ahu.sf_action = (__osiginfohandler_t *)catcher;
- sf.sf_addr = 0;
- } else {
- /* Old FreeBSD-style arguments. */
- sf.sf_arg2 = ksi->ksi_code;
- sf.sf_addr = (register_t)ksi->ksi_addr;
- sf.sf_ahu.sf_handler = 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_eax;
- sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx;
- sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx;
- sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx;
- sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi;
- sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi;
- 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 = rgs();
- sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp;
-
- /* 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_sp = regs->tf_esp;
- sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp;
- sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip;
- sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags;
- sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
- sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
-
- /*
- * 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) {
- /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */
- struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
- struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
-
- sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs;
- sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs;
- sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es;
- sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds;
-
- if (vm86->vm86_has_vme == 0)
- sf.sf_siginfo.si_sc.sc_ps =
- (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
- (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
-
- /* See sendsig() for comments. */
- tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
- }
-
- /*
- * Copy the sigframe out to the user's stack.
- */
- if (copyout(&sf, fp, sizeof(*fp)) != 0) {
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- regs->tf_esp = (int)fp;
- if (p->p_sysent->sv_sigcode_base != 0) {
- regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
- szosigcode;
- } else {
- /* a.out sysentvec does not use shared page */
- regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode;
- }
- regs->tf_eflags &= ~(PSL_T | PSL_D);
- regs->tf_cs = _ucodesel;
- regs->tf_ds = _udatasel;
- regs->tf_es = _udatasel;
- regs->tf_fs = _udatasel;
- load_gs(_udatasel);
- regs->tf_ss = _udatasel;
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-#endif /* COMPAT_43 */
-
-#ifdef COMPAT_FREEBSD4
-static void
-freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
-{
- struct sigframe4 sf, *sfp;
- 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_esp);
-
- /* Save user context. */
- bzero(&sf, sizeof(sf));
- sf.sf_uc.uc_sigmask = *mask;
- sf.sf_uc.uc_stack = td->td_sigstk;
- sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_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));
- bzero(sf.sf_uc.uc_mcontext.mc_fpregs,
- sizeof(sf.sf_uc.uc_mcontext.mc_fpregs));
- bzero(sf.sf_uc.uc_mcontext.__spare__,
- sizeof(sf.sf_uc.uc_mcontext.__spare__));
- bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__));
-
- /* Allocate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- sfp = (struct sigframe4 *)((uintptr_t)td->td_sigstk.ss_sp +
- td->td_sigstk.ss_size - sizeof(struct sigframe4));
-#if defined(COMPAT_43)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
- } else
- sfp = (struct sigframe4 *)regs->tf_esp - 1;
-
- /* Build the argument list for the signal handler. */
- sf.sf_signum = sig;
- sf.sf_ucontext = (register_t)&sfp->sf_uc;
- bzero(&sf.sf_si, sizeof(sf.sf_si));
- if (SIGISMEMBER(psp->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 = ksi->ksi_code;
- sf.sf_si.si_addr = ksi->ksi_addr;
- } else {
- /* Old FreeBSD-style arguments. */
- sf.sf_siginfo = ksi->ksi_code;
- sf.sf_addr = (register_t)ksi->ksi_addr;
- sf.sf_ahu.sf_handler = catcher;
- }
- mtx_unlock(&psp->ps_mtx);
- 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) {
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- regs->tf_esp = (int)sfp;
- regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
- szfreebsd4_sigcode;
- regs->tf_eflags &= ~(PSL_T | PSL_D);
- regs->tf_cs = _ucodesel;
- regs->tf_ds = _udatasel;
- regs->tf_es = _udatasel;
- regs->tf_fs = _udatasel;
- regs->tf_ss = _udatasel;
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-#endif /* COMPAT_FREEBSD4 */
-
-void
-sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
-{
- struct sigframe sf, *sfp;
- struct proc *p;
- struct thread *td;
- struct sigacts *psp;
- char *sp;
- struct trapframe *regs;
- struct segment_descriptor *sdp;
- char *xfpusave;
- size_t xfpusave_len;
- 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);
-#ifdef COMPAT_FREEBSD4
- if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
- freebsd4_sendsig(catcher, ksi, mask);
- return;
- }
-#endif
-#ifdef COMPAT_43
- if (SIGISMEMBER(psp->ps_osigset, sig)) {
- osendsig(catcher, ksi, mask);
- return;
- }
-#endif
- regs = td->td_frame;
- oonstack = sigonstack(regs->tf_esp);
-
- if (cpu_max_ext_state_size > sizeof(union savefpu) && use_xsave) {
- xfpusave_len = cpu_max_ext_state_size - sizeof(union savefpu);
- xfpusave = __builtin_alloca(xfpusave_len);
- } else {
- xfpusave_len = 0;
- xfpusave = NULL;
- }
-
- /* Save user context. */
- bzero(&sf, sizeof(sf));
- sf.sf_uc.uc_sigmask = *mask;
- sf.sf_uc.uc_stack = td->td_sigstk;
- sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_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));
- sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
- get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
- fpstate_drop(td);
- /*
- * Unconditionally fill the fsbase and gsbase into the mcontext.
- */
- sdp = &td->td_pcb->pcb_fsd;
- sf.sf_uc.uc_mcontext.mc_fsbase = sdp->sd_hibase << 24 |
- sdp->sd_lobase;
- sdp = &td->td_pcb->pcb_gsd;
- sf.sf_uc.uc_mcontext.mc_gsbase = sdp->sd_hibase << 24 |
- sdp->sd_lobase;
- bzero(sf.sf_uc.uc_mcontext.mc_spare2,
- sizeof(sf.sf_uc.uc_mcontext.mc_spare2));
-
- /* Allocate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
-#if defined(COMPAT_43)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
- } else
- sp = (char *)regs->tf_esp - 128;
- if (xfpusave != NULL) {
- sp -= xfpusave_len;
- sp = (char *)((unsigned int)sp & ~0x3F);
- sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
- }
- sp -= sizeof(struct sigframe);
-
- /* Align to 16 bytes. */
- sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
-
- /* Build the argument list for the signal handler. */
- sf.sf_signum = sig;
- sf.sf_ucontext = (register_t)&sfp->sf_uc;
- bzero(&sf.sf_si, sizeof(sf.sf_si));
- if (SIGISMEMBER(psp->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 = ksi->ksi_info;
- sf.sf_si.si_signo = sig; /* maybe a translated signal */
- } else {
- /* Old FreeBSD-style arguments. */
- sf.sf_siginfo = ksi->ksi_code;
- sf.sf_addr = (register_t)ksi->ksi_addr;
- sf.sf_ahu.sf_handler = catcher;
- }
- mtx_unlock(&psp->ps_mtx);
- 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 ||
- (xfpusave != NULL && copyout(xfpusave,
- (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
- != 0)) {
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- regs->tf_esp = (int)sfp;
- regs->tf_eip = p->p_sysent->sv_sigcode_base;
- if (regs->tf_eip == 0)
- regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode;
- regs->tf_eflags &= ~(PSL_T | PSL_D);
- regs->tf_cs = _ucodesel;
- regs->tf_ds = _udatasel;
- regs->tf_es = _udatasel;
- regs->tf_fs = _udatasel;
- regs->tf_ss = _udatasel;
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-
-/*
- * 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.
- *
- * MPSAFE
- */
-#ifdef COMPAT_43
-int
-osigreturn(td, uap)
- struct thread *td;
- struct osigreturn_args /* {
- struct osigcontext *sigcntxp;
- } */ *uap;
-{
- struct osigcontext sc;
- struct trapframe *regs;
- struct osigcontext *scp;
- int eflags, error;
- ksiginfo_t ksi;
-
- regs = td->td_frame;
- error = copyin(uap->sigcntxp, &sc, sizeof(sc));
- if (error != 0)
- return (error);
- scp = ≻
- eflags = scp->sc_ps;
- 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)) {
- ksiginfo_init_trap(&ksi);
- ksi.ksi_signo = SIGBUS;
- ksi.ksi_code = BUS_OBJERR;
- ksi.ksi_addr = (void *)regs->tf_eip;
- trapsignal(td, &ksi);
- }
-
- 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;
- }
- tf->tf_vm86_ds = scp->sc_ds;
- tf->tf_vm86_es = scp->sc_es;
- tf->tf_vm86_fs = scp->sc_fs;
- tf->tf_vm86_gs = scp->sc_gs;
- tf->tf_ds = _udatasel;
- tf->tf_es = _udatasel;
- tf->tf_fs = _udatasel;
- } else {
- /*
- * Don't allow users to change privileged or reserved flags.
- */
- if (!EFL_SECURE(eflags, regs->tf_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.
- */
- 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_eip;
- trapsignal(td, &ksi);
- return (EINVAL);
- }
- regs->tf_ds = scp->sc_ds;
- regs->tf_es = scp->sc_es;
- regs->tf_fs = scp->sc_fs;
- }
-
- /* Restore remaining registers. */
- regs->tf_eax = scp->sc_eax;
- regs->tf_ebx = scp->sc_ebx;
- regs->tf_ecx = scp->sc_ecx;
- regs->tf_edx = scp->sc_edx;
- regs->tf_esi = scp->sc_esi;
- regs->tf_edi = scp->sc_edi;
- regs->tf_cs = scp->sc_cs;
- regs->tf_ss = scp->sc_ss;
- regs->tf_isp = scp->sc_isp;
- regs->tf_ebp = scp->sc_fp;
- regs->tf_esp = scp->sc_sp;
- regs->tf_eip = scp->sc_pc;
- regs->tf_eflags = eflags;
-
-#if defined(COMPAT_43)
- if (scp->sc_onstack & 1)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
- else
- td->td_sigstk.ss_flags &= ~SS_ONSTACK;
-#endif
- kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL,
- SIGPROCMASK_OLD);
- return (EJUSTRETURN);
-}
-#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 trapframe *regs;
- struct ucontext4 *ucp;
- int cs, eflags, error;
- ksiginfo_t ksi;
-
- 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)) {
- ksiginfo_init_trap(&ksi);
- ksi.ksi_signo = SIGBUS;
- ksi.ksi_code = BUS_OBJERR;
- ksi.ksi_addr = (void *)regs->tf_eip;
- trapsignal(td, &ksi);
- }
- 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.
- */
- if (!EFL_SECURE(eflags, regs->tf_eflags)) {
- uprintf("pid %d (%s): freebsd4_sigreturn eflags = 0x%x\n",
- td->td_proc->p_pid, td->td_name, 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)) {
- uprintf("pid %d (%s): freebsd4_sigreturn cs = 0x%x\n",
- td->td_proc->p_pid, td->td_name, 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_eip;
- trapsignal(td, &ksi);
- return (EINVAL);
- }
-
- bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
- }
-
-#if defined(COMPAT_43)
- if (ucp->uc_mcontext.mc_onstack & 1)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
- else
- td->td_sigstk.ss_flags &= ~SS_ONSTACK;
-#endif
- kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
- return (EJUSTRETURN);
-}
-#endif /* COMPAT_FREEBSD4 */
-
-/*
- * MPSAFE
- */
-int
-sys_sigreturn(td, uap)
- struct thread *td;
- struct sigreturn_args /* {
- const struct __ucontext *sigcntxp;
- } */ *uap;
-{
- ucontext_t uc;
- struct proc *p;
- struct trapframe *regs;
- ucontext_t *ucp;
- char *xfpustate;
- size_t xfpustate_len;
- int cs, eflags, error, ret;
- ksiginfo_t ksi;
-
- p = td->td_proc;
-
- error = copyin(uap->sigcntxp, &uc, sizeof(uc));
- if (error != 0)
- return (error);
- ucp = &uc;
- if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) {
- uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid,
- td->td_name, ucp->uc_mcontext.mc_flags);
- return (EINVAL);
- }
- 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)) {
- ksiginfo_init_trap(&ksi);
- ksi.ksi_signo = SIGBUS;
- ksi.ksi_code = BUS_OBJERR;
- ksi.ksi_addr = (void *)regs->tf_eip;
- trapsignal(td, &ksi);
- }
-
- 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.
- */
- if (!EFL_SECURE(eflags, regs->tf_eflags)) {
- uprintf("pid %d (%s): sigreturn eflags = 0x%x\n",
- td->td_proc->p_pid, td->td_name, 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)) {
- uprintf("pid %d (%s): sigreturn cs = 0x%x\n",
- td->td_proc->p_pid, td->td_name, 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_eip;
- trapsignal(td, &ksi);
- return (EINVAL);
- }
-
- if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
- xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
- if (xfpustate_len > cpu_max_ext_state_size -
- sizeof(union savefpu)) {
- uprintf(
- "pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
- p->p_pid, td->td_name, xfpustate_len);
- return (EINVAL);
- }
- xfpustate = __builtin_alloca(xfpustate_len);
- error = copyin((const void *)uc.uc_mcontext.mc_xfpustate,
- xfpustate, xfpustate_len);
- if (error != 0) {
- uprintf(
- "pid %d (%s): sigreturn copying xfpustate failed\n",
- p->p_pid, td->td_name);
- return (error);
- }
- } else {
- xfpustate = NULL;
- xfpustate_len = 0;
- }
- ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate,
- xfpustate_len);
- if (ret != 0)
- return (ret);
- bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
- }
-
-#if defined(COMPAT_43)
- if (ucp->uc_mcontext.mc_onstack & 1)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
- else
- td->td_sigstk.ss_flags &= ~SS_ONSTACK;
-#endif
-
- kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
- return (EJUSTRETURN);
-}
-
-#ifdef COMPAT_43
-static void
-setup_priv_lcall_gate(struct proc *p)
-{
- struct i386_ldt_args uap;
- union descriptor desc;
- u_int lcall_addr;
-
- bzero(&uap, sizeof(uap));
- uap.start = 0;
- uap.num = 1;
- lcall_addr = p->p_sysent->sv_psstrings - sz_lcall_tramp;
- bzero(&desc, sizeof(desc));
- desc.sd.sd_type = SDT_MEMERA;
- desc.sd.sd_dpl = SEL_UPL;
- desc.sd.sd_p = 1;
- desc.sd.sd_def32 = 1;
- desc.sd.sd_gran = 1;
- desc.sd.sd_lolimit = 0xffff;
- desc.sd.sd_hilimit = 0xf;
- desc.sd.sd_lobase = lcall_addr;
- desc.sd.sd_hibase = lcall_addr >> 24;
- i386_set_ldt(curthread, &uap, &desc);
-}
-#endif
-
-/*
- * Reset the hardware debug registers if they were in use.
- * They won't have any meaning for the newly exec'd process.
- */
-void
-x86_clear_dbregs(struct pcb *pcb)
-{
- if ((pcb->pcb_flags & PCB_DBREGS) == 0)
- return;
-
- pcb->pcb_dr0 = 0;
- pcb->pcb_dr1 = 0;
- pcb->pcb_dr2 = 0;
- pcb->pcb_dr3 = 0;
- pcb->pcb_dr6 = 0;
- pcb->pcb_dr7 = 0;
-
- if (pcb == curpcb) {
- /*
- * Clear the debug registers on the running CPU,
- * otherwise they will end up affecting the next
- * process we switch to.
- */
- reset_dbregs();
- }
- pcb->pcb_flags &= ~PCB_DBREGS;
-}
-
-/*
- * Reset registers to default values on exec.
- */
-void
-exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
-{
- struct trapframe *regs;
- struct pcb *pcb;
- register_t saved_eflags;
-
- regs = td->td_frame;
- pcb = td->td_pcb;
-
- /* Reset pc->pcb_gs and %gs before possibly invalidating it. */
- pcb->pcb_gs = _udatasel;
- load_gs(_udatasel);
-
- mtx_lock_spin(&dt_lock);
- if (td->td_proc->p_md.md_ldt != NULL)
- user_ldt_free(td);
- else
- mtx_unlock_spin(&dt_lock);
-
-#ifdef COMPAT_43
- if (td->td_proc->p_sysent->sv_psstrings !=
- elf32_freebsd_sysvec.sv_psstrings)
- setup_priv_lcall_gate(td->td_proc);
-#endif
-
- /*
- * Reset the fs and gs bases. The values from the old address
- * space do not make sense for the new program. In particular,
- * gsbase might be the TLS base for the old program but the new
- * program has no TLS now.
- */
- set_fsbase(td, 0);
- set_gsbase(td, 0);
-
- /* Make sure edx is 0x0 on entry. Linux binaries depend on it. */
- saved_eflags = regs->tf_eflags & PSL_T;
- bzero((char *)regs, sizeof(struct trapframe));
- regs->tf_eip = imgp->entry_addr;
- regs->tf_esp = stack;
- regs->tf_eflags = PSL_USER | saved_eflags;
- regs->tf_ss = _udatasel;
- regs->tf_ds = _udatasel;
- regs->tf_es = _udatasel;
- regs->tf_fs = _udatasel;
- regs->tf_cs = _ucodesel;
-
- /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */
- regs->tf_ebx = (register_t)imgp->ps_strings;
-
- x86_clear_dbregs(pcb);
-
- pcb->pcb_initial_npxcw = __INITIAL_NPXCW__;
-
- /*
- * Drop the FP state if we hold it, so that the process gets a
- * clean FP state if it uses the FPU again.
- */
- fpstate_drop(td);
-}
-
void
cpu_setregs(void)
{
@@ -2759,479 +1841,6 @@
pcb->pcb_gs = rgs();
}
-int
-ptrace_set_pc(struct thread *td, u_long addr)
-{
-
- td->td_frame->tf_eip = addr;
- return (0);
-}
-
-int
-ptrace_single_step(struct thread *td)
-{
-
- PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
- if ((td->td_frame->tf_eflags & PSL_T) == 0) {
- td->td_frame->tf_eflags |= PSL_T;
- td->td_dbgflags |= TDB_STEP;
- }
- return (0);
-}
-
-int
-ptrace_clear_single_step(struct thread *td)
-{
-
- PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
- td->td_frame->tf_eflags &= ~PSL_T;
- td->td_dbgflags &= ~TDB_STEP;
- return (0);
-}
-
-int
-fill_regs(struct thread *td, struct reg *regs)
-{
- struct pcb *pcb;
- struct trapframe *tp;
-
- tp = td->td_frame;
- pcb = td->td_pcb;
- regs->r_gs = pcb->pcb_gs;
- return (fill_frame_regs(tp, regs));
-}
-
-int
-fill_frame_regs(struct trapframe *tp, struct reg *regs)
-{
-
- regs->r_fs = tp->tf_fs;
- regs->r_es = tp->tf_es;
- regs->r_ds = tp->tf_ds;
- regs->r_edi = tp->tf_edi;
- regs->r_esi = tp->tf_esi;
- regs->r_ebp = tp->tf_ebp;
- regs->r_ebx = tp->tf_ebx;
- regs->r_edx = tp->tf_edx;
- regs->r_ecx = tp->tf_ecx;
- regs->r_eax = tp->tf_eax;
- regs->r_eip = tp->tf_eip;
- regs->r_cs = tp->tf_cs;
- regs->r_eflags = tp->tf_eflags;
- regs->r_esp = tp->tf_esp;
- regs->r_ss = tp->tf_ss;
- regs->r_err = 0;
- regs->r_trapno = 0;
- return (0);
-}
-
-int
-set_regs(struct thread *td, struct reg *regs)
-{
- struct pcb *pcb;
- struct trapframe *tp;
-
- tp = td->td_frame;
- if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) ||
- !CS_SECURE(regs->r_cs))
- return (EINVAL);
- pcb = td->td_pcb;
- tp->tf_fs = regs->r_fs;
- tp->tf_es = regs->r_es;
- tp->tf_ds = regs->r_ds;
- tp->tf_edi = regs->r_edi;
- tp->tf_esi = regs->r_esi;
- tp->tf_ebp = regs->r_ebp;
- tp->tf_ebx = regs->r_ebx;
- tp->tf_edx = regs->r_edx;
- tp->tf_ecx = regs->r_ecx;
- tp->tf_eax = regs->r_eax;
- tp->tf_eip = regs->r_eip;
- tp->tf_cs = regs->r_cs;
- tp->tf_eflags = regs->r_eflags;
- tp->tf_esp = regs->r_esp;
- tp->tf_ss = regs->r_ss;
- pcb->pcb_gs = regs->r_gs;
- return (0);
-}
-
-int
-fill_fpregs(struct thread *td, struct fpreg *fpregs)
-{
-
- KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
- P_SHOULDSTOP(td->td_proc),
- ("not suspended thread %p", td));
- npxgetregs(td);
- if (cpu_fxsr)
- npx_fill_fpregs_xmm(&get_pcb_user_save_td(td)->sv_xmm,
- (struct save87 *)fpregs);
- else
- bcopy(&get_pcb_user_save_td(td)->sv_87, fpregs,
- sizeof(*fpregs));
- return (0);
-}
-
-int
-set_fpregs(struct thread *td, struct fpreg *fpregs)
-{
-
- critical_enter();
- if (cpu_fxsr)
- npx_set_fpregs_xmm((struct save87 *)fpregs,
- &get_pcb_user_save_td(td)->sv_xmm);
- else
- bcopy(fpregs, &get_pcb_user_save_td(td)->sv_87,
- sizeof(*fpregs));
- npxuserinited(td);
- critical_exit();
- return (0);
-}
-
-/*
- * Get machine context.
- */
-int
-get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
-{
- struct trapframe *tp;
- struct segment_descriptor *sdp;
-
- tp = td->td_frame;
-
- PROC_LOCK(curthread->td_proc);
- mcp->mc_onstack = sigonstack(tp->tf_esp);
- PROC_UNLOCK(curthread->td_proc);
- mcp->mc_gs = td->td_pcb->pcb_gs;
- mcp->mc_fs = tp->tf_fs;
- mcp->mc_es = tp->tf_es;
- mcp->mc_ds = tp->tf_ds;
- mcp->mc_edi = tp->tf_edi;
- mcp->mc_esi = tp->tf_esi;
- mcp->mc_ebp = tp->tf_ebp;
- mcp->mc_isp = tp->tf_isp;
- mcp->mc_eflags = tp->tf_eflags;
- if (flags & GET_MC_CLEAR_RET) {
- mcp->mc_eax = 0;
- mcp->mc_edx = 0;
- mcp->mc_eflags &= ~PSL_C;
- } else {
- mcp->mc_eax = tp->tf_eax;
- mcp->mc_edx = tp->tf_edx;
- }
- mcp->mc_ebx = tp->tf_ebx;
- mcp->mc_ecx = tp->tf_ecx;
- mcp->mc_eip = tp->tf_eip;
- mcp->mc_cs = tp->tf_cs;
- mcp->mc_esp = tp->tf_esp;
- mcp->mc_ss = tp->tf_ss;
- mcp->mc_len = sizeof(*mcp);
- get_fpcontext(td, mcp, NULL, 0);
- sdp = &td->td_pcb->pcb_fsd;
- mcp->mc_fsbase = sdp->sd_hibase << 24 | sdp->sd_lobase;
- sdp = &td->td_pcb->pcb_gsd;
- mcp->mc_gsbase = sdp->sd_hibase << 24 | sdp->sd_lobase;
- mcp->mc_flags = 0;
- mcp->mc_xfpustate = 0;
- mcp->mc_xfpustate_len = 0;
- bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2));
- return (0);
-}
-
-/*
- * Set machine context.
- *
- * However, we don't set any but the user modifiable flags, and we won't
- * touch the cs selector.
- */
-int
-set_mcontext(struct thread *td, mcontext_t *mcp)
-{
- struct trapframe *tp;
- char *xfpustate;
- int eflags, ret;
-
- tp = td->td_frame;
- if (mcp->mc_len != sizeof(*mcp) ||
- (mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
- return (EINVAL);
- eflags = (mcp->mc_eflags & PSL_USERCHANGE) |
- (tp->tf_eflags & ~PSL_USERCHANGE);
- if (mcp->mc_flags & _MC_HASFPXSTATE) {
- if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
- sizeof(union savefpu))
- return (EINVAL);
- xfpustate = __builtin_alloca(mcp->mc_xfpustate_len);
- ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
- mcp->mc_xfpustate_len);
- if (ret != 0)
- return (ret);
- } else
- xfpustate = NULL;
- ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
- if (ret != 0)
- return (ret);
- tp->tf_fs = mcp->mc_fs;
- tp->tf_es = mcp->mc_es;
- tp->tf_ds = mcp->mc_ds;
- tp->tf_edi = mcp->mc_edi;
- tp->tf_esi = mcp->mc_esi;
- tp->tf_ebp = mcp->mc_ebp;
- tp->tf_ebx = mcp->mc_ebx;
- tp->tf_edx = mcp->mc_edx;
- tp->tf_ecx = mcp->mc_ecx;
- tp->tf_eax = mcp->mc_eax;
- tp->tf_eip = mcp->mc_eip;
- tp->tf_eflags = eflags;
- tp->tf_esp = mcp->mc_esp;
- tp->tf_ss = mcp->mc_ss;
- td->td_pcb->pcb_gs = mcp->mc_gs;
- return (0);
-}
-
-static void
-get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
- size_t xfpusave_len)
-{
- size_t max_len, len;
-
- mcp->mc_ownedfp = npxgetregs(td);
- bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
- sizeof(mcp->mc_fpstate));
- mcp->mc_fpformat = npxformat();
- if (!use_xsave || xfpusave_len == 0)
- return;
- max_len = cpu_max_ext_state_size - sizeof(union savefpu);
- len = xfpusave_len;
- if (len > max_len) {
- len = max_len;
- bzero(xfpusave + max_len, len - max_len);
- }
- mcp->mc_flags |= _MC_HASFPXSTATE;
- mcp->mc_xfpustate_len = len;
- bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
-}
-
-static int
-set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate,
- size_t xfpustate_len)
-{
- int error;
-
- if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
- return (0);
- 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);
- error = 0;
- } else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
- mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
- error = npxsetregs(td, (union savefpu *)&mcp->mc_fpstate,
- xfpustate, xfpustate_len);
- } else
- return (EINVAL);
- return (error);
-}
-
-static void
-fpstate_drop(struct thread *td)
-{
-
- KASSERT(PCB_USER_FPU(td->td_pcb), ("fpstate_drop: kernel-owned fpu"));
- critical_enter();
- if (PCPU_GET(fpcurthread) == td)
- npxdrop();
- /*
- * XXX force a full drop of the npx. The above only drops it if we
- * owned it. npxgetregs() has the same bug in the !cpu_fxsr case.
- *
- * XXX I don't much like npxgetregs()'s semantics of doing a full
- * drop. Dropping only to the pcb matches fnsave's behaviour.
- * We only need to drop to !PCB_INITDONE in sendsig(). But
- * sendsig() is the only caller of npxgetregs()... perhaps we just
- * have too many layers.
- */
- curthread->td_pcb->pcb_flags &= ~(PCB_NPXINITDONE |
- PCB_NPXUSERINITDONE);
- critical_exit();
-}
-
-int
-fill_dbregs(struct thread *td, struct dbreg *dbregs)
-{
- struct pcb *pcb;
-
- if (td == NULL) {
- dbregs->dr[0] = rdr0();
- dbregs->dr[1] = rdr1();
- dbregs->dr[2] = rdr2();
- dbregs->dr[3] = rdr3();
- dbregs->dr[6] = rdr6();
- dbregs->dr[7] = rdr7();
- } else {
- pcb = td->td_pcb;
- dbregs->dr[0] = pcb->pcb_dr0;
- dbregs->dr[1] = pcb->pcb_dr1;
- dbregs->dr[2] = pcb->pcb_dr2;
- dbregs->dr[3] = pcb->pcb_dr3;
- dbregs->dr[6] = pcb->pcb_dr6;
- dbregs->dr[7] = pcb->pcb_dr7;
- }
- dbregs->dr[4] = 0;
- dbregs->dr[5] = 0;
- return (0);
-}
-
-int
-set_dbregs(struct thread *td, struct dbreg *dbregs)
-{
- struct pcb *pcb;
- int i;
-
- if (td == NULL) {
- load_dr0(dbregs->dr[0]);
- load_dr1(dbregs->dr[1]);
- load_dr2(dbregs->dr[2]);
- load_dr3(dbregs->dr[3]);
- load_dr6(dbregs->dr[6]);
- load_dr7(dbregs->dr[7]);
- } else {
- /*
- * Don't let an illegal value for dr7 get set. Specifically,
- * check for undefined settings. Setting these bit patterns
- * result in undefined behaviour and can lead to an unexpected
- * TRCTRAP.
- */
- for (i = 0; i < 4; i++) {
- if (DBREG_DR7_ACCESS(dbregs->dr[7], i) == 0x02)
- return (EINVAL);
- if (DBREG_DR7_LEN(dbregs->dr[7], i) == 0x02)
- return (EINVAL);
- }
-
- pcb = td->td_pcb;
-
- /*
- * Don't let a process set a breakpoint that is not within the
- * process's address space. If a process could do this, it
- * could halt the system by setting a breakpoint in the kernel
- * (if ddb was enabled). Thus, we need to check to make sure
- * that no breakpoints are being enabled for addresses outside
- * process's address space.
- *
- * XXX - what about when the watched area of the user's
- * address space is written into from within the kernel
- * ... wouldn't that still cause a breakpoint to be generated
- * from within kernel mode?
- */
-
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 0)) {
- /* dr0 is enabled */
- if (dbregs->dr[0] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
-
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 1)) {
- /* dr1 is enabled */
- if (dbregs->dr[1] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
-
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 2)) {
- /* dr2 is enabled */
- if (dbregs->dr[2] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
-
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 3)) {
- /* dr3 is enabled */
- if (dbregs->dr[3] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
-
- pcb->pcb_dr0 = dbregs->dr[0];
- pcb->pcb_dr1 = dbregs->dr[1];
- pcb->pcb_dr2 = dbregs->dr[2];
- pcb->pcb_dr3 = dbregs->dr[3];
- pcb->pcb_dr6 = dbregs->dr[6];
- pcb->pcb_dr7 = dbregs->dr[7];
-
- pcb->pcb_flags |= PCB_DBREGS;
- }
-
- return (0);
-}
-
-/*
- * Return > 0 if a hardware breakpoint has been hit, and the
- * breakpoint was in user space. Return 0, otherwise.
- */
-int
-user_dbreg_trap(register_t dr6)
-{
- u_int32_t dr7;
- u_int32_t bp; /* breakpoint bits extracted from dr6 */
- int nbp; /* number of breakpoints that triggered */
- caddr_t addr[4]; /* breakpoint addresses */
- int i;
-
- bp = dr6 & DBREG_DR6_BMASK;
- if (bp == 0) {
- /*
- * None of the breakpoint bits are set meaning this
- * trap was not caused by any of the debug registers
- */
- return 0;
- }
-
- dr7 = rdr7();
- if ((dr7 & 0x000000ff) == 0) {
- /*
- * all GE and LE bits in the dr7 register are zero,
- * thus the trap couldn't have been caused by the
- * hardware debug registers
- */
- return 0;
- }
-
- nbp = 0;
-
- /*
- * at least one of the breakpoints were hit, check to see
- * which ones and if any of them are user space addresses
- */
-
- if (bp & 0x01) {
- addr[nbp++] = (caddr_t)rdr0();
- }
- if (bp & 0x02) {
- addr[nbp++] = (caddr_t)rdr1();
- }
- if (bp & 0x04) {
- addr[nbp++] = (caddr_t)rdr2();
- }
- if (bp & 0x08) {
- addr[nbp++] = (caddr_t)rdr3();
- }
-
- for (i = 0; i < nbp; i++) {
- if (addr[i] < (caddr_t)VM_MAXUSER_ADDRESS) {
- /*
- * addr[i] is in user space
- */
- return nbp;
- }
- }
-
- /*
- * None of the breakpoints are in user space.
- */
- return 0;
-}
-
#ifdef KDB
/*
diff --git a/sys/i386/i386/ptrace_machdep.c b/sys/i386/i386/ptrace_machdep.c
--- a/sys/i386/i386/ptrace_machdep.c
+++ b/sys/i386/i386/ptrace_machdep.c
@@ -34,7 +34,9 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <machine/frame.h>
@@ -196,3 +198,33 @@
return (error);
}
+
+int
+ptrace_set_pc(struct thread *td, u_long addr)
+{
+
+ td->td_frame->tf_eip = addr;
+ return (0);
+}
+
+int
+ptrace_single_step(struct thread *td)
+{
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
+ if ((td->td_frame->tf_eflags & PSL_T) == 0) {
+ td->td_frame->tf_eflags |= PSL_T;
+ td->td_dbgflags |= TDB_STEP;
+ }
+ return (0);
+}
+
+int
+ptrace_clear_single_step(struct thread *td)
+{
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
+ td->td_frame->tf_eflags &= ~PSL_T;
+ td->td_dbgflags &= ~TDB_STEP;
+ return (0);
+}
diff --git a/sys/riscv/riscv/exec_machdep.c b/sys/riscv/riscv/exec_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/riscv/riscv/exec_machdep.c
@@ -0,0 +1,420 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2015-2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+#include <sys/rwlock.h>
+#include <sys/sched.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+
+#include <machine/cpu.h>
+#include <machine/kdb.h>
+#include <machine/pcb.h>
+#include <machine/pte.h>
+#include <machine/riscvreg.h>
+#include <machine/sbi.h>
+#include <machine/trap.h>
+
+#ifdef FPE
+#include <machine/fpe.h>
+#endif
+
+static void get_fpcontext(struct thread *td, mcontext_t *mcp);
+static void set_fpcontext(struct thread *td, mcontext_t *mcp);
+
+int
+fill_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+ regs->sepc = frame->tf_sepc;
+ regs->sstatus = frame->tf_sstatus;
+ regs->ra = frame->tf_ra;
+ regs->sp = frame->tf_sp;
+ regs->gp = frame->tf_gp;
+ regs->tp = frame->tf_tp;
+
+ memcpy(regs->t, frame->tf_t, sizeof(regs->t));
+ memcpy(regs->s, frame->tf_s, sizeof(regs->s));
+ memcpy(regs->a, frame->tf_a, sizeof(regs->a));
+
+ return (0);
+}
+
+int
+set_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+ frame->tf_sepc = regs->sepc;
+ frame->tf_ra = regs->ra;
+ frame->tf_sp = regs->sp;
+ frame->tf_gp = regs->gp;
+ frame->tf_tp = regs->tp;
+
+ memcpy(frame->tf_t, regs->t, sizeof(frame->tf_t));
+ memcpy(frame->tf_s, regs->s, sizeof(frame->tf_s));
+ memcpy(frame->tf_a, regs->a, sizeof(frame->tf_a));
+
+ return (0);
+}
+
+int
+fill_fpregs(struct thread *td, struct fpreg *regs)
+{
+#ifdef FPE
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+
+ if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running FPE instructions we will
+ * need to save the state to memcpy it below.
+ */
+ if (td == curthread)
+ fpe_state_save(td);
+
+ memcpy(regs->fp_x, pcb->pcb_x, sizeof(regs->fp_x));
+ regs->fp_fcsr = pcb->pcb_fcsr;
+ } else
+#endif
+ memset(regs, 0, sizeof(*regs));
+
+ return (0);
+}
+
+int
+set_fpregs(struct thread *td, struct fpreg *regs)
+{
+#ifdef FPE
+ struct trapframe *frame;
+ struct pcb *pcb;
+
+ frame = td->td_frame;
+ pcb = td->td_pcb;
+
+ memcpy(pcb->pcb_x, regs->fp_x, sizeof(regs->fp_x));
+ pcb->pcb_fcsr = regs->fp_fcsr;
+ pcb->pcb_fpflags |= PCB_FP_STARTED;
+ frame->tf_sstatus &= ~SSTATUS_FS_MASK;
+ frame->tf_sstatus |= SSTATUS_FS_CLEAN;
+#endif
+
+ return (0);
+}
+
+int
+fill_dbregs(struct thread *td, struct dbreg *regs)
+{
+
+ panic("fill_dbregs");
+}
+
+int
+set_dbregs(struct thread *td, struct dbreg *regs)
+{
+
+ panic("set_dbregs");
+}
+
+void
+exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
+{
+ struct trapframe *tf;
+ struct pcb *pcb;
+
+ tf = td->td_frame;
+ pcb = td->td_pcb;
+
+ memset(tf, 0, sizeof(struct trapframe));
+
+ tf->tf_a[0] = stack;
+ tf->tf_sp = STACKALIGN(stack);
+ tf->tf_ra = imgp->entry_addr;
+ tf->tf_sepc = imgp->entry_addr;
+
+ pcb->pcb_fpflags &= ~PCB_FP_STARTED;
+}
+
+/* Sanity check these are the same size, they will be memcpy'd to and from */
+CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
+ sizeof((struct gpregs *)0)->gp_a);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
+ sizeof((struct gpregs *)0)->gp_s);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
+ sizeof((struct gpregs *)0)->gp_t);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
+ sizeof((struct reg *)0)->a);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
+ sizeof((struct reg *)0)->s);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
+ sizeof((struct reg *)0)->t);
+
+int
+get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
+{
+ struct trapframe *tf = td->td_frame;
+
+ memcpy(mcp->mc_gpregs.gp_t, tf->tf_t, sizeof(mcp->mc_gpregs.gp_t));
+ memcpy(mcp->mc_gpregs.gp_s, tf->tf_s, sizeof(mcp->mc_gpregs.gp_s));
+ memcpy(mcp->mc_gpregs.gp_a, tf->tf_a, sizeof(mcp->mc_gpregs.gp_a));
+
+ if (clear_ret & GET_MC_CLEAR_RET) {
+ mcp->mc_gpregs.gp_a[0] = 0;
+ mcp->mc_gpregs.gp_t[0] = 0; /* clear syscall error */
+ }
+
+ mcp->mc_gpregs.gp_ra = tf->tf_ra;
+ mcp->mc_gpregs.gp_sp = tf->tf_sp;
+ mcp->mc_gpregs.gp_gp = tf->tf_gp;
+ mcp->mc_gpregs.gp_tp = tf->tf_tp;
+ mcp->mc_gpregs.gp_sepc = tf->tf_sepc;
+ mcp->mc_gpregs.gp_sstatus = tf->tf_sstatus;
+ get_fpcontext(td, mcp);
+
+ return (0);
+}
+
+int
+set_mcontext(struct thread *td, mcontext_t *mcp)
+{
+ struct trapframe *tf;
+
+ tf = td->td_frame;
+
+ /*
+ * Permit changes to the USTATUS bits of SSTATUS.
+ *
+ * Ignore writes to read-only bits (SD, XS).
+ *
+ * Ignore writes to the FS field as set_fpcontext() will set
+ * it explicitly.
+ */
+ if (((mcp->mc_gpregs.gp_sstatus ^ tf->tf_sstatus) &
+ ~(SSTATUS_SD | SSTATUS_XS_MASK | SSTATUS_FS_MASK | SSTATUS_UPIE |
+ SSTATUS_UIE)) != 0)
+ return (EINVAL);
+
+ memcpy(tf->tf_t, mcp->mc_gpregs.gp_t, sizeof(tf->tf_t));
+ memcpy(tf->tf_s, mcp->mc_gpregs.gp_s, sizeof(tf->tf_s));
+ memcpy(tf->tf_a, mcp->mc_gpregs.gp_a, sizeof(tf->tf_a));
+
+ tf->tf_ra = mcp->mc_gpregs.gp_ra;
+ tf->tf_sp = mcp->mc_gpregs.gp_sp;
+ tf->tf_gp = mcp->mc_gpregs.gp_gp;
+ tf->tf_sepc = mcp->mc_gpregs.gp_sepc;
+ tf->tf_sstatus = mcp->mc_gpregs.gp_sstatus;
+ set_fpcontext(td, mcp);
+
+ return (0);
+}
+
+static void
+get_fpcontext(struct thread *td, mcontext_t *mcp)
+{
+#ifdef FPE
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ curpcb = curthread->td_pcb;
+
+ KASSERT(td->td_pcb == curpcb, ("Invalid fpe pcb"));
+
+ if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running FPE instructions we will
+ * need to save the state to memcpy it below.
+ */
+ fpe_state_save(td);
+
+ KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
+ ("Non-userspace FPE flags set in get_fpcontext"));
+ memcpy(mcp->mc_fpregs.fp_x, curpcb->pcb_x,
+ sizeof(mcp->mc_fpregs.fp_x));
+ mcp->mc_fpregs.fp_fcsr = curpcb->pcb_fcsr;
+ mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
+ mcp->mc_flags |= _MC_FP_VALID;
+ }
+
+ critical_exit();
+#endif
+}
+
+static void
+set_fpcontext(struct thread *td, mcontext_t *mcp)
+{
+#ifdef FPE
+ struct pcb *curpcb;
+#endif
+
+ td->td_frame->tf_sstatus &= ~SSTATUS_FS_MASK;
+ td->td_frame->tf_sstatus |= SSTATUS_FS_OFF;
+
+#ifdef FPE
+ critical_enter();
+
+ if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
+ curpcb = curthread->td_pcb;
+ /* FPE usage is enabled, override registers. */
+ memcpy(curpcb->pcb_x, mcp->mc_fpregs.fp_x,
+ sizeof(mcp->mc_fpregs.fp_x));
+ curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr;
+ curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
+ td->td_frame->tf_sstatus |= SSTATUS_FS_CLEAN;
+ }
+
+ critical_exit();
+#endif
+}
+
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+ ucontext_t uc;
+ int error;
+
+ if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
+ return (EFAULT);
+
+ error = set_mcontext(td, &uc.uc_mcontext);
+ if (error != 0)
+ return (error);
+
+ /* Restore signal mask. */
+ kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
+
+ return (EJUSTRETURN);
+}
+
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct sigframe *fp, frame;
+ struct sysentvec *sysent;
+ struct trapframe *tf;
+ struct sigacts *psp;
+ struct thread *td;
+ struct proc *p;
+ int onstack;
+ int sig;
+
+ 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);
+
+ tf = td->td_frame;
+ onstack = sigonstack(tf->tf_sp);
+
+ CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
+ catcher, sig);
+
+ /* Allocate and validate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size);
+ } else {
+ fp = (struct sigframe *)td->td_frame->tf_sp;
+ }
+
+ /* Make room, keeping the stack aligned */
+ fp--;
+ fp = (struct sigframe *)STACKALIGN(fp);
+
+ /* Fill in the frame to copy out */
+ bzero(&frame, sizeof(frame));
+ get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+ frame.sf_si = ksi->ksi_info;
+ frame.sf_uc.uc_sigmask = *mask;
+ frame.sf_uc.uc_stack = td->td_sigstk;
+ frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
+ (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(td->td_proc);
+
+ /* Copy the sigframe out to the user's stack. */
+ if (copyout(&frame, fp, sizeof(*fp)) != 0) {
+ /* Process has trashed its stack. Kill it. */
+ CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ tf->tf_a[0] = sig;
+ tf->tf_a[1] = (register_t)&fp->sf_si;
+ tf->tf_a[2] = (register_t)&fp->sf_uc;
+
+ tf->tf_sepc = (register_t)catcher;
+ tf->tf_sp = (register_t)fp;
+
+ sysent = p->p_sysent;
+ if (sysent->sv_sigcode_base != 0)
+ tf->tf_ra = (register_t)sysent->sv_sigcode_base;
+ else
+ tf->tf_ra = (register_t)(sysent->sv_psstrings -
+ *(sysent->sv_szsigcode));
+
+ CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_sepc,
+ tf->tf_sp);
+
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c
--- a/sys/riscv/riscv/machdep.c
+++ b/sys/riscv/riscv/machdep.c
@@ -102,9 +102,6 @@
#include <dev/ofw/openfirm.h>
#endif
-static void get_fpcontext(struct thread *td, mcontext_t *mcp);
-static void set_fpcontext(struct thread *td, mcontext_t *mcp);
-
struct pcpu __pcpu[MAXCPU];
static struct trapframe proc0_tf;
@@ -182,282 +179,6 @@
return (0);
}
-int
-fill_regs(struct thread *td, struct reg *regs)
-{
- struct trapframe *frame;
-
- frame = td->td_frame;
- regs->sepc = frame->tf_sepc;
- regs->sstatus = frame->tf_sstatus;
- regs->ra = frame->tf_ra;
- regs->sp = frame->tf_sp;
- regs->gp = frame->tf_gp;
- regs->tp = frame->tf_tp;
-
- memcpy(regs->t, frame->tf_t, sizeof(regs->t));
- memcpy(regs->s, frame->tf_s, sizeof(regs->s));
- memcpy(regs->a, frame->tf_a, sizeof(regs->a));
-
- return (0);
-}
-
-int
-set_regs(struct thread *td, struct reg *regs)
-{
- struct trapframe *frame;
-
- frame = td->td_frame;
- frame->tf_sepc = regs->sepc;
- frame->tf_ra = regs->ra;
- frame->tf_sp = regs->sp;
- frame->tf_gp = regs->gp;
- frame->tf_tp = regs->tp;
-
- memcpy(frame->tf_t, regs->t, sizeof(frame->tf_t));
- memcpy(frame->tf_s, regs->s, sizeof(frame->tf_s));
- memcpy(frame->tf_a, regs->a, sizeof(frame->tf_a));
-
- return (0);
-}
-
-int
-fill_fpregs(struct thread *td, struct fpreg *regs)
-{
-#ifdef FPE
- struct pcb *pcb;
-
- pcb = td->td_pcb;
-
- if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
- /*
- * If we have just been running FPE instructions we will
- * need to save the state to memcpy it below.
- */
- if (td == curthread)
- fpe_state_save(td);
-
- memcpy(regs->fp_x, pcb->pcb_x, sizeof(regs->fp_x));
- regs->fp_fcsr = pcb->pcb_fcsr;
- } else
-#endif
- memset(regs, 0, sizeof(*regs));
-
- return (0);
-}
-
-int
-set_fpregs(struct thread *td, struct fpreg *regs)
-{
-#ifdef FPE
- struct trapframe *frame;
- struct pcb *pcb;
-
- frame = td->td_frame;
- pcb = td->td_pcb;
-
- memcpy(pcb->pcb_x, regs->fp_x, sizeof(regs->fp_x));
- pcb->pcb_fcsr = regs->fp_fcsr;
- pcb->pcb_fpflags |= PCB_FP_STARTED;
- frame->tf_sstatus &= ~SSTATUS_FS_MASK;
- frame->tf_sstatus |= SSTATUS_FS_CLEAN;
-#endif
-
- return (0);
-}
-
-int
-fill_dbregs(struct thread *td, struct dbreg *regs)
-{
-
- panic("fill_dbregs");
-}
-
-int
-set_dbregs(struct thread *td, struct dbreg *regs)
-{
-
- panic("set_dbregs");
-}
-
-int
-ptrace_set_pc(struct thread *td, u_long addr)
-{
-
- td->td_frame->tf_sepc = addr;
- return (0);
-}
-
-int
-ptrace_single_step(struct thread *td)
-{
-
- /* TODO; */
- return (EOPNOTSUPP);
-}
-
-int
-ptrace_clear_single_step(struct thread *td)
-{
-
- /* TODO; */
- return (EOPNOTSUPP);
-}
-
-void
-exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
-{
- struct trapframe *tf;
- struct pcb *pcb;
-
- tf = td->td_frame;
- pcb = td->td_pcb;
-
- memset(tf, 0, sizeof(struct trapframe));
-
- tf->tf_a[0] = stack;
- tf->tf_sp = STACKALIGN(stack);
- tf->tf_ra = imgp->entry_addr;
- tf->tf_sepc = imgp->entry_addr;
-
- pcb->pcb_fpflags &= ~PCB_FP_STARTED;
-}
-
-/* Sanity check these are the same size, they will be memcpy'd to and fro */
-CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
- sizeof((struct gpregs *)0)->gp_a);
-CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
- sizeof((struct gpregs *)0)->gp_s);
-CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
- sizeof((struct gpregs *)0)->gp_t);
-CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
- sizeof((struct reg *)0)->a);
-CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
- sizeof((struct reg *)0)->s);
-CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
- sizeof((struct reg *)0)->t);
-
-/* Support for FDT configurations only. */
-CTASSERT(FDT);
-
-int
-get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
-{
- struct trapframe *tf = td->td_frame;
-
- memcpy(mcp->mc_gpregs.gp_t, tf->tf_t, sizeof(mcp->mc_gpregs.gp_t));
- memcpy(mcp->mc_gpregs.gp_s, tf->tf_s, sizeof(mcp->mc_gpregs.gp_s));
- memcpy(mcp->mc_gpregs.gp_a, tf->tf_a, sizeof(mcp->mc_gpregs.gp_a));
-
- if (clear_ret & GET_MC_CLEAR_RET) {
- mcp->mc_gpregs.gp_a[0] = 0;
- mcp->mc_gpregs.gp_t[0] = 0; /* clear syscall error */
- }
-
- mcp->mc_gpregs.gp_ra = tf->tf_ra;
- mcp->mc_gpregs.gp_sp = tf->tf_sp;
- mcp->mc_gpregs.gp_gp = tf->tf_gp;
- mcp->mc_gpregs.gp_tp = tf->tf_tp;
- mcp->mc_gpregs.gp_sepc = tf->tf_sepc;
- mcp->mc_gpregs.gp_sstatus = tf->tf_sstatus;
- get_fpcontext(td, mcp);
-
- return (0);
-}
-
-int
-set_mcontext(struct thread *td, mcontext_t *mcp)
-{
- struct trapframe *tf;
-
- tf = td->td_frame;
-
- /*
- * Permit changes to the USTATUS bits of SSTATUS.
- *
- * Ignore writes to read-only bits (SD, XS).
- *
- * Ignore writes to the FS field as set_fpcontext() will set
- * it explicitly.
- */
- if (((mcp->mc_gpregs.gp_sstatus ^ tf->tf_sstatus) &
- ~(SSTATUS_SD | SSTATUS_XS_MASK | SSTATUS_FS_MASK | SSTATUS_UPIE |
- SSTATUS_UIE)) != 0)
- return (EINVAL);
-
- memcpy(tf->tf_t, mcp->mc_gpregs.gp_t, sizeof(tf->tf_t));
- memcpy(tf->tf_s, mcp->mc_gpregs.gp_s, sizeof(tf->tf_s));
- memcpy(tf->tf_a, mcp->mc_gpregs.gp_a, sizeof(tf->tf_a));
-
- tf->tf_ra = mcp->mc_gpregs.gp_ra;
- tf->tf_sp = mcp->mc_gpregs.gp_sp;
- tf->tf_gp = mcp->mc_gpregs.gp_gp;
- tf->tf_sepc = mcp->mc_gpregs.gp_sepc;
- tf->tf_sstatus = mcp->mc_gpregs.gp_sstatus;
- set_fpcontext(td, mcp);
-
- return (0);
-}
-
-static void
-get_fpcontext(struct thread *td, mcontext_t *mcp)
-{
-#ifdef FPE
- struct pcb *curpcb;
-
- critical_enter();
-
- curpcb = curthread->td_pcb;
-
- KASSERT(td->td_pcb == curpcb, ("Invalid fpe pcb"));
-
- if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
- /*
- * If we have just been running FPE instructions we will
- * need to save the state to memcpy it below.
- */
- fpe_state_save(td);
-
- KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
- ("Non-userspace FPE flags set in get_fpcontext"));
- memcpy(mcp->mc_fpregs.fp_x, curpcb->pcb_x,
- sizeof(mcp->mc_fpregs.fp_x));
- mcp->mc_fpregs.fp_fcsr = curpcb->pcb_fcsr;
- mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
- mcp->mc_flags |= _MC_FP_VALID;
- }
-
- critical_exit();
-#endif
-}
-
-static void
-set_fpcontext(struct thread *td, mcontext_t *mcp)
-{
-#ifdef FPE
- struct pcb *curpcb;
-#endif
-
- td->td_frame->tf_sstatus &= ~SSTATUS_FS_MASK;
- td->td_frame->tf_sstatus |= SSTATUS_FS_OFF;
-
-#ifdef FPE
- critical_enter();
-
- if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
- curpcb = curthread->td_pcb;
- /* FPE usage is enabled, override registers. */
- memcpy(curpcb->pcb_x, mcp->mc_fpregs.fp_x,
- sizeof(mcp->mc_fpregs.fp_x));
- curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr;
- curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
- td->td_frame->tf_sstatus |= SSTATUS_FS_CLEAN;
- }
-
- critical_exit();
-#endif
-}
-
void
cpu_idle(int busy)
{
@@ -545,31 +266,6 @@
}
}
-#ifndef _SYS_SYSPROTO_H_
-struct sigreturn_args {
- ucontext_t *ucp;
-};
-#endif
-
-int
-sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
-{
- ucontext_t uc;
- int error;
-
- if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
- return (EFAULT);
-
- error = set_mcontext(td, &uc.uc_mcontext);
- if (error != 0)
- return (error);
-
- /* Restore signal mask. */
- kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
-
- return (EJUSTRETURN);
-}
-
/*
* Construct a PCB from a trapframe. This is called from kdb_trap() where
* we want to start a backtrace from the function that caused us to enter
@@ -589,85 +285,6 @@
pcb->pcb_tp = tf->tf_tp;
}
-void
-sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
-{
- struct sigframe *fp, frame;
- struct sysentvec *sysent;
- struct trapframe *tf;
- struct sigacts *psp;
- struct thread *td;
- struct proc *p;
- int onstack;
- int sig;
-
- 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);
-
- tf = td->td_frame;
- onstack = sigonstack(tf->tf_sp);
-
- CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
- catcher, sig);
-
- /* Allocate and validate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
- td->td_sigstk.ss_size);
- } else {
- fp = (struct sigframe *)td->td_frame->tf_sp;
- }
-
- /* Make room, keeping the stack aligned */
- fp--;
- fp = (struct sigframe *)STACKALIGN(fp);
-
- /* Fill in the frame to copy out */
- bzero(&frame, sizeof(frame));
- get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
- frame.sf_si = ksi->ksi_info;
- frame.sf_uc.uc_sigmask = *mask;
- frame.sf_uc.uc_stack = td->td_sigstk;
- frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
- (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
- mtx_unlock(&psp->ps_mtx);
- PROC_UNLOCK(td->td_proc);
-
- /* Copy the sigframe out to the user's stack. */
- if (copyout(&frame, fp, sizeof(*fp)) != 0) {
- /* Process has trashed its stack. Kill it. */
- CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- tf->tf_a[0] = sig;
- tf->tf_a[1] = (register_t)&fp->sf_si;
- tf->tf_a[2] = (register_t)&fp->sf_uc;
-
- tf->tf_sepc = (register_t)catcher;
- tf->tf_sp = (register_t)fp;
-
- sysent = p->p_sysent;
- if (sysent->sv_sigcode_base != 0)
- tf->tf_ra = (register_t)sysent->sv_sigcode_base;
- else
- tf->tf_ra = (register_t)(sysent->sv_psstrings -
- *(sysent->sv_szsigcode));
-
- CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_sepc,
- tf->tf_sp);
-
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-
static void
init_proc0(vm_offset_t kstack)
{
@@ -803,6 +420,9 @@
rvbp->kern_phys, rvbp->kern_phys + (lastaddr - KERNBASE));
}
+/* Support for FDT configurations only. */
+CTASSERT(FDT);
+
#ifdef FDT
static void
parse_fdt_bootargs(void)
diff --git a/sys/riscv/riscv/ptrace_machdep.c b/sys/riscv/riscv/ptrace_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/riscv/riscv/ptrace_machdep.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2015-2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+#include <sys/rwlock.h>
+#include <sys/sched.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/pte.h>
+#include <machine/riscvreg.h>
+#include <machine/sbi.h>
+#include <machine/trap.h>
+
+int
+ptrace_set_pc(struct thread *td, u_long addr)
+{
+
+ td->td_frame->tf_sepc = addr;
+ return (0);
+}
+
+int
+ptrace_single_step(struct thread *td)
+{
+
+ /* TODO; */
+ return (EOPNOTSUPP);
+}
+
+int
+ptrace_clear_single_step(struct thread *td)
+{
+
+ /* TODO; */
+ return (EOPNOTSUPP);
+}
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 7, 7:20 AM (15 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17027360
Default Alt Text
D32310.id96322.diff (156 KB)
Attached To
Mode
D32310: i386, arm, arm64, riscv: move ABI code from machdep.c to exec_machdep.c
Attached
Detach File
Event Timeline
Log In to Comment