Skip to content

Commit 6d99870

Browse files
committed
arch: riscv: Add function to clear all unlocked PMP entries
Introduce the new function `riscv_pmp_clear_all()` to securely reset the Physical Memory Protection (PMP) configuration. This function iterates through all configured PMP slots. For each entry, it checks if the Lock (L) bit is set. If the entry is not locked, it clears the Address Matching Mode (A) bits, effectively setting the region type to OFF (Null Region), disabling the entry. The function ensures it operates in Machine mode with MSTATUS.MPRV = 0 before modifying any PMP Control and Status Registers (CSRs). This provides a mechanism to clear all non-locked PMP regions, returning them to a default disabled state. The function is exposed in the pmp.h header file. Signed-off-by: Firas Sammoura <[email protected]>
1 parent 16f4d6c commit 6d99870

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

arch/riscv/core/pmp.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,54 @@ static unsigned long global_pmp_last_addr;
345345
/* End of global PMP entry range */
346346
static unsigned int global_pmp_end_index;
347347

348+
void riscv_pmp_clear_all(void)
349+
{
350+
/*
351+
* Ensure we are in M-mode and that memory accesses use M-mode privileges
352+
* (MPRV=0). We also set MPP to M-mode to establish a predictable prior privilege level.
353+
*/
354+
csr_clear(mstatus, MSTATUS_MPRV);
355+
csr_set(mstatus, MSTATUS_MPP);
356+
357+
unsigned long pmp_cfg[CONFIG_PMP_SLOTS / PMPCFG_STRIDE];
358+
359+
#ifdef CONFIG_64BIT
360+
pmp_cfg[0] = csr_read(pmpcfg0);
361+
#if CONFIG_PMP_SLOTS > 8
362+
pmp_cfg[1] = csr_read(pmpcfg2);
363+
#endif
364+
#else
365+
pmp_cfg[0] = csr_read(pmpcfg0);
366+
pmp_cfg[1] = csr_read(pmpcfg1);
367+
#if CONFIG_PMP_SLOTS > 8
368+
pmp_cfg[2] = csr_read(pmpcfg2);
369+
pmp_cfg[3] = csr_read(pmpcfg3);
370+
#endif
371+
#endif
372+
373+
uint8_t *pmp_n_cfg = (uint8_t *)pmp_cfg;
374+
375+
for (int index = 0; index < CONFIG_PMP_SLOTS; ++index) {
376+
if ((pmp_n_cfg[index] & PMP_L) == 0) {
377+
pmp_n_cfg[index] &= ~PMP_A;
378+
}
379+
}
380+
381+
#ifdef CONFIG_64BIT
382+
csr_write(pmpcfg0, pmp_cfg[0]);
383+
#if CONFIG_PMP_SLOTS > 8
384+
csr_write(pmpcfg2, pmp_cfg[1]);
385+
#endif
386+
#else
387+
csr_write(pmpcfg0, pmp_cfg[0]);
388+
csr_write(pmpcfg1, pmp_cfg[1]);
389+
#if CONFIG_PMP_SLOTS > 8
390+
csr_write(pmpcfg2, pmp_cfg[2]);
391+
csr_write(pmpcfg3, pmp_cfg[3]);
392+
#endif
393+
#endif
394+
}
395+
348396
/**
349397
* @Brief Initialize the PMP with global entries on each CPU
350398
*/

arch/riscv/include/pmp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,15 @@ void z_riscv_pmp_usermode_init(struct k_thread *thread);
1515
void z_riscv_pmp_usermode_prepare(struct k_thread *thread);
1616
void z_riscv_pmp_usermode_enable(struct k_thread *thread);
1717

18+
/**
19+
* @brief Resets all unlocked PMP entries to OFF mode (Null Region).
20+
*
21+
* This function is used to securely clear the PMP configuration. It first
22+
* ensures the execution context is M-mode by setting MSTATUS_MPRV=0 and
23+
* MSTATUS_MPP=M-mode. It then reads all pmpcfgX CSRs, iterates through
24+
* the configuration bytes, and clears the Address Matching Mode bits (PMP_A)
25+
* for any entry that is not locked (PMP_L is clear), effectively disabling the region.
26+
*/
27+
void riscv_pmp_clear_all(void);
28+
1829
#endif /* PMP_H_ */

0 commit comments

Comments
 (0)