[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