git: 874635e38173 - main - arm64: fix hardware single-stepping from EL1

Mitchell Horne mhorne at FreeBSD.org
Mon Mar 1 14:08:21 UTC 2021


The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=874635e381731e1fbd5e2d0459ca87814f1e455c

commit 874635e381731e1fbd5e2d0459ca87814f1e455c
Author:     Mitchell Horne <mhorne at FreeBSD.org>
AuthorDate: 2021-03-01 13:59:25 +0000
Commit:     Mitchell Horne <mhorne at FreeBSD.org>
CommitDate: 2021-03-01 14:04:22 +0000

    arm64: fix hardware single-stepping from EL1
    
    The main issue is that debug exceptions must to be disabled for the
    entire duration that SS bit in MDSCR_EL1 is set. Otherwise, a
    single-step exception will be generated immediately. This can occur
    before returning from the debugger (when MDSCR is written to) or before
    re-entering it after the single-step (when debug exceptions are unmasked
    in the exception handler).
    
    Solve this by delaying the unmask to C code for EL1, and avoid unmasking
    at all while handling debug exceptions, thus avoiding any recursive
    debug traps.
    
    Reviewed by:    markj, jhb
    MFC after:      5 days
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D28944
---
 sys/arm64/arm64/debug_monitor.c | 6 ++++++
 sys/arm64/arm64/exception.S     | 6 +++++-
 sys/arm64/arm64/trap.c          | 8 ++++++++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/sys/arm64/arm64/debug_monitor.c b/sys/arm64/arm64/debug_monitor.c
index eb5d19567697..c6622650f1ad 100644
--- a/sys/arm64/arm64/debug_monitor.c
+++ b/sys/arm64/arm64/debug_monitor.c
@@ -186,6 +186,9 @@ void
 kdb_cpu_set_singlestep(void)
 {
 
+	KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
+	    ("%s: debug exceptions are not masked", __func__));
+
 	kdb_frame->tf_spsr |= DBG_SPSR_SS;
 	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) |
 	    DBG_MDSCR_SS | DBG_MDSCR_KDE);
@@ -205,6 +208,9 @@ void
 kdb_cpu_clear_singlestep(void)
 {
 
+	KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
+	    ("%s: debug exceptions are not masked", __func__));
+
 	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) &
 	    ~(DBG_MDSCR_SS | DBG_MDSCR_KDE));
 
diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S
index 9fe825fd12b5..9a28a5eac022 100644
--- a/sys/arm64/arm64/exception.S
+++ b/sys/arm64/arm64/exception.S
@@ -75,8 +75,12 @@ __FBSDID("$FreeBSD$");
 
 	ldr	x0, [x18, #(PC_CURTHREAD)]
 	bl	dbg_monitor_enter
-.endif
 	msr	daifclr, #8	/* Enable the debug exception */
+.endif
+	/*
+	 * For EL1, debug exceptions are conditionally unmasked in
+	 * do_el1h_sync().
+	 */
 .endm
 
 .macro	restore_registers el
diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index cb3a05ad0163..d793e34a6894 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -377,6 +377,14 @@ do_el1h_sync(struct thread *td, struct trapframe *frame)
 	    "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td,
 	    esr, frame->tf_elr, frame);
 
+	/*
+	 * Enable debug exceptions if we aren't already handling one. They will
+	 * be masked again in the exception handler's epilogue.
+	 */
+	if (exception != EXCP_BRK && exception != EXCP_WATCHPT_EL1 &&
+	    exception != EXCP_SOFTSTP_EL1)
+		dbg_enable();
+
 	switch (exception) {
 	case EXCP_FP_SIMD:
 	case EXCP_TRAP_FP:


More information about the dev-commits-src-main mailing list