[PATCH 2/3] lib: sbi: Enable Smrnmi extension handler
Anup Patel
anup at brainfault.org
Sat Mar 7 20:32:58 PST 2026
On Thu, Jan 29, 2026 at 1:44 PM Nylon Chen <nylon.chen at sifive.com> wrote:
>
> Enable the Smrnmi extension by:
> 1. Adding sbi_rnmi_vector_init() to allocate per-HART RNMI context and enable RNMI via MNSTATUS.NMIE
> 2. Saving and restoring CSR_MNSCRATCH and CSR_MNSTATUS across non-retentive suspend/resume
> 3. Calling sbi_rnmi_vector_init() from the cold and warm init paths
>
> Co-developed-by: Zong Li <zong.li at sifive.com>
> Signed-off-by: Zong Li <zong.li at sifive.com>
> Suggested-by: Nick Hu <nick.hu at sifive.com>
> Suggested-by: Samuel Holland <samuel.holland at sifive.com>
> Signed-off-by: Nylon Chen <nylon.chen at sifive.com>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
> ---
> include/sbi/sbi_hart.h | 1 +
> include/sbi/sbi_platform.h | 9 +++++++++
> lib/sbi/sbi_hart.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> lib/sbi/sbi_hsm.c | 10 ++++++++++
> lib/sbi/sbi_init.c | 8 ++++++++
> 5 files changed, 71 insertions(+)
>
> diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
> index 7d038a18..3e442546 100644
> --- a/include/sbi/sbi_hart.h
> +++ b/include/sbi/sbi_hart.h
> @@ -128,6 +128,7 @@ struct sbi_scratch;
>
> int sbi_hart_reinit(struct sbi_scratch *scratch);
> int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
> +int sbi_rnmi_vector_init(struct sbi_scratch *scratch, bool cold_boot);
No need to make this as global function, see more comments below.
>
> extern void (*sbi_hart_expected_trap)(void);
>
> diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
> index e65d9877..c4f6c456 100644
> --- a/include/sbi/sbi_platform.h
> +++ b/include/sbi/sbi_platform.h
> @@ -149,6 +149,15 @@ 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.
> + *
> + * The core will call this from sbi_rnmi_vector_init() with the
> + * firmware RNMI handler entry address (rnmi_handler) and the
> + * cold_boot flag. Platforms that support Smrnmi should implement
> + * this; others can leave it NULL.
> + */
> + int (*set_rnmi_trap_vector)(uintptr_t handler_addr, bool cold_boot);
To be consistent with other platform operations, use "unsigned long" for
handler_addr instead of "uintptr_t".
> };
>
> /** 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..baebc438 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -28,6 +28,7 @@ extern void __sbi_expected_trap_hext(void);
> void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
>
> unsigned long hart_features_offset;
> +static unsigned long rnmi_context_offset;
>
> static void mstatus_init(struct sbi_scratch *scratch)
> {
> @@ -833,3 +834,45 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
> __asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
> __builtin_unreachable();
> }
> +
> +int sbi_rnmi_vector_init(struct sbi_scratch *scratch, bool cold_boot)
Rename this to rnmi_vector_init() and make it a static function.
> +{
> + unsigned long rnmi_sp;
> + void *rnmi_ctx;
> + 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 without RNMI vector hook cannot support RNMI. */
> + if (!ops || !ops->set_rnmi_trap_vector)
> + return 0;
> +
> + /*
> + * Allocate per-HART RNMI context area once during cold boot and
> + * remember its offset inside struct sbi_scratch. All harts use
> + * the same offset but different scratch pointers, so each hart
> + * gets its own RNMI context.
> + */
> + if (cold_boot) {
> + rnmi_context_offset = sbi_scratch_alloc_offset(SBI_TRAP_REGS_SIZE);
> + if (!rnmi_context_offset)
> + return SBI_ENOMEM;
> + }
> +
> + if (!rnmi_context_offset)
> + return 0;
> +
> + /* Set CSR_MNSCRATCH to point above the RNMI trap-regs save area. */
> + rnmi_ctx = sbi_scratch_offset_ptr(scratch, rnmi_context_offset);
> + rnmi_sp = (unsigned long)rnmi_ctx + SBI_TRAP_REGS_SIZE;
> + csr_write(CSR_MNSCRATCH, rnmi_sp);
> +
> + /* Enable RNMI now that CSR_MNSCRATCH and the trap vector are set up. */
> + csr_set(CSR_MNSTATUS, MNSTATUS_NMIE);
> +
> + return 0;
> +}
> diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> index 0a355f9c..f259c257 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,10 @@ 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);
> + 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)
> @@ -437,6 +443,10 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
> struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
> hart_data_offset);
>
> + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMRNMI)) {
> + csr_write(CSR_MNSCRATCH, hdata->saved_mnscratch);
> + csr_write(CSR_MNSTATUS, hdata->saved_mnstatus);
> + }
> if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
> csr_write64(CSR_MENVCFG, hdata->saved_menvcfg);
> csr_write(CSR_MIDELEG, hdata->saved_mideleg);
> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> index 5259064b..60a24809 100644
> --- a/lib/sbi/sbi_init.c
> +++ b/lib/sbi/sbi_init.c
> @@ -273,6 +273,10 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
> if (rc)
> sbi_hart_hang();
>
> + rc = sbi_rnmi_vector_init(scratch, true);
> + if (rc)
> + sbi_hart_hang();
> +
> rc = sbi_pmu_init(scratch, true);
> if (rc) {
> sbi_printf("%s: pmu init failed (error %d)\n",
> @@ -432,6 +436,10 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
> if (rc)
> sbi_hart_hang();
>
> + rc = sbi_rnmi_vector_init(scratch, false);
> + if (rc)
> + sbi_hart_hang();
> +
Drop the changes in sbi_init.c() instead directly call
rnmi_vector_init() at the end of sbi_hart_init().
> rc = sbi_pmu_init(scratch, false);
> if (rc)
> sbi_hart_hang();
>
> --
> 2.43.7
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
Regards,
Anup
More information about the opensbi
mailing list