Skip to content

Commit b1528e5

Browse files
committed
Add PMP CSR access infrastructure
Provide helper functions for runtime-indexed access to PMP control and status registers alongside existing compile-time CSR macros. RISC-V CSR instructions encode register addresses as immediate values in the instruction itself, making dynamic selection impossible through simple arithmetic. These helpers use switch-case dispatch to map runtime indices to specific CSR instructions while preserving type safety. This enables PMP register management code to iterate over regions without knowing exact register numbers at compile-time, supporting features with multiple registers of the same type. PMP implementation is now included in the build system to make these helpers and future PMP functionality available at link time.
1 parent 694a40d commit b1528e5

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed

arch/riscv/build.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ LDFLAGS += --gc-sections
7070
ARFLAGS = r
7171
LDSCRIPT = $(ARCH_DIR)/riscv32-qemu.ld
7272

73-
HAL_OBJS := boot.o hal.o muldiv.o
73+
HAL_OBJS := boot.o hal.o muldiv.o pmp.o
7474
HAL_OBJS := $(addprefix $(BUILD_KERNEL_DIR)/,$(HAL_OBJS))
7575
deps += $(HAL_OBJS:%.o=%.o.d)
7676

arch/riscv/hal.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ extern uint32_t _stack_bottom, _stack_top; /* Bottom/top of the STACK memory */
2828
*/
2929
#define write_csr(reg, val) ({ asm volatile("csrw " #reg ", %0" ::"rK"(val)); })
3030

