物理内存保护 (PMP)
概述
物理内存保护 (Physical Memory Protection,PMP) 是 RISC-V 提供的一个组件,用于保护内存区域,防止非法访问。和 MPU 不同的是,PMP 只能控制 R/W/X 权限,而不能控制缓存属性。
支持 16 个 PMP 条目,且只能在 M-Mode 下配置
KR4 限制 PMP 区域大小至少为 1KB 对齐
多个 PMP 区间重叠时,编号较小的 PMP 条目优先生效
PMP 未配置的区域默认为 M-Mode 可访问,S-Mode 和 U-Mode 不可访问
PMP 已配置的区域:
S-Mode 和 U-Mode 下的访问受控;
PMP 配置寄存器没有锁定时,不检查 M-Mode 下的访问(KR4默认都运行在M-Mode);
PMP 配置寄存器锁定后,M-Mode 下的访问受控,只有reset后才能解锁;
缓存管理
KR4 的缓存属性由 MCCA (Cache Attribute Register) 控制,配置的区域大小必须是 512MB 的整数倍,启动后由 setupMMUTable()
函数配置成下表设定,不建议更改。
Address |
Cache |
---|---|
0x00000000 ~ 0x1FFFFFFFF |
Write-through, read-allocate |
0x20000000 ~ 0x3FFFFFFFF |
Write-Back, write-allocate, read-allocate |
0x40000000 ~ 0x5FFFFFFFF |
non-cacheable, non-mergeable |
0x60000000 ~ 0x7FFFFFFFF |
Write-Back, write-allocate, read-allocate |
0x80000000 ~ 0x9FFFFFFFF |
non-cacheable, non-mergeable |
0xA0000000 ~ 0xBFFFFFFFF |
non-cacheable, non-mergeable |
0xC0000000 ~ 0xDFFFFFFFF |
non-cacheable, non-mergeable |
0xE0000000 ~ 0xFFFFFFFFF |
non-cacheable, non-mergeable |
使用说明
pmpxcfg 和 pmpaddrx 一一对应,设置时需要注意 pmpcfgn 寄存器包含 4个 PMP 条目的配置,每个配置的格式如下:
Bit |
Symbol |
Description |
---|---|---|
[7] |
L |
Locking and Privilege Mode |
[6:5] |
Reserved |
|
[4:3] |
A |
Address Matching |
[2] |
X |
Execute Enable |
[1] |
W |
Write Enable |
[0] |
R |
Read Enable |
其中 Address Matching 表示以下几种模式:
取值为 0 时表示 OFF;
取值为 1 时表示 TOR (Top of Region),只定义结束地址,即 pmpaddrx = EndAddr >> 2;
如果 x == 0,表示 PMP 区域是 [0, EndAddr);
如果 x != 0,表示 PMP 区域是 [StartAddr, EndAddr),其中 pmpaddrx-1 = StartAddr >> 2,并且 pmpx-1cfg.A 可以是任意值;
取值为 2 时表示 NA4 (Next Address 4),这意味着 PMP 区域大小是 4 字节对齐,KR4不支持该模式;
取值为 3 时表示 NAPOT (Naturally Aligned Power of Two),PMP 区域是 [StartAddr, StartAddr + region_size),在这种情况下:
region_size = 8 * (2 ^ n),KR4 要求 n >= 7,即至少 1KB 对齐;
pmpxcfg.A = 3;
pmpaddrx = (StartAddr >> 2) | (2 ^ n - 1);
以 TOR 模式为例,想要禁止 [0, StartAddr) 区域的写权限时,配置 PMP 的代码如下:
u32 temp = __csr_read(pmpcfg0);
temp &= ~0xFF; /* 清除 pmp0cfg 寄存器的所有配置 */
temp |= 0x8d; /* L = 1,否则M-Mode下不检查,同时 W=0 禁止写入 */
__csr_write(pmpcfg0, temp);
__csr_write(pmpaddr0, StartAddr >> 2);