Skip to content

Commit a13cada

Browse files
committed
arch: riscv: Add riscv_pmp_clear_all() to reset PMP entries
Introduce the new function `riscv_pmp_clear_all()` to reset the Physical Memory Protection (PMP) configuration. This function iterates through all configured PMP slots. For each entry, it writes 0x0 to the entry's 8-bit configuration register. This action attempts to clear all fields, including the Address Matching Mode (A) bits (setting the region type to OFF), the permission bits (R, W, X), and the Lock (L) bit. According to the RISC-V specification, any writes to the configuration or address registers of a locked PMP entry are ignored. Thus, locked entries will remain unchanged, while all non-locked entries will be effectively disabled and their permissions cleared. The function ensures it operates in Machine mode with MSTATUS.MPRV = 0 and MSTATUS.MPP = M-mode 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 declaration is exposed in the `include/zephyr/arch/riscv/pmp.h` header file, making it available for inclusion and use by external modules. It is recommended for firmware to call this function before transitioning from a Read-Only (RO) stage to a Read-Write (RW) stage. This ensures that any PMP settings established during the RO phase, which might no longer be appropriate, are cleared, providing a clean and secure base PMP configuration for the RW firmware. Signed-off-by: Firas Sammoura <[email protected]>
1 parent 5c8380d commit a13cada

File tree

2 files changed

+73
-0
lines changed
  • arch/riscv/core
  • include/zephyr/arch/riscv

2 files changed

+73
-0
lines changed

arch/riscv/core/pmp.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,52 @@ 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+
pmp_n_cfg[index] = 0x0;
377+
}
378+
379+
#ifdef CONFIG_64BIT
380+
csr_write(pmpcfg0, pmp_cfg[0]);
381+
#if CONFIG_PMP_SLOTS > 8
382+
csr_write(pmpcfg2, pmp_cfg[1]);
383+
#endif
384+
#else
385+
csr_write(pmpcfg0, pmp_cfg[0]);
386+
csr_write(pmpcfg1, pmp_cfg[1]);
387+
#if CONFIG_PMP_SLOTS > 8
388+
csr_write(pmpcfg2, pmp_cfg[2]);
389+
csr_write(pmpcfg3, pmp_cfg[3]);
390+
#endif
391+
#endif
392+
}
393+
348394
/**
349395
* @Brief Initialize the PMP with global entries on each CPU
350396
*/

include/zephyr/arch/riscv/pmp.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2025 Alphabet
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_RISCV_PMP_H_
8+
#define ZEPHYR_INCLUDE_RISCV_PMP_H_
9+
10+
#include <zephyr/arch/riscv/arch.h>
11+
12+
#ifdef CONFIG_RISCV_PMP
13+
14+
/**
15+
* @brief Resets all unlocked PMP entries to OFF mode (Null Region).
16+
*
17+
* This function is used to securely clear the PMP configuration. It first
18+
* ensures the execution context is M-mode by setting MSTATUS_MPRV=0 and
19+
* MSTATUS_MPP=M-mode. It then reads all pmpcfgX CSRs, iterates through
20+
* the configuration bytes, and clears the Address Matching Mode bits (PMP_A)
21+
* for any entry that is not locked (PMP_L is clear), effectively disabling the region.
22+
*/
23+
void riscv_pmp_clear_all(void);
24+
25+
#endif
26+
27+
#endif /* ZEPHYR_INCLUDE_RISCV_PMP_H_ */

0 commit comments

Comments
 (0)