diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c --- a/sys/arm64/arm64/exec_machdep.c +++ b/sys/arm64/arm64/exec_machdep.c @@ -97,7 +97,6 @@ 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)); @@ -109,12 +108,27 @@ * it put it. */ frame->tf_elr = regs->x[15]; - frame->tf_spsr |= regs->x[16] & PSR_FLAGS; + frame->tf_spsr &= ~PSR_SETTABLE_32; + frame->tf_spsr |= regs->x[16] & PSR_SETTABLE_32; + /* Don't allow userspace to ask to continue single stepping. + * The SPSR.SS field doesn't exist when the EL1 is AArch32. + * As the SPSR.DIT field has moved in its place don't + * allow userspace to set the SPSR.SS field. + */ } else #endif { frame->tf_elr = regs->elr; - frame->tf_spsr |= regs->spsr & PSR_FLAGS; + frame->tf_spsr &= ~PSR_SETTABLE_64; + frame->tf_spsr |= regs->spsr & PSR_SETTABLE_64; + /* Enable single stepping if userspace asked fot it */ + if ((frame->tf_spsr & PSR_SS) != 0) { + td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; + + WRITE_SPECIALREG(mdscr_el1, + READ_SPECIALREG(mdscr_el1) | MDSCR_SS); + isb(); + } } return (0); } @@ -333,8 +347,8 @@ 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; + tf->tf_spsr &= ~PSR_SETTABLE_32; + tf->tf_spsr |= regs->r_cpsr & PSR_SETTABLE_32; return (0); } @@ -450,6 +464,13 @@ tf->tf_lr = mcp->mc_gpregs.gp_lr; tf->tf_elr = mcp->mc_gpregs.gp_elr; tf->tf_spsr = mcp->mc_gpregs.gp_spsr; + if ((tf->tf_spsr & PSR_SS) != 0) { + td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; + + WRITE_SPECIALREG(mdscr_el1, + READ_SPECIALREG(mdscr_el1) | MDSCR_SS); + isb(); + } set_fpcontext(td, mcp); return (0); @@ -604,6 +625,14 @@ tf->tf_sp = (register_t)fp; tf->tf_lr = (register_t)p->p_sysent->sv_sigcode_base; + /* Clear the single step flag while in the signal handler */ + if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) { + td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; + WRITE_SPECIALREG(mdscr_el1, + READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS); + isb(); + } + CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr, tf->tf_sp); diff --git a/sys/arm64/arm64/freebsd32_machdep.c b/sys/arm64/arm64/freebsd32_machdep.c --- a/sys/arm64/arm64/freebsd32_machdep.c +++ b/sys/arm64/arm64/freebsd32_machdep.c @@ -198,14 +198,34 @@ { struct trapframe *tf; mcontext32_vfp_t mc_vfp; + uint32_t spsr; int i; tf = td->td_frame; + spsr = mcp->mc_gregset[16]; + /* + * There is no PSR_SS in the 32-bit kernel so ignore it if it's set + * as we will set it later if needed. + */ + if ((spsr & ~(PSR_SETTABLE_32 | PSR_SS)) != + (tf->tf_spsr & ~(PSR_SETTABLE_32 | PSR_SS))) + return (EINVAL); + + spsr &= PSR_SETTABLE_32; + spsr |= tf->tf_spsr & ~PSR_SETTABLE_32; + + if ((td->td_dbgflags & TDB_STEP) != 0) { + spsr |= PSR_SS; + td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; + WRITE_SPECIALREG(mdscr_el1, + READ_SPECIALREG(mdscr_el1) | MDSCR_SS); + } + for (i = 0; i < 15; i++) tf->tf_x[i] = mcp->mc_gregset[i]; tf->tf_elr = mcp->mc_gregset[15]; - tf->tf_spsr = mcp->mc_gregset[16]; + tf->tf_spsr = spsr; #ifdef VFP if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) { if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp, @@ -404,6 +424,14 @@ else tf->tf_spsr &= ~PSR_T; + /* Clear the single step flag while in the signal handler */ + if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) { + td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; + WRITE_SPECIALREG(mdscr_el1, + READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS); + isb(); + } + CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14], tf->tf_x[13]); diff --git a/sys/arm64/arm64/ptrace_machdep.c b/sys/arm64/arm64/ptrace_machdep.c --- a/sys/arm64/arm64/ptrace_machdep.c +++ b/sys/arm64/arm64/ptrace_machdep.c @@ -59,18 +59,22 @@ int ptrace_single_step(struct thread *td) { - - td->td_frame->tf_spsr |= PSR_SS; - td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; + PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); + if ((td->td_frame->tf_spsr & PSR_SS) == 0) { + td->td_frame->tf_spsr |= PSR_SS; + td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; + 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_spsr &= ~PSR_SS; td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; + td->td_dbgflags &= ~TDB_STEP; return (0); } diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -620,10 +620,14 @@ userret(td, frame); break; case EXCP_SOFTSTP_EL0: - td->td_frame->tf_spsr &= ~PSR_SS; - td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; - WRITE_SPECIALREG(mdscr_el1, - READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS); + PROC_LOCK(td->td_proc); + if ((td->td_dbgflags & TDB_STEP) != 0) { + td->td_frame->tf_spsr &= ~PSR_SS; + td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; + WRITE_SPECIALREG(mdscr_el1, + READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS); + } + PROC_UNLOCK(td->td_proc); call_trapsignal(td, SIGTRAP, TRAP_TRACE, (void *)frame->tf_elr, exception); userret(td, frame); diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h --- a/sys/arm64/include/armreg.h +++ b/sys/arm64/include/armreg.h @@ -1315,6 +1315,9 @@ #define PSR_Z 0x40000000 #define PSR_N 0x80000000 #define PSR_FLAGS 0xf0000000 +/* PSR fields that can be set from 32-bit and 64-bit processes */ +#define PSR_SETTABLE_32 PSR_FLAGS +#define PSR_SETTABLE_64 (PSR_FLAGS | PSR_SS) /* TCR_EL1 - Translation Control Register */ /* Bits 63:59 are reserved */ diff --git a/tests/sys/kern/basic_signal.c b/tests/sys/kern/basic_signal.c --- a/tests/sys/kern/basic_signal.c +++ b/tests/sys/kern/basic_signal.c @@ -10,6 +10,20 @@ #include #include +#if defined(__aarch64__) +#include +#define SET_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_gpregs.gp_spsr |= PSR_SS +#define CLR_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_gpregs.gp_spsr &= ~PSR_SS +#elif defined(__amd64__) +#include +#define SET_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_rflags |= PSL_T +#define CLR_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_rflags &= ~PSL_T +#elif defined(__i386__) +#include +#define SET_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_eflags |= PSL_T +#define CLR_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_eflags &= ~PSL_T +#endif + static volatile sig_atomic_t signal_fired = 0; static void @@ -62,6 +76,55 @@ ATF_CHECK(signal_fired == 3); } +/* + * Check setting the machine dependent single step flag works when supported. + */ +#ifdef SET_TRACE_FLAG +static volatile sig_atomic_t trap_signal_fired = 0; + +static void +trap_sig_handler(int signo, siginfo_t *info __unused, void *_ucp) +{ + ucontext_t *ucp = _ucp; + + if (trap_signal_fired < 9) { + SET_TRACE_FLAG(ucp); + } else { + CLR_TRACE_FLAG(ucp); + } + trap_signal_fired++; +} + +ATF_TC(trap_signal_test); + +ATF_TC_HEAD(trap_signal_test, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Testing signal handler setting the MD single step flag"); +} + +ATF_TC_BODY(trap_signal_test, tc) +{ + /* + * Setup the signal handlers + */ + struct sigaction sa = { + .sa_sigaction = trap_sig_handler, + .sa_flags = SA_SIGINFO, + }; + ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0); + ATF_REQUIRE(sigaction(SIGTRAP, &sa, NULL) == 0); + + /* + * Fire SIGTRAP + */ + ATF_CHECK(trap_signal_fired == 0); + ATF_REQUIRE(raise(SIGTRAP) == 0); + ATF_CHECK(trap_signal_fired == 10); +} +#endif + /* * Special tests for 32-bit arm. We can call thumb code (really just t32) from * normal (a32) mode and vice versa. Likewise, signals can interrupt a T32 @@ -150,6 +213,9 @@ { ATF_TP_ADD_TC(tp, signal_test); +#ifdef SET_TRACE_FLAG + ATF_TP_ADD_TC(tp, trap_signal_test); +#endif #ifdef __arm__ ATF_TP_ADD_TC(tp, signal_test_T32_to_A32); ATF_TP_ADD_TC(tp, signal_test_A32_to_T32);