From 1c3d247a271e265fd23456c71ff677bd468bdd76 Mon Sep 17 00:00:00 2001 From: Firas Sammoura Date: Wed, 17 Sep 2025 23:07:56 +0000 Subject: [PATCH] arch/riscv: Allow overriding ROM region for PMP setup The Physical Memory Protection (PMP) setup for the ROM region currently relies on the fixed linker symbols `__rom_region_start` and `__rom_region_size`. In environments where the firmware is loaded by a bootloader (example a two-stage boot, or jumping from a RO-image to a RW-image), the actual physical address of the executable code might change. This is especially critical when the PMP must protect the entire persistent ROM area, regardless of which stage of the firmware is executing. This commit addresses this by: 1. Introducing `CONFIG_ROM_REGION_START` and `CONFIG_ROM_REGION_SIZE` Kconfig options, guarded by `RISCV_PMP`. These default to the standard linker symbols but allow manual override via hexadecimal strings. 2. Adding a compile-time `ADDRESS_RESOLVER` macro in `pmp.c` to parse the Kconfig string, correctly handling the conversion of either the default linker symbol or a user-provided hexadecimal address into a numerical value. 3. Updating `z_riscv_pmp_init()` to use the resolved Kconfig values, ensuring that the PMP always protects the correct, full ROM area as defined by the user or the linker. Signed-off-by: Firas Sammoura --- arch/riscv/Kconfig | 24 ++++++++++++++++++++++++ arch/riscv/core/pmp.c | 17 +++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 05dcd84465380..f1a1a5b89ce6b 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -432,6 +432,30 @@ config PMP_STACK_GUARD_MIN_SIZE wiggle room to accommodate the eventual overflow exception stack usage. +config ROM_REGION_START + string "Start address or linker symbol of the ROM region" + depends on RISCV_PMP + default "__rom_region_start" + help + The linker symbol or hexadecimal address that defines the start of the + ROM region. + This configuration is used to calculate the physical memory + protection (PMP) region entry. The value is resolved at compile time. + To override the linker's default, set this to a hexadecimal string, + such as "0x80000000". + +config ROM_REGION_SIZE + string "Size or linker symbol of the ROM region" + depends on RISCV_PMP + default "__rom_region_size" + help + The linker symbol or hexadecimal size that defines the overall byte + length of the ROM region. + This configuration is used to calculate the physical memory + protection (PMP) region size. The value is resolved at compile time. + To manually override the linker's default size, set this to a + hexadecimal string, such as "0x100000". + # Implement the null pointer detection using the Physical Memory Protection # (PMP) Unit. config NULL_POINTER_EXCEPTION_DETECTION_PMP diff --git a/arch/riscv/core/pmp.c b/arch/riscv/core/pmp.c index ca5e5a49d5a74..6d589a6fcc168 100644 --- a/arch/riscv/core/pmp.c +++ b/arch/riscv/core/pmp.c @@ -32,6 +32,8 @@ #include #include +#include + #define LOG_LEVEL CONFIG_MPU_LOG_LEVEL #include LOG_MODULE_REGISTER(mpu); @@ -56,6 +58,14 @@ LOG_MODULE_REGISTER(mpu); #define PMP_NONE 0 +#define ADDRESS_RESOLVER(config_value) \ + (strcmp(config_value, "__rom_region_start") == 0) ? (uintptr_t)__rom_region_start \ + : (strcmp(config_value, "__rom_region_size") == 0) \ + ? (uintptr_t)__rom_region_size \ + : ((config_value[0] == '0' && (config_value[1] == 'x' || config_value[1] == 'X')) \ + ? (uintptr_t)strtoul(config_value, NULL, 16) \ + : 0) + static void print_pmp_entries(unsigned int pmp_start, unsigned int pmp_end, unsigned long *pmp_addr, unsigned long *pmp_cfg, const char *banner) @@ -355,10 +365,9 @@ void z_riscv_pmp_init(void) unsigned int index = 0; /* The read-only area is always there for every mode */ - set_pmp_entry(&index, PMP_R | PMP_X | PMP_L, - (uintptr_t)__rom_region_start, - (size_t)__rom_region_size, - pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr)); + set_pmp_entry(&index, PMP_R | PMP_X | PMP_L, ADDRESS_RESOLVER(CONFIG_ROM_REGION_START), + ADDRESS_RESOLVER(CONFIG_ROM_REGION_SIZE), pmp_addr, pmp_cfg, + ARRAY_SIZE(pmp_addr)); #ifdef CONFIG_NULL_POINTER_EXCEPTION_DETECTION_PMP /*