[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