31+
/* Read CSR by numeric address (for dynamic register selection).
32+
* Used when CSR number is not known at compile-time (e.g., PMP registers).
33+
* @csr_num : CSR address as a compile-time constant.
34+
*/
35+
#define read_csr_num(csr_num) \
36+
({ \
37+
uint32_t __tmp; \
38+
asm volatile("csrr %0, %1" : "=r"(__tmp) : "i"(csr_num)); \
39+
__tmp; \
40+
})
41+
42+
/* Write CSR by numeric address (for dynamic register selection).
43+
* Used when CSR number is not known at compile-time (e.g., PMP registers).
44+
* @csr_num : CSR address as a compile-time constant.
45+
* @val : The 32-bit value to write.
46+
*/
47+
#define write_csr_num(csr_num, val) \
48+
({ asm volatile("csrw %0, %1" ::"i"(csr_num), "rK"(val)); })
49+
3150
/* Globally enable or disable machine-level interrupts by setting mstatus.MIE.
3251
* @enable : Non-zero to enable, zero to disable.
3352
* Returns the previous state of the interrupt enable bit (1 if enabled, 0 if

arch/riscv/pmp.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,149 @@
77
#include <hal.h>
88
#include <sys/memprot.h>
99
#include "csr.h"
10+
#include "private/error.h"
11+
12+
/* PMP CSR Access Helpers
13+
*
14+
* RISC-V CSR instructions require compile-time constant addresses encoded in
15+
* the instruction itself. These helpers use switch-case dispatch to provide
16+
* runtime indexed access to PMP configuration and address registers.
17+
*
18+
* - pmpcfg0-3: Four 32-bit configuration registers (16 regions, 8 bits each)
19+
* - pmpaddr0-15: Sixteen address registers for TOR (Top-of-Range) mode
20+
*/
21+
22+
/* Read PMP configuration register by index (0-3) */
23+
static uint32_t read_pmpcfg(uint8_t idx)
24+
{
25+
switch (idx) {
26+
case 0:
27+
return read_csr_num(CSR_PMPCFG0);
28+
case 1:
29+
return read_csr_num(CSR_PMPCFG1);
30+
case 2:
31+
return read_csr_num(CSR_PMPCFG2);
32+
case 3:
33+
return read_csr_num(CSR_PMPCFG3);
34+
default:
35+
return 0;
36+
}
37+
}
38+
39+
/* Write PMP configuration register by index (0-3) */
40+
static void write_pmpcfg(uint8_t idx, uint32_t val)
41+
{
42+
switch (idx) {
43+
case 0:
44+
write_csr_num(CSR_PMPCFG0, val);
45+
break;
46+
case 1:
47+
write_csr_num(CSR_PMPCFG1, val);
48+
break;
49+
case 2:
50+
write_csr_num(CSR_PMPCFG2, val);
51+
break;
52+
case 3:
53+
write_csr_num(CSR_PMPCFG3, val);
54+
break;
55+
}
56+
}
57+
58+
/* Read PMP address register by index (0-15) */
59+
static uint32_t read_pmpaddr(uint8_t idx)
60+
{
61+
switch (idx) {
62+
case 0:
63+
return read_csr_num(CSR_PMPADDR0);
64+
case 1:
65+
return read_csr_num(CSR_PMPADDR1);
66+
case 2:
67+
return read_csr_num(CSR_PMPADDR2);
68+
case 3:
69+
return read_csr_num(CSR_PMPADDR3);
70+
case 4:
71+
return read_csr_num(CSR_PMPADDR4);
72+
case 5:
73+
return read_csr_num(CSR_PMPADDR5);
74+
case 6:
75+
return read_csr_num(CSR_PMPADDR6);
76+
case 7:
77+
return read_csr_num(CSR_PMPADDR7);
78+
case 8:
79+
return read_csr_num(CSR_PMPADDR8);
80+
case 9:
81+
return read_csr_num(CSR_PMPADDR9);
82+
case 10:
83+
return read_csr_num(CSR_PMPADDR10);
84+
case 11:
85+
return read_csr_num(CSR_PMPADDR11);
86+
case 12:
87+
return read_csr_num(CSR_PMPADDR12);
88+
case 13:
89+
return read_csr_num(CSR_PMPADDR13);
90+
case 14:
91+
return read_csr_num(CSR_PMPADDR14);
92+
case 15:
93+
return read_csr_num(CSR_PMPADDR15);
94+
default:
95+
return 0;
96+
}
97+
}
98+
99+
/* Write PMP address register by index (0-15) */
100+
static void write_pmpaddr(uint8_t idx, uint32_t val)
101+
{
102+
switch (idx) {
103+
case 0:
104+
write_csr_num(CSR_PMPADDR0, val);
105+
break;
106+
case 1:
107+
write_csr_num(CSR_PMPADDR1, val);
108+
break;
109+
case 2:
110+
write_csr_num(CSR_PMPADDR2, val);
111+
break;
112+
case 3:
113+
write_csr_num(CSR_PMPADDR3, val);
114+
break;
115+
case 4:
116+
write_csr_num(CSR_PMPADDR4, val);
117+
break;
118+
case 5:
119+
write_csr_num(CSR_PMPADDR5, val);
120+
break;
121+
case 6:
122+
write_csr_num(CSR_PMPADDR6, val);
123+
break;
124+
case 7:
125+
write_csr_num(CSR_PMPADDR7, val);
126+
break;
127+
case 8:
128+
write_csr_num(CSR_PMPADDR8, val);
129+
break;
130+
case 9:
131+
write_csr_num(CSR_PMPADDR9, val);
132+
break;
133+
case 10:
134+
write_csr_num(CSR_PMPADDR10, val);
135+
break;
136+
case 11:
137+
write_csr_num(CSR_PMPADDR11, val);
138+
break;
139+
case 12:
140+
write_csr_num(CSR_PMPADDR12, val);
141+
break;
142+
case 13:
143+
write_csr_num(CSR_PMPADDR13, val);
144+
break;
145+
case 14:
146+
write_csr_num(CSR_PMPADDR14, val);
147+
break;
148+
case 15:
149+
write_csr_num(CSR_PMPADDR15, val);
150+
break;
151+
}
152+
}
10153

11154
/* Static Memory Pools for Boot-time PMP Initialization
12155
*

0 commit comments

Comments
 (0)