git: 35435ee5725a - stable/13 - arm64: fix hardware single-stepping from EL1
Mitchell Horne
mhorne at FreeBSD.org
Mon Mar 8 14:03:50 UTC 2021
The branch stable/13 has been updated by mhorne:
URL: https://cgit.FreeBSD.org/src/commit/?id=35435ee5725a8c0c67bdb4fd22d18154634dd081
commit 35435ee5725a8c0c67bdb4fd22d18154634dd081
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-08 14:01:32 +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
Sponsored by: The FreeBSD Foundation
(cherry picked from commit 874635e381731e1fbd5e2d0459ca87814f1e455c)
---
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 dcb3645cf5d4..d302c8c95b4f 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 bcb444ef2f55..2af32a185748 100644
--- a/sys/arm64/arm64/exception.S
+++ b/sys/arm64/arm64/exception.S
@@ -76,8 +76,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-all
mailing list