diff --git a/arch/riscv/core/pmp.c b/arch/riscv/core/pmp.c index ca5e5a49d5a74..925488ab2a564 100644 --- a/arch/riscv/core/pmp.c +++ b/arch/riscv/core/pmp.c @@ -345,6 +345,54 @@ static unsigned long global_pmp_last_addr; /* End of global PMP entry range */ static unsigned int global_pmp_end_index; +void riscv_pmp_clear_all(void) +{ + /* + * Ensure we are in M-mode and that memory accesses use M-mode privileges + * (MPRV=0). We also set MPP to M-mode to establish a predictable prior privilege level. + */ + csr_clear(mstatus, MSTATUS_MPRV); + csr_set(mstatus, MSTATUS_MPP); + + unsigned long pmp_cfg[CONFIG_PMP_SLOTS / PMPCFG_STRIDE]; + +#ifdef CONFIG_64BIT + pmp_cfg[0] = csr_read(pmpcfg0); +#if CONFIG_PMP_SLOTS > 8 + pmp_cfg[1] = csr_read(pmpcfg2); +#endif +#else + pmp_cfg[0] = csr_read(pmpcfg0); + pmp_cfg[1] = csr_read(pmpcfg1); +#if CONFIG_PMP_SLOTS > 8 + pmp_cfg[2] = csr_read(pmpcfg2); + pmp_cfg[3] = csr_read(pmpcfg3); +#endif +#endif + + uint8_t *pmp_n_cfg = (uint8_t *)pmp_cfg; + + for (int index = 0; index < CONFIG_PMP_SLOTS; ++index) { + if ((pmp_n_cfg[index] & PMP_L) == 0) { + pmp_n_cfg[index] &= ~PMP_A; + } + } + +#ifdef CONFIG_64BIT + csr_write(pmpcfg0, pmp_cfg[0]); +#if CONFIG_PMP_SLOTS > 8 + csr_write(pmpcfg2, pmp_cfg[1]); +#endif +#else + csr_write(pmpcfg0, pmp_cfg[0]); + csr_write(pmpcfg1, pmp_cfg[1]); +#if CONFIG_PMP_SLOTS > 8 + csr_write(pmpcfg2, pmp_cfg[2]); + csr_write(pmpcfg3, pmp_cfg[3]); +#endif +#endif +} + /** * @Brief Initialize the PMP with global entries on each CPU */ diff --git a/arch/riscv/include/pmp.h b/arch/riscv/include/pmp.h index ca4f37f3a2aba..ac1f31bbe1715 100644 --- a/arch/riscv/include/pmp.h +++ b/arch/riscv/include/pmp.h @@ -15,4 +15,15 @@ void z_riscv_pmp_usermode_init(struct k_thread *thread); void z_riscv_pmp_usermode_prepare(struct k_thread *thread); void z_riscv_pmp_usermode_enable(struct k_thread *thread); +/** + * @brief Resets all unlocked PMP entries to OFF mode (Null Region). + * + * This function is used to securely clear the PMP configuration. It first + * ensures the execution context is M-mode by setting MSTATUS_MPRV=0 and + * MSTATUS_MPP=M-mode. It then reads all pmpcfgX CSRs, iterates through + * the configuration bytes, and clears the Address Matching Mode bits (PMP_A) + * for any entry that is not locked (PMP_L is clear), effectively disabling the region. + */ +void riscv_pmp_clear_all(void); + #endif /* PMP_H_ */