Skip to content

Commit c905cb2

Browse files
committed
RISCV: PMP: Correct pmpcfg register indexing for multi-register configs
The PMP initialization and thread context switching logic was incorrectly assuming that the configuration for all global PMP entries was stored and restored from the first PMP configuration register, pmpcfg0 (i.e., pmp_cfg[0]). On RISC-V architectures, each pmpcfg register controls multiple PMP entries (e.g., 4 entries on RV32). When the number of PMP entries exceeds this, the configuration data spans across multiple pmpcfg registers (pmpcfg0, pmpcfg1, etc.). Failure to save and restore the contents of the correct pmpcfg register leads to an incorrect PMP setup, potentially compromising memory protection boundaries. This patch fixes the indexing by calculating the correct pmpcfg array index using integer division (index / PMPCFG_STRIDE), where PMPCFG_STRIDE represents the number of PMP entries per cfg register. The fixes are in: 1) z_riscv_pmp_init: When saving the configuration of the last global PMP entry, the content is now read from pmp_cfg[index / PMPCFG_STRIDE] instead of always from pmp_cfg[0]. 2) z_riscv_pmp_thread_init: When restoring the global PMP configuration for a new thread, the saved value is now written back to pmp_cfg[global_pmp_end_index / PMPCFG_STRIDE]. Additionally, this patch corrects a parameter in the write_pmp_entries call within z_riscv_pmp_stackguard_enable. The clear_to_end argument is set to true to ensure that any subsequent PMP entries are properly cleared, maintaining a clean PMP state. Signed-off-by: Firas Sammoura <[email protected]>
1 parent dddd738 commit c905cb2

File tree

1 file changed

+4
-5
lines changed

1 file changed

+4
-5
lines changed

arch/riscv/core/pmp.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,12 +432,12 @@ void z_riscv_pmp_init(void)
432432
/* Make sure secondary CPUs produced the same values */
433433
if (global_pmp_end_index != 0) {
434434
__ASSERT(global_pmp_end_index == index, "");
435-
__ASSERT(global_pmp_cfg[0] == pmp_cfg[0], "");
435+
__ASSERT(global_pmp_cfg[0] == pmp_cfg[index / PMPCFG_STRIDE], "");
436436
__ASSERT(global_pmp_last_addr == pmp_addr[index - 1], "");
437437
}
438438
#endif
439439

440-
global_pmp_cfg[0] = pmp_cfg[0];
440+
global_pmp_cfg[0] = pmp_cfg[index / PMPCFG_STRIDE];
441441
global_pmp_last_addr = pmp_addr[index - 1];
442442
global_pmp_end_index = index;
443443

@@ -459,7 +459,7 @@ static inline unsigned int z_riscv_pmp_thread_init(unsigned long *pmp_addr,
459459
/*
460460
* Retrieve pmpcfg0 partial content from global entries.
461461
*/
462-
pmp_cfg[0] = global_pmp_cfg[0];
462+
pmp_cfg[global_pmp_end_index / PMPCFG_STRIDE] = global_pmp_cfg[0];
463463

464464
/*
465465
* Retrieve the pmpaddr value matching the last global PMP slot.
@@ -519,8 +519,7 @@ void z_riscv_pmp_stackguard_enable(struct k_thread *thread)
519519
csr_clear(mstatus, MSTATUS_MPRV | MSTATUS_MPP);
520520

521521
/* Write our m-mode MPP entries */
522-
write_pmp_entries(global_pmp_end_index, thread->arch.m_mode_pmp_end_index,
523-
false /* no need to clear to the end */,
522+
write_pmp_entries(global_pmp_end_index, thread->arch.m_mode_pmp_end_index, true,
524523
PMP_M_MODE(thread));
525524

526525
if (PMP_DEBUG_DUMP) {

0 commit comments

Comments
 (0)