物理内存保护 (PMP)

IC:

概述

物理内存保护 (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 表示以下几种模式:

  1. 取值为 0 时表示 OFF;

  2. 取值为 1 时表示 TOR (Top of Region),只定义结束地址,即 pmpaddrx = EndAddr >> 2;

    1. 如果 x == 0,表示 PMP 区域是 [0, EndAddr);

    2. 如果 x != 0,表示 PMP 区域是 [StartAddr, EndAddr),其中 pmpaddrx-1 = StartAddr >> 2,并且 pmpx-1cfg.A 可以是任意值;

  3. 取值为 2 时表示 NA4 (Next Address 4),这意味着 PMP 区域大小是 4 字节对齐,KR4不支持该模式;

  4. 取值为 3 时表示 NAPOT (Naturally Aligned Power of Two),PMP 区域是 [StartAddr, StartAddr + region_size),在这种情况下:

    1. region_size = 8 * (2 ^ n),KR4 要求 n >= 7,即至少 1KB 对齐;

    2. pmpxcfg.A = 3;

    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);