From 631efeeb4913f278b8f5e5920b8c233ac250ff28 Mon Sep 17 00:00:00 2001 From: Yu-Chien Peter Lin Date: Wed, 8 Oct 2025 16:44:42 +0800 Subject: [PATCH] lib: sbi_domain: ensure consistent firmware PMP entries During domain context switches, all PMP entries are reconfigured which can clear firmware access permissions, causing M-mode access faults under SmePMP. Sort domain regions to place firmware regions first, ensuring consistent firmware PMP entries so they won't be revoked during domain context switches. Signed-off-by: Yu-Chien Peter Lin Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20251008084444.3525615-7-peter.lin@sifive.com Signed-off-by: Anup Patel --- include/sbi/sbi_domain.h | 3 +++ lib/sbi/sbi_domain.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index 9193feb0..1196d609 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -121,6 +121,9 @@ struct sbi_domain_memregion { ((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \ !(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)) +#define SBI_DOMAIN_MEMREGION_IS_FIRMWARE(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_FW) ? true : false) \ + /** Bit to control if permissions are enforced on all modes */ #define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 8b03db12..da0f0557 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -292,6 +292,19 @@ static bool is_region_compatible(const struct sbi_domain_memregion *regA, static bool is_region_before(const struct sbi_domain_memregion *regA, const struct sbi_domain_memregion *regB) { + /* + * Enforce firmware region ordering for memory access + * under SmePMP. + * Place firmware regions first to ensure consistent + * PMP entries during domain context switches. + */ + if (SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regA->flags) && + !SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regB->flags)) + return true; + if (!SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regA->flags) && + SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regB->flags)) + return false; + if (regA->order < regB->order) return true;