From 878c2676e633ff05a8275c2ff76254990e120bed Mon Sep 17 00:00:00 2001 From: Bo Gan Date: Thu, 18 Dec 2025 02:42:40 -0800 Subject: [PATCH] lib: sbi: give platform choice of using single memregion to cover OpenSBI 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 Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20251218104243.562667-5-ganboing@gmail.com Signed-off-by: Anup Patel --- include/sbi/sbi_platform.h | 21 +++++++++++++++++++++ lib/sbi/sbi_domain.c | 34 +++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index d75c12de..e65d9877 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); @@ -347,6 +350,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 a19bf25b..90cbb540 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -923,18 +923,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++]); + 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++]); + 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;