[RFC PATCH v3 4/6] lib: sbi: sbi_hart: extend PMP handling to support multiple reserved entries
Yu-Chien Peter Lin
peter.lin at sifive.com
Sun Nov 30 03:16:41 PST 2025
Previously, OpenSBI supported only a single reserved PMP entry. Add
support for multiple reserved PMP entries, with the count determined
by the platform-specific sbi_platform_reserved_pmp_count() function.
Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
include/sbi/sbi_hart.h | 15 ----------
lib/sbi/sbi_domain_context.c | 6 ++--
lib/sbi/sbi_hart.c | 53 +++++++++++++++++++++++++-----------
3 files changed, 41 insertions(+), 33 deletions(-)
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index e66dd52f..6d5d0be7 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -105,21 +105,6 @@ enum sbi_hart_csrs {
SBI_HART_CSR_MAX,
};
-/*
- * Smepmp enforces access boundaries between M-mode and
- * S/U-mode. When it is enabled, the PMPs are programmed
- * such that M-mode doesn't have access to S/U-mode memory.
- *
- * To give M-mode R/W access to the shared memory between M and
- * S/U-mode, first entry is reserved. It is disabled at boot.
- * When shared memory access is required, the physical address
- * should be programmed into the first PMP entry with R/W
- * permissions to the M-mode. Once the work is done, it should be
- * unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
- * pair should be used to map/unmap the shared memory.
- */
-#define SBI_SMEPMP_RESV_ENTRY 0
-
struct sbi_hart_features {
bool detected;
int priv_version;
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index 74ad25e8..d2269529 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -11,6 +11,7 @@
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
+#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_domain.h>
@@ -102,6 +103,8 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
struct sbi_trap_context *trap_ctx;
struct sbi_domain *current_dom, *target_dom;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+ const struct sbi_platform *plat = sbi_platform_thishart_ptr();
+ u32 reserved_pmp_count = sbi_platform_reserved_pmp_count(plat);
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
if (!ctx || !dom_ctx || ctx == dom_ctx)
@@ -121,11 +124,10 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
spin_unlock(&target_dom->assigned_harts_lock);
/* Reconfigure PMP settings for the new domain */
- for (int i = 0; i < pmp_count; i++) {
+ for (int i = reserved_pmp_count; i < pmp_count; i++) {
/* Don't revoke firmware access permissions */
if (sbi_hart_smepmp_is_fw_region(i))
continue;
-
sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
pmp_disable(i);
}
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 548fdecd..a7235758 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -32,6 +32,7 @@ void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
static unsigned long hart_features_offset;
static DECLARE_BITMAP(fw_smepmp_ids, PMP_COUNT);
static bool fw_smepmp_ids_inited;
+static unsigned int saddr_pmp_id;
static void mstatus_init(struct sbi_scratch *scratch)
{
@@ -349,6 +350,8 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
unsigned long pmp_addr_max)
{
struct sbi_domain_memregion *reg;
+ const struct sbi_platform *plat = sbi_platform_thishart_ptr();
+ u32 reserved_pmp_count = sbi_platform_reserved_pmp_count(plat);
struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_idx, pmp_flags;
@@ -358,15 +361,13 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
*/
csr_set(CSR_MSECCFG, MSECCFG_RLB);
- /* Disable the reserved entry */
- pmp_disable(SBI_SMEPMP_RESV_ENTRY);
+ /* Disable the reserved entries */
+ for (int i = 0; i < reserved_pmp_count; i++)
+ pmp_disable(i);
/* Program M-only regions when MML is not set. */
- pmp_idx = 0;
+ pmp_idx = reserved_pmp_count;
sbi_domain_for_each_memregion(dom, reg) {
- /* Skip reserved entry */
- if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
- pmp_idx++;
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
return SBI_EFAIL;
@@ -405,11 +406,8 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
csr_set(CSR_MSECCFG, MSECCFG_MML);
/* Program shared and SU-only regions */
- pmp_idx = 0;
+ pmp_idx = reserved_pmp_count;
sbi_domain_for_each_memregion(dom, reg) {
- /* Skip reserved entry */
- if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
- pmp_idx++;
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
return SBI_EFAIL;
@@ -439,11 +437,14 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
unsigned long pmp_addr_max)
{
struct sbi_domain_memregion *reg;
+ const struct sbi_platform *plat = sbi_platform_thishart_ptr();
+ u32 reserved_pmp_count = sbi_platform_reserved_pmp_count(plat);
struct sbi_domain *dom = sbi_domain_thishart_ptr();
- unsigned int pmp_idx = 0;
+ unsigned int pmp_idx;
unsigned int pmp_flags;
unsigned long pmp_addr;
+ pmp_idx = reserved_pmp_count;
sbi_domain_for_each_memregion(dom, reg) {
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
return SBI_EFAIL;
@@ -481,6 +482,19 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
return 0;
}
+/*
+ * Smepmp enforces access boundaries between M-mode and
+ * S/U-mode. When it is enabled, the PMPs are programmed
+ * such that M-mode doesn't have access to S/U-mode memory.
+ *
+ * To give M-mode R/W access to the shared memory between M and
+ * S/U-mode, high-priority entry is reserved. It is disabled at boot.
+ * When shared memory access is required, the physical address
+ * should be programmed into the reserved PMP entry with R/W
+ * permissions to the M-mode. Once the work is done, it should be
+ * unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
+ * pair should be used to map/unmap the shared memory.
+ */
int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
{
/* shared R/W access for M and S/U mode */
@@ -492,8 +506,9 @@ int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
- if (is_pmp_entry_mapped(SBI_SMEPMP_RESV_ENTRY))
+ if (reserved_pmp_alloc(&saddr_pmp_id)) {
return SBI_ENOSPC;
+ }
for (order = MAX(sbi_hart_pmp_log2gran(scratch), log2roundup(size));
order <= __riscv_xlen; order++) {
@@ -509,23 +524,29 @@ int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
}
}
- sbi_platform_pmp_set(sbi_platform_ptr(scratch), SBI_SMEPMP_RESV_ENTRY,
+ sbi_platform_pmp_set(sbi_platform_ptr(scratch), saddr_pmp_id,
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW,
pmp_flags, base, order);
- pmp_set(SBI_SMEPMP_RESV_ENTRY, pmp_flags, base, order);
+ pmp_set(saddr_pmp_id, pmp_flags, base, order);
return SBI_OK;
}
int sbi_hart_unmap_saddr(void)
{
+ int rc;
+
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
- sbi_platform_pmp_disable(sbi_platform_ptr(scratch), SBI_SMEPMP_RESV_ENTRY);
- return pmp_disable(SBI_SMEPMP_RESV_ENTRY);
+ sbi_platform_pmp_disable(sbi_platform_ptr(scratch), saddr_pmp_id);
+ rc = pmp_disable(saddr_pmp_id);
+ if (rc)
+ return rc;
+
+ return reserved_pmp_free(saddr_pmp_id);
}
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
--
2.39.3
More information about the opensbi
mailing list