diff --git a/arch/risc-v/src/common/riscv_pmp.c b/arch/risc-v/src/common/riscv_pmp.c index 9a19c94a39550..bf0b19a210f9c 100644 --- a/arch/risc-v/src/common/riscv_pmp.c +++ b/arch/risc-v/src/common/riscv_pmp.c @@ -100,6 +100,32 @@ typedef struct pmp_entry_s pmp_entry_t; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: log2ceil + * + * Description: + * Calculate the up-rounded power-of-two for input. + * + * Input Parameters: + * size - The size of the PMP region. + * + * Returned Value: + * Power-of-two for argument, rounded up. + * + ****************************************************************************/ + +static uintptr_t log2ceil(uintptr_t size) +{ + uintptr_t pot = 0; + + for (size = size - 1; size > 1; size >>= 1) + { + pot++; + } + + return pot; +} + /**************************************************************************** * Name: pmp_check_addrmatch_type * @@ -160,7 +186,8 @@ static bool pmp_check_addrmatch_type(uintptr_t type) * ****************************************************************************/ -static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size) +static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size, + uintptr_t type) { /* Check that the size is not too small */ @@ -183,7 +210,23 @@ static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size) return false; } - return OK; + /* Perform additional checks on base and size for NAPOT area */ + + if (type == PMPCFG_A_NAPOT) + { + /* Get the power-of-two for size, rounded up */ + + uintptr_t pot = log2ceil(size); + + if ((base & ((UINT64_C(1) << pot) - 1)) != 0) + { + /* The start address is not properly aligned with size */ + + return false; + } + } + + return true; } /**************************************************************************** @@ -455,7 +498,7 @@ int riscv_config_pmp_region(uintptr_t region, uintptr_t attr, /* Check the region attributes */ - if (pmp_check_region_attrs(base, size)) + if (pmp_check_region_attrs(base, size, type) == false) { return -EINVAL; } @@ -463,7 +506,7 @@ int riscv_config_pmp_region(uintptr_t region, uintptr_t attr, /* Calculate new base address from type */ addr = base >> 2; - if (PMPCFG_A_NAPOT == (attr & PMPCFG_A_MASK)) + if (type == PMPCFG_A_NAPOT) { addr |= (size - 1) >> 3; }