[PATCH v3 2/4] lib: sbi: give platform choice of using single memregion to cover OpenSBI
Yu-Chien Peter Lin
peter.lin at sifive.com
Mon Dec 1 00:11:56 PST 2025
Hi Bo,
Maybe use a FW option to enable single FW region at compile
or runtime options.
compile time [1]:
make PLATFORM=generic FW_OPTIONS=0x4
runtime [2]:
Use fw dynamic and pass 0x4 via ((struct fw_dynamic_info *)$a2)->options
[1]
https://github.com/riscv-software-src/opensbi/blob/master/docs/firmware/fw.md#options-for-opensbi-firmware-behaviors
[2]
https://github.com/riscv-software-src/opensbi/blob/825d0e918a9e41cc57097a8cb913f26550699911/docs/firmware/fw_dynamic.md?plain=1#L10
diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h
index f1b4155d..4f40fedd 100644
--- a/include/sbi/sbi_scratch.h
+++ b/include/sbi/sbi_scratch.h
@@ -115,6 +115,13 @@ enum sbi_scratch_options {
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
/** Enable runtime debug prints */
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
+ /**
+ * Use single PMP entry covering entire firmware region.
+ * Saves one PMP entry on non-Smepmp platforms at the cost
+ * of coarser PMP granularity.
+ * Not compatible with Smepmp (M-mode RWX is not supported).
+ */
+ SBI_SCRATCH_SINGLE_FW_PMP = (1 << 2),
};
/** Get pointer to sbi_scratch for current HART */
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index da0f0557..0222ca93 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -904,18 +904,27 @@ int sbi_domain_init(struct sbi_scratch *scratch,
u32 cold_hartid)
root.possible_harts = root_hmask;
/* Root domain firmware memory region */
- sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
- (SBI_DOMAIN_MEMREGION_M_READABLE |
- SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
- SBI_DOMAIN_MEMREGION_FW),
- &root_memregs[root_memregs_count++]);
-
- sbi_domain_memregion_init((scratch->fw_start +
scratch->fw_rw_offset),
- (scratch->fw_size -
scratch->fw_rw_offset),
- (SBI_DOMAIN_MEMREGION_M_READABLE |
- SBI_DOMAIN_MEMREGION_M_WRITABLE |
- SBI_DOMAIN_MEMREGION_FW),
- &root_memregs[root_memregs_count++]);
+ if (scratch->options & SBI_SCRATCH_SINGLE_FW_PMP) {
+ sbi_domain_memregion_init(scratch->fw_start,
scratch->fw_size,
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
+ SBI_DOMAIN_MEMREGION_FW),
+ &root_memregs[root_memregs_count++]);
+ } else {
+ sbi_domain_memregion_init(scratch->fw_start,
scratch->fw_rw_offset,
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
+ SBI_DOMAIN_MEMREGION_FW),
+ &root_memregs[root_memregs_count++]);
+
+ sbi_domain_memregion_init((scratch->fw_start +
scratch->fw_rw_offset),
+ (scratch->fw_size -
scratch->fw_rw_offset),
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_FW),
+ &root_memregs[root_memregs_count++]);
+ }
root.fw_region_inited = true;
Best regards,
Peter Lin
On 11/20/25 5:34 PM, Bo Gan wrote:
> By default the OpenSBI itself is covered by 2 memregions for RX/RW
> sections. This is required by platforms with Smepmp to enforce
> proper permissions in M mode. Note: M-mode only regions can't
> have RWX permissions with Smepmp. Platforms with traditional PMPs
> won't be able to benefit from it, as both regions are effectively
> RWX in M mode, but usually it's harmless to so. Now we provide
> these platforms with an option to disable this logic. It saves 1
> PMP entry. For platforms really in short of PMPs, it does make a
> difference.
>
> Note: Platform requesting single OpenSBI memregion must be using
> traditional (old) PMP. We expect the platform code to do
> the right thing.
>
> Signed-off-by: Bo Gan <ganboing at gmail.com>
> ---
> include/sbi/sbi_platform.h | 21 +++++++++++++++++++++
> lib/sbi/sbi_domain.c | 36 ++++++++++++++++++++++++------------
> 2 files changed, 45 insertions(+), 12 deletions(-)
>
> diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
> index a53e1797..f414514f 100644
> --- a/include/sbi/sbi_platform.h
> +++ b/include/sbi/sbi_platform.h
> @@ -76,6 +76,9 @@ struct sbi_platform_operations {
> /* Check if specified HART is allowed to do cold boot */
> bool (*cold_boot_allowed)(u32 hartid);
>
> + /* Check if platform requires single firmware region */
> + bool (*single_fw_region)(void);
> +
> /* Platform nascent initialization */
> int (*nascent_init)(void);
>
> @@ -359,6 +362,24 @@ static inline bool sbi_platform_cold_boot_allowed(
> return true;
> }
>
> +/**
> + * Check whether platform requires single firmware region
> + *
> + * Note: Single firmware region only works with legacy PMP because with
> + * Smepmp M-mode only regions can't have RWX permissions.
> + *
> + * @param plat pointer to struct sbi_platform
> + *
> + * @return true if single firmware region required and false otherwise
> + */
> +static inline bool sbi_platform_single_fw_region(
> + const struct sbi_platform *plat)
> +{
> + if (plat && sbi_platform_ops(plat)->single_fw_region)
> + return sbi_platform_ops(plat)->single_fw_region();
> + return false;
> +}
> +
> /**
> * Nascent (very early) initialization for current HART
> *
> diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
> index 32e4c882..afda7365 100644
> --- a/lib/sbi/sbi_domain.c
> +++ b/lib/sbi/sbi_domain.c
> @@ -925,18 +925,30 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
> root.possible_harts = root_hmask;
>
> /* Root domain firmware memory region */
> - sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
> - (SBI_DOMAIN_MEMREGION_M_READABLE |
> - SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
> - SBI_DOMAIN_MEMREGION_FW),
> - &root_memregs[root_memregs_count++]);
> -
> - sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
> - (scratch->fw_size - scratch->fw_rw_offset),
> - (SBI_DOMAIN_MEMREGION_M_READABLE |
> - SBI_DOMAIN_MEMREGION_M_WRITABLE |
> - SBI_DOMAIN_MEMREGION_FW),
> - &root_memregs[root_memregs_count++]);
> + if (sbi_platform_single_fw_region(sbi_platform_ptr(scratch))) {
> + sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size,
> + (SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE |
> + SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
> + SBI_DOMAIN_MEMREGION_FW),
> + &root_memregs[root_memregs_count++]);
> + } else {
> + sbi_domain_memregion_init(scratch->fw_start,
> + scratch->fw_rw_offset,
> + (SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
> + SBI_DOMAIN_MEMREGION_FW),
> + &root_memregs[root_memregs_count++]);
> +
> + sbi_domain_memregion_init((scratch->fw_start +
> + scratch->fw_rw_offset),
> + (scratch->fw_size -
> + scratch->fw_rw_offset),
> + (SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE |
> + SBI_DOMAIN_MEMREGION_FW),
> + &root_memregs[root_memregs_count++]);
> + }
>
> root.fw_region_inited = true;
>
More information about the opensbi
mailing list