[PATCH 2/2] lib: sbi: Fix stale prev_context in RNMI handler
Nia Su
nia.su at sifive.com
Thu Aug 27 23:09:32 PDT 2026
Before an RNMI is taken, an earlier SBI trap may have already used
the same slot on the M-mode exception stack to save its trap context.
When the RNMI later comes in, it reuses that same stack slot for its
own trap context, but sbi_trap_rnmi_handler() never links prev_context
to the previously active trap context, so it still holds the value
left there by that earlier trap context.
sbi_trap_error() then walks this chain with
`for (tc = tcntx; tc; tc = tc->prev_context) depth++;` to count the
depth before printing anything. If this stale prev_context happens
to point back to tcntx itself, the loop never terminates, hanging
the hart before any diagnostics are even printed.
Update sbi_trap_rnmi_handler() so that sbi_scratch points to the
new trap context on entry, and points back to the previous context
on exit, the same way sbi_trap_handler() does. This serves two
purposes: it makes tcntx->prev_context always point to the correct
previous trap context (or NULL when there isn't one) instead of
stale data, fixing the hang described above; and it lets an
exception taken while already inside RNMI handling correctly chain
back to the RNMI's trap context, instead of the RNMI context being
silently dropped from the chain and never printed. Together, these
let sbi_trap_error() print every nested trap context in the chain,
including the RNMI's own state.
Fixes: 8cdb5b1023df ("firmware: Add RNMI handler infrastructure")
Suggested-by: Nick Hu <nick.hu at sifive.com>
Signed-off-by: Nia Su <nia.su at sifive.com>
---
lib/sbi/sbi_trap.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c
index 16774fd2f73059c1268bfb9f43fdf8e9c460c0b6..e694188c25b7b1715df660206af0a501290389fc 100644
--- a/lib/sbi/sbi_trap.c
+++ b/lib/sbi/sbi_trap.c
@@ -394,9 +394,14 @@ trap_done:
struct sbi_trap_context *sbi_trap_rnmi_handler(struct sbi_trap_context *tcntx)
{
int rc;
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
const struct sbi_platform_operations *ops = sbi_platform_ops(plat);
+ /* Update trap context pointer so nested traps chain correctly */
+ tcntx->prev_context = sbi_trap_get_context(scratch);
+ sbi_trap_set_context(scratch, tcntx);
+
/* Call platform-specific NMI handler if registered */
if (ops && ops->rnmi_handler) {
rc = ops->rnmi_handler(tcntx);
@@ -404,14 +409,15 @@ struct sbi_trap_context *sbi_trap_rnmi_handler(struct sbi_trap_context *tcntx)
/* Platform handler failed to handle NMI */
sbi_trap_error("platform NMI handler failed", rc, tcntx);
}
- return tcntx;
+ goto done;
}
/* No platform handler - treat as unhandled NMI */
sbi_trap_error("unhandled NMI (no platform rnmi_handler)",
SBI_ENOTSUPP, tcntx);
- /* Never returns */
+done:
+ sbi_trap_set_context(scratch, tcntx->prev_context);
return tcntx;
}
--
2.43.7
More information about the opensbi
mailing list