From nobody Sat Oct 16 13:02:52 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id C9ABB180C7A4; Sat, 16 Oct 2021 13:02:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HWjws1ZsKz3Dwr; Sat, 16 Oct 2021 13:02:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 1044D1A713; Sat, 16 Oct 2021 13:02:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 19GD2qDV037161; Sat, 16 Oct 2021 13:02:52 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 19GD2qYF037160; Sat, 16 Oct 2021 13:02:52 GMT (envelope-from git) Date: Sat, 16 Oct 2021 13:02:52 GMT Message-Id: <202110161302.19GD2qYF037160@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Konstantin Belousov Subject: git: d89b4788767f - stable/13 - arm64: move signal delivery code to exec_machdep.c List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kib X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: d89b4788767f57fc07b6e7881bc6103a0ab78b7c Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=d89b4788767f57fc07b6e7881bc6103a0ab78b7c commit d89b4788767f57fc07b6e7881bc6103a0ab78b7c Author: Konstantin Belousov AuthorDate: 2021-10-04 06:55:51 +0000 Commit: Konstantin Belousov CommitDate: 2021-10-16 13:01:47 +0000 arm64: move signal delivery code to exec_machdep.c (cherry picked from commit b4ae6b166066a789641e4a579020ca6b10b40cfa) --- sys/arm64/arm64/exec_machdep.c | 617 +++++++++++++++++++++++++++++++++++++++ sys/arm64/arm64/machdep.c | 588 ------------------------------------- sys/arm64/arm64/ptrace_machdep.c | 74 +++++ sys/conf/files.arm64 | 2 + 4 files changed, 693 insertions(+), 588 deletions(-) diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c new file mode 100644 index 000000000000..cfc288e2b5aa --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef VFP +#include +#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 index eedde49e5de9..529b17772d17 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -100,9 +100,6 @@ __FBSDID("$FreeBSD$"); #include #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 @@ cpu_idle_wakeup(int cpu) 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); -} *** 376 LINES SKIPPED ***