[PATCH v3 1/4] lib: sbi: allow platform to override PMP (un)configuration
Bo Gan
ganboing at gmail.com
Thu Nov 20 01:34:37 PST 2025
Platform sometimes wants to override the entire PMP (un)config phase,
not just performing additional work for each individual PMP entry. This
allows platforms to insert SoC/core specific PMP entries in a way that
works together with the existing ones set by lib/ code, not conflicting.
platform can also choose to merge or skip memory regions in a reasonable
way in case there's a shortage of PMP entries.
In addition, logic for determining flags in `sbi_hart_oldpmp_configure`
is abstracted out as sbi_domain_get_oldpmp_flags, analogous to the
`sbi_domain_get_smepmp_flags` for smepmp. so platform with traditional
PMP can leverage it in its own `pmp_configure`
Signed-off-by: Bo Gan <ganboing at gmail.com>
---
include/sbi/sbi_domain.h | 7 +++++
include/sbi/sbi_hart.h | 3 ++
include/sbi/sbi_platform.h | 53 ++++++++++++++++++++++++++++++++++++
lib/sbi/sbi_domain.c | 21 ++++++++++++++
lib/sbi/sbi_domain_context.c | 11 +-------
lib/sbi/sbi_hart.c | 45 ++++++++++++++++++------------
6 files changed, 113 insertions(+), 27 deletions(-)
diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index 1196d609..3360e090 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -253,6 +253,13 @@ void sbi_domain_memregion_init(unsigned long addr,
unsigned long flags,
struct sbi_domain_memregion *reg);
+/**
+ * Return the oldpmp pmpcfg LRWX encoding for the flags in @reg.
+ *
+ * @param reg pointer to memory region; its flags field encodes permissions.
+ */
+unsigned int sbi_domain_get_oldpmp_flags(struct sbi_domain_memregion *reg);
+
/**
* Return the Smepmp pmpcfg LRWX encoding for the flags in @reg.
*
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index e66dd52f..c0bf79e0 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -133,6 +133,8 @@ struct sbi_hart_features {
};
struct sbi_scratch;
+struct sbi_domain;
+struct sbi_domain_memregion;
int sbi_hart_reinit(struct sbi_scratch *scratch);
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
@@ -147,6 +149,7 @@ unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
bool sbi_hart_smepmp_is_fw_region(unsigned int pmp_idx);
+void sbi_hart_pmp_unconfigure(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
int sbi_hart_unmap_saddr(void);
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index d75c12de..a53e1797 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -146,6 +146,18 @@ struct sbi_platform_operations {
unsigned long log2len);
/** platform specific pmp disable on current HART */
void (*pmp_disable)(unsigned int n);
+
+ /** platform pmp configure override on current HART */
+ int (*pmp_configure)(unsigned int pmp_count,
+ unsigned int pmp_log2gran,
+ unsigned long pmp_addr_max);
+ /**
+ * You need both pmp_configure/unconfigure to properly
+ * provide platform override
+ */
+
+ /** platform pmp unconfigure override on current HART */
+ void (*pmp_unconfigure)(void);
};
/** Platform default per-HART stack size for exception/interrupt handling */
@@ -666,6 +678,47 @@ static inline void sbi_platform_pmp_disable(const struct sbi_platform *plat,
sbi_platform_ops(plat)->pmp_disable(n);
}
+/**
+ * Check if platform wants to override PMP (un)configuration
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline bool sbi_platform_pmp_override(const struct sbi_platform *plat)
+{
+ return plat &&
+ sbi_platform_ops(plat)->pmp_configure &&
+ sbi_platform_ops(plat)->pmp_unconfigure;
+}
+
+/**
+ * Platform PMP configuration override
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param pmp_count number of PMP entries
+ * @param pmp_log2gran PMP granularity
+ * @param pmp_addr_max largest value pmpaddr(x) can hold
+ */
+static inline int sbi_platform_pmp_configure(const struct sbi_platform *plat,
+ unsigned int pmp_count,
+ unsigned int pmp_log2gran,
+ unsigned long pmp_addr_max)
+{
+ return sbi_platform_ops(plat)->pmp_configure(pmp_count,
+ pmp_log2gran,
+ pmp_addr_max);
+}
+
+/**
+ * Platform PMP unconfiguration override
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void sbi_platform_pmp_unconfigure(
+ const struct sbi_platform *plat)
+{
+ return sbi_platform_ops(plat)->pmp_unconfigure();
+}
+
#endif
#endif
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index da0f0557..32e4c882 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -122,6 +122,27 @@ void sbi_domain_memregion_init(unsigned long addr,
}
}
+unsigned int sbi_domain_get_oldpmp_flags(struct sbi_domain_memregion *reg)
+{
+ unsigned int pmp_flags = 0;
+
+ /*
+ * If permissions are to be enforced for all modes on
+ * this region, the lock bit should be set.
+ */
+ if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS)
+ pmp_flags |= PMP_L;
+
+ if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
+ pmp_flags |= PMP_R;
+ if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
+ pmp_flags |= PMP_W;
+ if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
+ pmp_flags |= PMP_X;
+
+ return pmp_flags;
+}
+
unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
{
unsigned int pmp_flags = 0;
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index 74ad25e8..ea7f741b 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -102,7 +102,6 @@ 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();
- unsigned int pmp_count = sbi_hart_pmp_count(scratch);
if (!ctx || !dom_ctx || ctx == dom_ctx)
return SBI_EINVAL;
@@ -120,15 +119,7 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
sbi_hartmask_set_hartindex(hartindex, &target_dom->assigned_harts);
spin_unlock(&target_dom->assigned_harts_lock);
- /* Reconfigure PMP settings for the new domain */
- for (int i = 0; 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);
- }
+ sbi_hart_pmp_unconfigure(scratch);
sbi_hart_pmp_configure(scratch);
/* Save current CSR context and restore target domain's CSR context */
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index a91703b4..b39f4de9 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -448,23 +448,9 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
return SBI_EFAIL;
- pmp_flags = 0;
-
- /*
- * If permissions are to be enforced for all modes on
- * this region, the lock bit should be set.
- */
- if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS)
- pmp_flags |= PMP_L;
-
- if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
- pmp_flags |= PMP_R;
- if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
- pmp_flags |= PMP_W;
- if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
- pmp_flags |= PMP_X;
-
+ pmp_flags = sbi_domain_get_oldpmp_flags(reg);
pmp_addr = reg->base >> PMP_SHIFT;
+
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
sbi_platform_pmp_set(sbi_platform_ptr(scratch),
pmp_idx, reg->flags, pmp_flags,
@@ -528,12 +514,34 @@ int sbi_hart_unmap_saddr(void)
return pmp_disable(SBI_SMEPMP_RESV_ENTRY);
}
+void sbi_hart_pmp_unconfigure(struct sbi_scratch *scratch)
+{
+ unsigned int pmp_count = sbi_hart_pmp_count(scratch);
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if (sbi_platform_pmp_override(plat)) {
+ sbi_platform_pmp_unconfigure(plat);
+ return;
+ }
+
+ /* Reconfigure PMP settings for the new domain */
+ for (unsigned int i = 0; 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);
+ }
+}
+
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
int rc;
unsigned int pmp_bits, pmp_log2gran;
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
unsigned long pmp_addr_max;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!pmp_count)
return 0;
@@ -542,7 +550,10 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
- if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
+ if (sbi_platform_pmp_override(plat))
+ rc = sbi_platform_pmp_configure(plat, pmp_count,
+ pmp_log2gran, pmp_addr_max);
+ else if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
rc = sbi_hart_smepmp_configure(scratch, pmp_count,
pmp_log2gran, pmp_addr_max);
else
--
2.34.1
More information about the opensbi
mailing list