* [PATCH v4 0/3] Add support for RISC-V Smrnmi extension
@ 2026-03-13 13:39 Nylon Chen
2026-03-13 13:39 ` [PATCH v4 1/3] lib: sbi: Add Smrnmi extension detection Nylon Chen
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Nylon Chen @ 2026-03-13 13:39 UTC (permalink / raw)
To: opensbi
Cc: zong.li, nick.hu, samuel.holland, yongxuan.wang, anup, rkrcmar,
atishp, Nylon Chen
This patch series adds support for the RISC-V Smrnmi (Resumable
Non-Maskable Interrupts) extension to OpenSBI.
1. PATCH 1/3: Add Smrnmi extension detection
- Defines Smrnmi CSR registers (MNSCRATCH, MNEPC, MNCAUSE, MNSTATUS)
- Defines MNSTATUS bit fields (NMIE, MNPV, MNPELP, MNPP)
- Registers the Smrnmi extension in hart extension enumeration
2. PATCH 2/3: Enable Smrnmi extension handler
- Implements rnmi_vector_init() as a static function in sbi_hart.c
- Sets MNSCRATCH to the scratch pointer (same role as MSCRATCH)
- Adds platform operation set_rnmi_trap_vector() for trap vector programming
- Adds suspend/resume support for RNMI CSRs (MNSCRATCH, MNSTATUS)
- Calls rnmi_vector_init() at the end of sbi_hart_init()
- Note: Does not yet enable RNMI; trap vector setup deferred to Patch 3
3. PATCH 3/3: Add common NMI trap handler
- Implements sbi_rnmi_vector assembly entry point in fw_base.S
- Checks MNSTATUS.MNPP to distinguish S/U-mode vs M-mode interrupts
- Uses scratch area for S/U-mode interrupts
- Reuses existing M-mode stack for M-mode interrupts (nested RNMI)
- Implements default sbi_rnmi_trap_handler() in C (marked __attribute__((weak)))
- Completes rnmi_vector_init() with platform hook call and NMIE enablement
Changes in v4:
- Added MNSTATUS.MNPELP bit definition (for Zicfilp extension)
- Made rnmi_vector_init() a static function and removed global declaration
- Moved rnmi_vector_init() call from sbi_init.c to end of sbi_hart_init()
- Changed set_rnmi_trap_vector() parameter type from uintptr_t to unsigned long
- Changed platform hook requirement from "should" to "must" in documentation
- Simplified MNSCRATCH setup: directly use scratch pointer instead of allocating
separate RNMI context (addresses Radim's feedback on stack space)
- Rewrote sbi_rnmi_vector to check MNSTATUS.MNPP and reuse M-mode stack for
nested RNMI (addresses Radim's feedback on M-mode stack reuse)
- Removed RNMI_SAVE_REGS/RNMI_RESTORE_REGS macros in favor of explicit
register save/restore for better control
- Added sbi_rnmi_trap_handler() declaration in sbi_trap.h
- Changed printf format from %016lx to PRILX macro for 32/64-bit compatibility
- Fixed patch structure: Patch 2 now only sets up MNSCRATCH; Patch 3 completes
the initialization with trap vector setup and NMIE enablement (ensures each
patch can be compiled independently)
- Marked sbi_rnmi_trap_handler() as __attribute__((weak)) to allow platform override
Changes in v3:
- Split single patch into three-patch series per Anup's feedback:
* PATCH 1: Add Smrnmi extension detection (without enabling NMI)
* PATCH 2: Enable Smrnmi extension handler
* PATCH 3: Add common NMI trap handler in fw_base.S
- Added platform abstraction via set_rnmi_trap_vector() callback
- Added per-HART RNMI context allocation
- Added suspend/resume support for RNMI CSRs
Changes in v2:
- Remove hart_smrnmi_get_allowed() and use sbi_hart_has_extension() for
Smrnmi detection
Co-developed-by: Zong Li <zong.li@sifive.com>
Signed-off-by: Zong Li <zong.li@sifive.com>
Suggested-by: Nick Hu <nick.hu@sifive.com>
Suggested-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Nylon Chen (3):
lib: sbi: Add Smrnmi extension detection
lib: sbi: Enable Smrnmi extension handler
firmware: fw_base.S: Add common NMI trap handler
firmware/fw_base.S | 141 +++++++++++++++++++++++++++++++++++
include/sbi/riscv_encoding.h | 12 +++
include/sbi/sbi_hart.h | 2 +
include/sbi/sbi_platform.h | 8 ++
include/sbi/sbi_trap.h | 22 +++++-
lib/sbi/sbi_hart.c | 54 +++++++++++++-
lib/sbi/sbi_hsm.c | 14 ++++
lib/sbi/sbi_trap.c | 17 +++++
8 files changed, 267 insertions(+), 3 deletions(-)
--
2.43.7
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 1/3] lib: sbi: Add Smrnmi extension detection
2026-03-13 13:39 [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
@ 2026-03-13 13:39 ` Nylon Chen
2026-03-13 13:39 ` [PATCH v4 2/3] lib: sbi: Enable Smrnmi extension handler Nylon Chen
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Nylon Chen @ 2026-03-13 13:39 UTC (permalink / raw)
To: opensbi
Cc: zong.li, nick.hu, samuel.holland, yongxuan.wang, anup, rkrcmar,
atishp, Nylon Chen
Add detection support for the RISC-V Smrnmi (Resumable Non-Maskable
Interrupts) extension.
Co-developed-by: Zong Li <zong.li@sifive.com>
Signed-off-by: Zong Li <zong.li@sifive.com>
Suggested-by: Nick Hu <nick.hu@sifive.com>
Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
---
include/sbi/riscv_encoding.h | 12 ++++++++++++
include/sbi/sbi_hart.h | 2 ++
lib/sbi/sbi_hart.c | 1 +
3 files changed, 15 insertions(+)
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
index b5a4ce81..386c1720 100644
--- a/include/sbi/riscv_encoding.h
+++ b/include/sbi/riscv_encoding.h
@@ -215,6 +215,12 @@
#endif
+/* Smrnmi extension status bits */
+#define MNSTATUS_NMIE (_UL(0x8))
+#define MNSTATUS_MNPV (_UL(0x80))
+#define MNSTATUS_MNPELP (_UL(0x200))
+#define MNSTATUS_MNPP (_UL(0x1800))
+
#define MHPMEVENT_SSCOF_MASK _ULL(0xFF00000000000000)
#define ENVCFG_STCE (_ULL(1) << 63)
@@ -780,6 +786,12 @@
#define CSR_MVIPH 0x319
#define CSR_MIPH 0x354
+/* Smrnmi extension registers */
+#define CSR_MNSCRATCH 0x740
+#define CSR_MNEPC 0x741
+#define CSR_MNCAUSE 0x742
+#define CSR_MNSTATUS 0x744
+
/* Vector extension registers */
#define CSR_VSTART 0x8
#define CSR_VL 0xc20
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index a788b34c..937cdf29 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -87,6 +87,8 @@ enum sbi_hart_extensions {
SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1,
/** Hart has Xsfcease extension */
SBI_HART_EXT_XSIFIVE_CEASE,
+ /** Hart has Smrnmi extension */
+ SBI_HART_EXT_SMRNMI,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 60e95bca..495ad1d8 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -396,6 +396,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
__SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
__SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1),
__SBI_HART_EXT_DATA(xsfcease, SBI_HART_EXT_XSIFIVE_CEASE),
+ __SBI_HART_EXT_DATA(smrnmi, SBI_HART_EXT_SMRNMI),
};
_Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
--
2.43.7
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 2/3] lib: sbi: Enable Smrnmi extension handler
2026-03-13 13:39 [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
2026-03-13 13:39 ` [PATCH v4 1/3] lib: sbi: Add Smrnmi extension detection Nylon Chen
@ 2026-03-13 13:39 ` Nylon Chen
2026-03-13 13:39 ` [PATCH v4 3/3] firmware: fw_base.S: Add common NMI trap handler Nylon Chen
2026-03-13 16:03 ` [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
3 siblings, 0 replies; 5+ messages in thread
From: Nylon Chen @ 2026-03-13 13:39 UTC (permalink / raw)
To: opensbi
Cc: zong.li, nick.hu, samuel.holland, yongxuan.wang, anup, rkrcmar,
atishp, Nylon Chen
Introduce rnmi_vector_init() which prepares the hart for Smrnmi:
1. Checks if the hart supports Smrnmi extension
2. Writes scratch pointer into MNSCRATCH (same role as MSCRATCH for
the RNMI entry path)
The function is file-static and called at the end of sbi_hart_init()
so every hart (cold and warm) initializes its own RNMI state before
returning to the firmware boot sequence.
Add set_rnmi_trap_vector() to struct sbi_platform_operations:
int (*set_rnmi_trap_vector)(unsigned long handler_addr, bool cold_boot);
Use 'unsigned long' rather than 'uintptr_t' for consistency with the
rest of the platform operations interface. Platforms that support Smrnmi
must implement this; others can leave it NULL.
Add suspend/resume support for RNMI CSRs (MNSCRATCH and MNSTATUS) to
ensure proper state preservation across non-retentive suspend.
Note: This patch does not yet enable RNMI interrupts. The trap vector
setup and MNSTATUS.NMIE enablement will be added in the next patch after
the trap handler is implemented.
Co-developed-by: Zong Li <zong.li@sifive.com>
Signed-off-by: Zong Li <zong.li@sifive.com>
Suggested-by: Nick Hu <nick.hu@sifive.com>
Suggested-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
---
include/sbi/sbi_platform.h | 8 ++++++++
lib/sbi/sbi_hart.c | 27 ++++++++++++++++++++++++++-
lib/sbi/sbi_hsm.c | 14 ++++++++++++++
3 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index e65d9877..555e8b79 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -149,6 +149,14 @@ struct sbi_platform_operations {
unsigned long log2len);
/** platform specific pmp disable on current HART */
void (*pmp_disable)(unsigned int n);
+ /**
+ * Platform-specific helper to program the RNMI trap vector.
+ *
+ * Called from rnmi_vector_init() with the firmware RNMI handler
+ * entry address and the cold_boot flag. Platforms that support
+ * Smrnmi must implement this; others can leave it NULL.
+ */
+ int (*set_rnmi_trap_vector)(unsigned long handler_addr, bool cold_boot);
};
/** Platform default per-HART stack size for exception/interrupt handling */
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 495ad1d8..eca6662f 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -29,6 +29,9 @@ void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
unsigned long hart_features_offset;
+/* Forward declaration */
+static int rnmi_vector_init(struct sbi_scratch *scratch, bool cold_boot);
+
static void mstatus_init(struct sbi_scratch *scratch)
{
int cidx;
@@ -756,7 +759,29 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
if (rc)
return rc;
- return sbi_hart_reinit(scratch);
+ rc = sbi_hart_reinit(scratch);
+ if (rc)
+ return rc;
+
+ return rnmi_vector_init(scratch, cold_boot);
+}
+
+static int rnmi_vector_init(struct sbi_scratch *scratch, bool cold_boot)
+{
+ /* If the hart does not support Smrnmi then nothing to do. */
+ if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMRNMI))
+ return 0;
+
+ /*
+ * Set MNSCRATCH to the scratch pointer (same role as MSCRATCH).
+ * The RNMI handler (to be added in the next patch) will check
+ * MNSTATUS.MNPP to determine whether to use the scratch area
+ * (S/U-mode interrupted) or reuse the existing M-mode stack
+ * (M-mode interrupted).
+ */
+ csr_write(CSR_MNSCRATCH, (unsigned long)scratch);
+
+ return 0;
}
void __attribute__((noreturn)) sbi_hart_hang(void)
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index 0a355f9c..41115080 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -49,6 +49,8 @@ struct sbi_hsm_data {
unsigned long saved_medeleg;
unsigned long saved_mideleg;
u64 saved_menvcfg;
+ unsigned long saved_mnscratch;
+ unsigned long saved_mnstatus;
atomic_t start_ticket;
};
@@ -430,6 +432,12 @@ void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
hdata->saved_mideleg = csr_read(CSR_MIDELEG);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
hdata->saved_menvcfg = csr_read64(CSR_MENVCFG);
+
+ /* Save RNMI CSRs if Smrnmi is supported */
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMRNMI)) {
+ hdata->saved_mnscratch = csr_read(CSR_MNSCRATCH);
+ hdata->saved_mnstatus = csr_read(CSR_MNSTATUS);
+ }
}
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
@@ -443,6 +451,12 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
csr_write(CSR_MEDELEG, hdata->saved_medeleg);
csr_write(CSR_MIE, hdata->saved_mie);
csr_set(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
+
+ /* Restore RNMI CSRs if Smrnmi is supported */
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMRNMI)) {
+ csr_write(CSR_MNSCRATCH, hdata->saved_mnscratch);
+ csr_write(CSR_MNSTATUS, hdata->saved_mnstatus);
+ }
}
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
--
2.43.7
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 3/3] firmware: fw_base.S: Add common NMI trap handler
2026-03-13 13:39 [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
2026-03-13 13:39 ` [PATCH v4 1/3] lib: sbi: Add Smrnmi extension detection Nylon Chen
2026-03-13 13:39 ` [PATCH v4 2/3] lib: sbi: Enable Smrnmi extension handler Nylon Chen
@ 2026-03-13 13:39 ` Nylon Chen
2026-03-13 16:03 ` [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
3 siblings, 0 replies; 5+ messages in thread
From: Nylon Chen @ 2026-03-13 13:39 UTC (permalink / raw)
To: opensbi
Cc: zong.li, nick.hu, samuel.holland, yongxuan.wang, anup, rkrcmar,
atishp, Nylon Chen
Implement the firmware-level RNMI entry point and complete the RNMI
initialization:
fw_base.S - sbi_rnmi_vector assembly entry:
Mirrors the existing _trap_handler pattern. MNSCRATCH holds the
per-hart scratch pointer (set by rnmi_vector_init), so the entry
sequence is structurally identical to _trap_handler:
csrrw sp, MNSCRATCH, sp ; sp=scratch_ptr, MNSCRATCH=original_sp
REG_S t0, TMP0(sp) ; stash t0 in scratch tmp0 slot
check MNSTATUS.MNPP ; same bit layout as MSTATUS.MPP
S/U-mode interrupted:
frame allocated below scratch area (same as _trap_handler_s_mode)
M-mode interrupted:
frame allocated on the existing M-mode stack so no separate RNMI
stack is required (same as _trap_handler_m_mode)
After saving all registers, MNEPC/MNSTATUS are saved into the
standard sbi_trap_regs mepc/mstatus fields so the C handler can
inspect them with the same accessors used for normal traps.
The handler is called as:
sbi_rnmi_trap_handler(regs, mncause)
On return registers are restored and mnret is executed. The mnret
opcode is emitted as a raw .word (0x70200073) because older toolchain
versions do not recognise the mnemonic.
sbi_trap.c - sbi_rnmi_trap_handler default implementation:
Prints mnepc, mncause, and mnstatus, then hangs the hart. This is
the correct behaviour for an unexpected NMI; a platform that can
actually handle and resume from an NMI should override this function.
sbi_trap.h - declarations for sbi_rnmi_vector and sbi_rnmi_trap_handler.
sbi_hart.c - complete rnmi_vector_init():
Adds the platform set_rnmi_trap_vector() call and MNSTATUS.NMIE
enablement that were deferred from the previous patch.
Co-developed-by: Zong Li <zong.li@sifive.com>
Signed-off-by: Zong Li <zong.li@sifive.com>
Suggested-by: Nick Hu <nick.hu@sifive.com>
Suggested-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
---
firmware/fw_base.S | 141 +++++++++++++++++++++++++++++++++++++++++
include/sbi/sbi_trap.h | 22 ++++++-
lib/sbi/sbi_hart.c | 34 ++++++++--
lib/sbi/sbi_trap.c | 17 +++++
4 files changed, 208 insertions(+), 6 deletions(-)
diff --git a/firmware/fw_base.S b/firmware/fw_base.S
index bce9e226..641f314a 100644
--- a/firmware/fw_base.S
+++ b/firmware/fw_base.S
@@ -643,6 +643,147 @@ memcmp:
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0)
.endm
+/* Smrnmi mnret instruction encoding (0x70200073) */
+.macro MNRET
+ .word 0x70200073
+.endm
+
+ .align 4
+ .section .entry, "ax", %progbits
+ .globl sbi_rnmi_vector
+sbi_rnmi_vector:
+ /* Swap SP with MNSCRATCH. After: sp=scratch_ptr, MNSCRATCH=original_sp */
+ csrrw sp, CSR_MNSCRATCH, sp
+
+ /* Save T0 in scratch tmp0 slot */
+ REG_S t0, SBI_SCRATCH_TMP0_OFFSET(sp)
+
+ /* Check MNSTATUS.MNPP to determine interrupted privilege mode */
+ csrr t0, CSR_MNSTATUS
+ srl t0, t0, MSTATUS_MPP_SHIFT
+ and t0, t0, PRV_M
+ xori t0, t0, PRV_M
+ beq t0, zero, _sbi_rnmi_m_mode
+
+ /* Interrupted S/U-mode: use scratch area as exception stack */
+_sbi_rnmi_s_mode:
+ /* Load original SP from MNSCRATCH into T0 */
+ csrr t0, CSR_MNSCRATCH
+ /* Restore MNSCRATCH = scratch_ptr for future RNMI entries */
+ csrw CSR_MNSCRATCH, sp
+ /* Allocate exception frame just below scratch area */
+ addi sp, sp, -(SBI_TRAP_REGS_SIZE)
+ j _sbi_rnmi_save_regs
+
+ /* Interrupted M-mode: reuse existing M-mode stack */
+_sbi_rnmi_m_mode:
+ /* Load original SP from MNSCRATCH into T0 */
+ csrr t0, CSR_MNSCRATCH
+ /* Restore MNSCRATCH = scratch_ptr for future RNMI entries */
+ csrw CSR_MNSCRATCH, sp
+ /* Allocate exception frame on the existing M-mode stack */
+ addi sp, t0, -(SBI_TRAP_REGS_SIZE)
+
+_sbi_rnmi_save_regs:
+ /* sp = exception frame, t0 = original SP, MNSCRATCH = scratch_ptr */
+
+ /* Save original SP (from T0) */
+ REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp)
+
+ /* Reload saved T0 from scratch tmp0, then save to exception frame */
+ csrr t0, CSR_MNSCRATCH
+ REG_L t0, SBI_SCRATCH_TMP0_OFFSET(t0)
+ REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
+
+ /* Save all general registers except SP and T0 (already saved) */
+ REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
+ REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
+ REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
+ REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
+ REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
+ REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
+ REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
+ REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
+ REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
+ REG_S a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
+ REG_S a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
+ REG_S a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
+ REG_S a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
+ REG_S a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
+ REG_S a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
+ REG_S a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
+ REG_S s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
+ REG_S s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
+ REG_S s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
+ REG_S s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
+ REG_S s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
+ REG_S s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
+ REG_S s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
+ REG_S s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
+ REG_S s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
+ REG_S s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
+ REG_S t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
+ REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
+ REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
+ REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
+
+ /* Save MNEPC into regs->mepc, MNSTATUS into regs->mstatus */
+ csrr t0, CSR_MNEPC
+ REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
+ csrr t0, CSR_MNSTATUS
+ REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
+
+ /* Call C RNMI handler: a0=regs, a1=mncause */
+ add a0, sp, zero
+ csrr a1, CSR_MNCAUSE
+ call sbi_rnmi_trap_handler
+
+ /* Restore MNEPC and MNSTATUS from exception frame */
+ REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
+ csrw CSR_MNEPC, t0
+ REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
+ csrw CSR_MNSTATUS, t0
+
+ /* Restore all general registers except SP and T0 */
+ REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
+ REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
+ REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
+ REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
+ REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
+ REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
+ REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
+ REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
+ REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
+ REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
+ REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
+ REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
+ REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
+ REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
+ REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
+ REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
+ REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
+ REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
+ REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
+ REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
+ REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
+ REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
+ REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
+ REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
+ REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
+ REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
+ REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
+ REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
+ REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
+
+ /* Restore T0 */
+ REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
+
+ /* Restore SP */
+ REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
+
+ /* Return from RNMI */
+ MNRET
+
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
diff --git a/include/sbi/sbi_trap.h b/include/sbi/sbi_trap.h
index 731a0c98..6a56e64e 100644
--- a/include/sbi/sbi_trap.h
+++ b/include/sbi/sbi_trap.h
@@ -289,6 +289,24 @@ static inline void sbi_trap_set_context(struct sbi_scratch *scratch,
struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx);
-#endif
+/**
+ * Common firmware RNMI trap handler entry in M-mode.
+ *
+ * Platforms program their RNMI trap vector to this address using the
+ * set_rnmi_trap_vector platform operation.
+ */
+void sbi_rnmi_vector(void);
-#endif
+/**
+ * Default RNMI trap handler called from sbi_rnmi_vector.
+ *
+ * This is the default handler for Resumable Non-Maskable Interrupts (RNMI).
+ * It prints diagnostic information and hangs the hart. Platforms that can
+ * handle and resume from an NMI should override this function.
+ */
+void __attribute__((weak)) sbi_rnmi_trap_handler(struct sbi_trap_regs *regs,
+ unsigned long mncause);
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __SBI_TRAP_H__ */
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index eca6662f..519d29a0 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -766,21 +766,47 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
return rnmi_vector_init(scratch, cold_boot);
}
+/* Forward declaration for the RNMI vector entry point in fw_base.S */
+extern void sbi_rnmi_vector(void);
+
static int rnmi_vector_init(struct sbi_scratch *scratch, bool cold_boot)
{
+ int ret;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ const struct sbi_platform_operations *ops =
+ plat ? sbi_platform_ops(plat) : NULL;
+
/* If the hart does not support Smrnmi then nothing to do. */
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMRNMI))
return 0;
+ /* Platform MUST provide RNMI vector hook if hart supports Smrnmi. */
+ if (!ops || !ops->set_rnmi_trap_vector) {
+ sbi_printf("%s: platform does not support Smrnmi\n", __func__);
+ return SBI_ENOTSUPP;
+ }
+
/*
* Set MNSCRATCH to the scratch pointer (same role as MSCRATCH).
- * The RNMI handler (to be added in the next patch) will check
- * MNSTATUS.MNPP to determine whether to use the scratch area
- * (S/U-mode interrupted) or reuse the existing M-mode stack
- * (M-mode interrupted).
+ * The RNMI handler swaps SP/MNSCRATCH on entry, detects the
+ * interrupted mode via MNSTATUS.MNPP, and then either reuses the
+ * existing M-mode stack (M-mode interrupted) or uses the scratch
+ * area as a stack base (S/U-mode interrupted) -- mirroring what
+ * _trap_handler already does for nested M-mode traps.
*/
csr_write(CSR_MNSCRATCH, (unsigned long)scratch);
+ /* Ask the platform to program the RNMI trap vector. */
+ ret = ops->set_rnmi_trap_vector((unsigned long)sbi_rnmi_vector,
+ cold_boot);
+ if (ret == SBI_ENODEV)
+ return 0;
+ if (ret)
+ return ret;
+
+ /* Enable RNMI now that MNSCRATCH and the trap vector are set up. */
+ csr_set(CSR_MNSTATUS, MNSTATUS_NMIE);
+
return 0;
}
diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c
index f41db4d1..38be122a 100644
--- a/lib/sbi/sbi_trap.c
+++ b/lib/sbi/sbi_trap.c
@@ -375,3 +375,20 @@ trap_done:
sbi_trap_set_context(scratch, tcntx->prev_context);
return tcntx;
}
+
+/**
+ * Default RNMI trap handler.
+ *
+ * This is the default handler for Resumable Non-Maskable Interrupts (RNMI).
+ * It is invoked directly from the firmware RNMI entry (rnmi_handler)
+ * and prints diagnostic information before hanging the hart.
+ */
+void __attribute__((weak)) sbi_rnmi_trap_handler(struct sbi_trap_regs *regs,
+ unsigned long mncause)
+{
+ sbi_printf("mnepc = 0x%" PRILX "\n", regs->mepc);
+ sbi_printf("mncause = 0x%" PRILX "\n", mncause);
+ sbi_printf("mnstatus = 0x%" PRILX "\n", regs->mstatus);
+
+ sbi_hart_hang();
+}
--
2.43.7
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v4 0/3] Add support for RISC-V Smrnmi extension
2026-03-13 13:39 [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
` (2 preceding siblings ...)
2026-03-13 13:39 ` [PATCH v4 3/3] firmware: fw_base.S: Add common NMI trap handler Nylon Chen
@ 2026-03-13 16:03 ` Nylon Chen
3 siblings, 0 replies; 5+ messages in thread
From: Nylon Chen @ 2026-03-13 16:03 UTC (permalink / raw)
To: opensbi
Cc: zong.li, nick.hu, samuel.holland, yongxuan.wang, anup, rkrcmar,
atishp, npiggin, Evgeny Voevodin
Sorry, please ignore this v4 series. It was sent before I had fully
reviewed the ongoing discussion, particularly Nick's comments and
Evgeny's Smrnmi series for Ascalon.
I will take time to review their work carefully and send a revised
version that better aligns with the direction of the discussion.
Apologies for the noise.
Thanks,
Nylon
Nylon Chen <nylon.chen@sifive.com> 於 2026年3月13日週五 下午9:39寫道:
>
> This patch series adds support for the RISC-V Smrnmi (Resumable
> Non-Maskable Interrupts) extension to OpenSBI.
>
> 1. PATCH 1/3: Add Smrnmi extension detection
> - Defines Smrnmi CSR registers (MNSCRATCH, MNEPC, MNCAUSE, MNSTATUS)
> - Defines MNSTATUS bit fields (NMIE, MNPV, MNPELP, MNPP)
> - Registers the Smrnmi extension in hart extension enumeration
>
> 2. PATCH 2/3: Enable Smrnmi extension handler
> - Implements rnmi_vector_init() as a static function in sbi_hart.c
> - Sets MNSCRATCH to the scratch pointer (same role as MSCRATCH)
> - Adds platform operation set_rnmi_trap_vector() for trap vector programming
> - Adds suspend/resume support for RNMI CSRs (MNSCRATCH, MNSTATUS)
> - Calls rnmi_vector_init() at the end of sbi_hart_init()
> - Note: Does not yet enable RNMI; trap vector setup deferred to Patch 3
>
> 3. PATCH 3/3: Add common NMI trap handler
> - Implements sbi_rnmi_vector assembly entry point in fw_base.S
> - Checks MNSTATUS.MNPP to distinguish S/U-mode vs M-mode interrupts
> - Uses scratch area for S/U-mode interrupts
> - Reuses existing M-mode stack for M-mode interrupts (nested RNMI)
> - Implements default sbi_rnmi_trap_handler() in C (marked __attribute__((weak)))
> - Completes rnmi_vector_init() with platform hook call and NMIE enablement
>
> Changes in v4:
> - Added MNSTATUS.MNPELP bit definition (for Zicfilp extension)
> - Made rnmi_vector_init() a static function and removed global declaration
> - Moved rnmi_vector_init() call from sbi_init.c to end of sbi_hart_init()
> - Changed set_rnmi_trap_vector() parameter type from uintptr_t to unsigned long
> - Changed platform hook requirement from "should" to "must" in documentation
> - Simplified MNSCRATCH setup: directly use scratch pointer instead of allocating
> separate RNMI context (addresses Radim's feedback on stack space)
> - Rewrote sbi_rnmi_vector to check MNSTATUS.MNPP and reuse M-mode stack for
> nested RNMI (addresses Radim's feedback on M-mode stack reuse)
> - Removed RNMI_SAVE_REGS/RNMI_RESTORE_REGS macros in favor of explicit
> register save/restore for better control
> - Added sbi_rnmi_trap_handler() declaration in sbi_trap.h
> - Changed printf format from %016lx to PRILX macro for 32/64-bit compatibility
> - Fixed patch structure: Patch 2 now only sets up MNSCRATCH; Patch 3 completes
> the initialization with trap vector setup and NMIE enablement (ensures each
> patch can be compiled independently)
> - Marked sbi_rnmi_trap_handler() as __attribute__((weak)) to allow platform override
>
> Changes in v3:
> - Split single patch into three-patch series per Anup's feedback:
> * PATCH 1: Add Smrnmi extension detection (without enabling NMI)
> * PATCH 2: Enable Smrnmi extension handler
> * PATCH 3: Add common NMI trap handler in fw_base.S
> - Added platform abstraction via set_rnmi_trap_vector() callback
> - Added per-HART RNMI context allocation
> - Added suspend/resume support for RNMI CSRs
>
> Changes in v2:
> - Remove hart_smrnmi_get_allowed() and use sbi_hart_has_extension() for
> Smrnmi detection
>
> Co-developed-by: Zong Li <zong.li@sifive.com>
> Signed-off-by: Zong Li <zong.li@sifive.com>
> Suggested-by: Nick Hu <nick.hu@sifive.com>
> Suggested-by: Samuel Holland <samuel.holland@sifive.com>
> Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
>
> Nylon Chen (3):
> lib: sbi: Add Smrnmi extension detection
> lib: sbi: Enable Smrnmi extension handler
> firmware: fw_base.S: Add common NMI trap handler
>
> firmware/fw_base.S | 141 +++++++++++++++++++++++++++++++++++
> include/sbi/riscv_encoding.h | 12 +++
> include/sbi/sbi_hart.h | 2 +
> include/sbi/sbi_platform.h | 8 ++
> include/sbi/sbi_trap.h | 22 +++++-
> lib/sbi/sbi_hart.c | 54 +++++++++++++-
> lib/sbi/sbi_hsm.c | 14 ++++
> lib/sbi/sbi_trap.c | 17 +++++
> 8 files changed, 267 insertions(+), 3 deletions(-)
>
> --
> 2.43.7
>
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-13 16:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-13 13:39 [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
2026-03-13 13:39 ` [PATCH v4 1/3] lib: sbi: Add Smrnmi extension detection Nylon Chen
2026-03-13 13:39 ` [PATCH v4 2/3] lib: sbi: Enable Smrnmi extension handler Nylon Chen
2026-03-13 13:39 ` [PATCH v4 3/3] firmware: fw_base.S: Add common NMI trap handler Nylon Chen
2026-03-13 16:03 ` [PATCH v4 0/3] Add support for RISC-V Smrnmi extension Nylon Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox