Skip to content

Commit a333aff

Browse files
committed
Add PMP infrastructure and management structures
Introduces RISC-V Physical Memory Protection (PMP) support for hardware-enforced memory isolation. TOR mode is adopted as the addressing scheme for its flexibility in supporting arbitrary address ranges without alignment requirements, simplifying region management for task stacks of varying sizes. Adds CSR definitions for PMP registers, permission encodings, and hardware constants. Provides structures for region configuration and state tracking, with priority-based management to handle the 16-region hardware limit. Includes error codes and functions for region configuration and access verification.
1 parent 7dbdfc6 commit a333aff

File tree

4 files changed

+180
-0
lines changed

4 files changed

+180
-0
lines changed

arch/riscv/csr.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,82 @@
179179

180180
/* Machine Scratch Register - For temporary storage during traps */
181181
#define CSR_MSCRATCH 0x340
182+
183+
/* PMP Address Registers (pmpaddr0-pmpaddr15) - 16 regions maximum
184+
* In TOR (Top-of-Range) mode, these define the upper boundary of each region.
185+
* The lower boundary is defined by the previous region's upper boundary.
186+
*/
187+
#define CSR_PMPADDR0 0x3b0
188+
#define CSR_PMPADDR1 0x3b1
189+
#define CSR_PMPADDR2 0x3b2
190+
#define CSR_PMPADDR3 0x3b3
191+
#define CSR_PMPADDR4 0x3b4
192+
#define CSR_PMPADDR5 0x3b5
193+
#define CSR_PMPADDR6 0x3b6
194+
#define CSR_PMPADDR7 0x3b7
195+
#define CSR_PMPADDR8 0x3b8
196+
#define CSR_PMPADDR9 0x3b9
197+
#define CSR_PMPADDR10 0x3ba
198+
#define CSR_PMPADDR11 0x3bb
199+
#define CSR_PMPADDR12 0x3bc
200+
#define CSR_PMPADDR13 0x3bd
201+
#define CSR_PMPADDR14 0x3be
202+
#define CSR_PMPADDR15 0x3bf
203+
204+
/* PMP Configuration Registers (pmpcfg0-pmpcfg3)
205+
* Each configuration register controls 4 PMP regions (on RV32).
206+
* pmpcfg0 controls pmpaddr0-3, pmpcfg1 controls pmpaddr4-7, etc.
207+
*/
208+
#define CSR_PMPCFG0 0x3a0
209+
#define CSR_PMPCFG1 0x3a1
210+
#define CSR_PMPCFG2 0x3a2
211+
#define CSR_PMPCFG3 0x3a3
212+
213+
/* PMP Configuration Field Bits (8 bits per region within pmpcfg)
214+
* Layout in each byte of pmpcfg:
215+
* Bit 7: L (Lock) - Locks this region until hardware reset
216+
* Bits 6-5: Reserved
217+
* Bits 4-3: A (Address Matching Mode)
218+
* Bit 2: X (Execute permission)
219+
* Bit 1: W (Write permission)
220+
* Bit 0: R (Read permission)
221+
*/
222+
223+
/* Lock bit: Prevents further modification of this region */
224+
#define PMPCFG_L (1U << 7)
225+
226+
/* Address Matching Mode (bits 3-4)
227+
* Choose TOR mode for no alignment requirements on region sizes, and support
228+
* for arbitrary address ranges.
229+
*/
230+
#define PMPCFG_A_SHIFT 3
231+
#define PMPCFG_A_MASK (0x3U << PMPCFG_A_SHIFT)
232+
#define PMPCFG_A_OFF (0x0U << PMPCFG_A_SHIFT) /* Null region (disabled) */
233+
#define PMPCFG_A_TOR (0x1U << PMPCFG_A_SHIFT) /* Top-of-Range mode */
234+
235+
/* Permission bits */
236+
#define PMPCFG_X (1U << 2) /* Execute permission */
237+
#define PMPCFG_W (1U << 1) /* Write permission */
238+
#define PMPCFG_R (1U << 0) /* Read permission */
239+
240+
/* Common permission combinations */
241+
#define PMPCFG_PERM_NONE (0x0U) /* No access */
242+
#define PMPCFG_PERM_R (PMPCFG_R) /* Read-only */
243+
#define PMPCFG_PERM_RW (PMPCFG_R | PMPCFG_W) /* Read-Write */
244+
#define PMPCFG_PERM_X (PMPCFG_X) /* Execute-only */
245+
#define PMPCFG_PERM_RX (PMPCFG_R | PMPCFG_X) /* Read-Execute */
246+
#define PMPCFG_PERM_RWX (PMPCFG_R | PMPCFG_W | PMPCFG_X) /* All access */
247+
248+
/* Utility macros for PMP configuration manipulation */
249+
250+
/* Extract PMP address matching mode */
251+
#define PMPCFG_GET_A(cfg) (((cfg) & PMPCFG_A_MASK) >> PMPCFG_A_SHIFT)
252+
253+
/* Extract permission bits from configuration byte */
254+
#define PMPCFG_GET_PERM(cfg) ((cfg) & (PMPCFG_R | PMPCFG_W | PMPCFG_X))
255+
256+
/* Check if region is locked */
257+
#define PMPCFG_IS_LOCKED(cfg) (((cfg) & PMPCFG_L) != 0)
258+
259+
/* Check if region is enabled (address mode is not OFF) */
260+
#define PMPCFG_IS_ENABLED(cfg) (PMPCFG_GET_A(cfg) != PMPCFG_A_OFF)

arch/riscv/hal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,8 @@ void hal_cpu_idle(void);
110110

111111
/* Default stack size for new tasks if not otherwise specified */
112112
#define DEFAULT_STACK_SIZE 4096
113+
114+
/* Physical Memory Protection (PMP) region limit constants */
115+
#define PMP_MAX_REGIONS 16 /* RISC-V supports 16 PMP regions */
116+
#define PMP_TOR_PAIRS 8 /* In TOR mode, 16 regions = 8 pairs (uses 2 addrs each) */
117+
#define MIN_PMP_REGION_SIZE 4 /* Minimum addressable size in TOR mode (4 bytes) */

arch/riscv/pmp.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* RISC-V Physical Memory Protection (PMP) Hardware Layer
2+
*
3+
* Low-level interface to RISC-V PMP using TOR (Top-of-Range) mode for
4+
* flexible region management without alignment constraints.
5+
*/
6+
7+
#pragma once
8+
9+
#include <types.h>
10+
11+
/* PMP Region Priority Levels (lower value = higher priority)
12+
*
13+
* Used for eviction decisions when hardware PMP regions are exhausted.
14+
*/
15+
typedef enum {
16+
PMP_PRIORITY_KERNEL = 0,
17+
PMP_PRIORITY_STACK = 1,
18+
PMP_PRIORITY_SHARED = 2,
19+
PMP_PRIORITY_TEMPORARY = 3,
20+
PMP_PRIORITY_COUNT = 4
21+
} pmp_priority_t;
22+
23+
/* PMP Region Configuration */
24+
typedef struct {
25+
uint32_t addr_start; /* Start address (inclusive) */
26+
uint32_t addr_end; /* End address (exclusive, written to pmpaddr) */
27+
uint8_t permissions; /* R/W/X bits (PMPCFG_R | PMPCFG_W | PMPCFG_X) */
28+
pmp_priority_t priority; /* Eviction priority */
29+
uint8_t region_id; /* Hardware region index (0-15) */
30+
uint8_t locked; /* Lock bit (cannot modify until reset) */
31+
} pmp_region_t;
32+
33+
/* PMP Global State */
34+
typedef struct {
35+
pmp_region_t regions[PMP_MAX_REGIONS]; /* Shadow of hardware config */
36+
uint8_t region_count; /* Active region count */
37+
uint8_t next_region_idx; /* Next free region index */
38+
uint32_t initialized; /* Initialization flag */
39+
} pmp_config_t;
40+
41+
/* PMP Management Functions */
42+
43+
/* Initializes the PMP hardware and configuration state.
44+
* @config : Pointer to pmp_config_t structure to be initialized.
45+
* Returns 0 on success, or negative error code on failure.
46+
*/
47+
int32_t pmp_init(pmp_config_t *config);
48+
49+
/* Configures a single PMP region in TOR mode.
50+
* @config : Pointer to PMP configuration state
51+
* @region : Pointer to pmp_region_t structure with desired configuration
52+
* Returns 0 on success, or negative error code on failure.
53+
*/
54+
int32_t pmp_set_region(pmp_config_t *config, const pmp_region_t *region);
55+
56+
/* Reads the current configuration of a PMP region.
57+
* @config : Pointer to PMP configuration state
58+
* @region_idx : Index of the region to read (0-15)
59+
* @region : Pointer to pmp_region_t to store the result
60+
* Returns 0 on success, or negative error code on failure.
61+
*/
62+
int32_t pmp_get_region(const pmp_config_t *config, uint8_t region_idx,
63+
pmp_region_t *region);
64+
65+
/* Disables a PMP region.
66+
* @config : Pointer to PMP configuration state
67+
* @region_idx : Index of the region to disable (0-15)
68+
* Returns 0 on success, or negative error code on failure.
69+
*/
70+
int32_t pmp_disable_region(pmp_config_t *config, uint8_t region_idx);
71+
72+
/* Locks a PMP region to prevent further modification.
73+
* @config : Pointer to PMP configuration state
74+
* @region_idx : Index of the region to lock (0-15)
75+
* Returns 0 on success, or negative error code on failure.
76+
*/
77+
int32_t pmp_lock_region(pmp_config_t *config, uint8_t region_idx);
78+
79+
/* Verifies that a memory access is allowed by the current PMP configuration.
80+
* @config : Pointer to PMP configuration state
81+
* @addr : Address to check
82+
* @size : Size of the access in bytes
83+
* @is_write : 1 for write access, 0 for read access
84+
* @is_execute : 1 for execute access, 0 for data access
85+
* Returns 1 if access is allowed, 0 if denied, or negative error code.
86+
*/
87+
int32_t pmp_check_access(const pmp_config_t *config, uint32_t addr,
88+
uint32_t size, uint8_t is_write, uint8_t is_execute);

include/private/error.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ enum {
2929
ERR_STACK_CHECK, /* Stack overflow or corruption detected */
3030
ERR_HEAP_CORRUPT, /* Heap corruption or invalid free detected */
3131

32+
/* PMP Configuration Errors */
33+
ERR_PMP_INVALID_REGION, /* Invalid PMP region parameters */
34+
ERR_PMP_NO_REGIONS, /* No free PMP regions available */
35+
ERR_PMP_LOCKED, /* Region is locked by higher priority */
36+
ERR_PMP_SIZE_MISMATCH, /* Size doesn't meet alignment requirements */
37+
ERR_PMP_ADDR_RANGE, /* Address range is invalid */
38+
ERR_PMP_NOT_INIT, /* PMP not initialized */
39+
3240
/* IPC and Synchronization Errors */
3341
ERR_PIPE_ALLOC, /* Pipe allocation failed */
3442
ERR_PIPE_DEALLOC, /* Pipe deallocation failed */

0 commit comments

Comments
 (0)