Skip to content

Commit 49ddd7d

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 ebc1697 commit 49ddd7d

File tree

3 files changed

+101
-1
lines changed

3 files changed

+101
-1
lines changed

arch/riscv/build.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ OBJ = $(CROSS_COMPILE)objcopy
3939
SIZE = $(CROSS_COMPILE)size
4040
AR = $(CROSS_COMPILE)ar
4141

42-
HAL_OBJS := boot.o hal.o muldiv.o
42+
HAL_OBJS := boot.o hal.o muldiv.o pmp.o
4343
HAL_OBJS := $(addprefix $(BUILD_KERNEL_DIR)/,$(HAL_OBJS))
4444
deps += $(HAL_OBJS:%.o=%.o.d)
4545

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: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,87 @@
77
#include <sys/memprot.h>
88
#include "csr.h"
99
#include "pmp.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: return read_csr_num(CSR_PMPCFG0);
27+
case 1: return read_csr_num(CSR_PMPCFG1);
28+
case 2: return read_csr_num(CSR_PMPCFG2);
29+
case 3: return read_csr_num(CSR_PMPCFG3);
30+
default: return 0;
31+
}
32+
}
33+
34+
/* Write PMP configuration register by index (0-3) */
35+
static void write_pmpcfg(uint8_t idx, uint32_t val)
36+
{
37+
switch (idx) {
38+
case 0: write_csr_num(CSR_PMPCFG0, val); break;
39+
case 1: write_csr_num(CSR_PMPCFG1, val); break;
40+
case 2: write_csr_num(CSR_PMPCFG2, val); break;
41+
case 3: write_csr_num(CSR_PMPCFG3, val); break;
42+
}
43+
}
44+
45+
/* Read PMP address register by index (0-15) */
46+
static uint32_t read_pmpaddr(uint8_t idx)
47+
{
48+
switch (idx) {
49+
case 0: return read_csr_num(CSR_PMPADDR0);
50+
case 1: return read_csr_num(CSR_PMPADDR1);
51+
case 2: return read_csr_num(CSR_PMPADDR2);
52+
case 3: return read_csr_num(CSR_PMPADDR3);
53+
case 4: return read_csr_num(CSR_PMPADDR4);
54+
case 5: return read_csr_num(CSR_PMPADDR5);
55+
case 6: return read_csr_num(CSR_PMPADDR6);
56+
case 7: return read_csr_num(CSR_PMPADDR7);
57+
case 8: return read_csr_num(CSR_PMPADDR8);
58+
case 9: return read_csr_num(CSR_PMPADDR9);
59+
case 10: return read_csr_num(CSR_PMPADDR10);
60+
case 11: return read_csr_num(CSR_PMPADDR11);
61+
case 12: return read_csr_num(CSR_PMPADDR12);
62+
case 13: return read_csr_num(CSR_PMPADDR13);
63+
case 14: return read_csr_num(CSR_PMPADDR14);
64+
case 15: return read_csr_num(CSR_PMPADDR15);
65+
default: return 0;
66+
}
67+
}
68+
69+
/* Write PMP address register by index (0-15) */
70+
static void write_pmpaddr(uint8_t idx, uint32_t val)
71+
{
72+
switch (idx) {
73+
case 0: write_csr_num(CSR_PMPADDR0, val); break;
74+
case 1: write_csr_num(CSR_PMPADDR1, val); break;
75+
case 2: write_csr_num(CSR_PMPADDR2, val); break;
76+
case 3: write_csr_num(CSR_PMPADDR3, val); break;
77+
case 4: write_csr_num(CSR_PMPADDR4, val); break;
78+
case 5: write_csr_num(CSR_PMPADDR5, val); break;
79+
case 6: write_csr_num(CSR_PMPADDR6, val); break;
80+
case 7: write_csr_num(CSR_PMPADDR7, val); break;
81+
case 8: write_csr_num(CSR_PMPADDR8, val); break;
82+
case 9: write_csr_num(CSR_PMPADDR9, val); break;
83+
case 10: write_csr_num(CSR_PMPADDR10, val); break;
84+
case 11: write_csr_num(CSR_PMPADDR11, val); break;
85+
case 12: write_csr_num(CSR_PMPADDR12, val); break;
86+
case 13: write_csr_num(CSR_PMPADDR13, val); break;
87+
case 14: write_csr_num(CSR_PMPADDR14, val); break;
88+
case 15: write_csr_num(CSR_PMPADDR15, val); break;
89+
}
90+
}
1091

1192
/* Static Memory Pools for Boot-time PMP Initialization
1293
*

0 commit comments

Comments
 (0)