计算机体系结构 20:Sv32、TLB 与权限

核心问题

第 16 到第 19 篇把数据缓存看成“物理地址进入缓存后发生什么”。这一篇补上物理地址之前的一段:一个 load、store 或取指给出的地址通常先是虚拟地址,处理器要用页表把它翻译成物理地址,再把结果交给后续缓存层级。

本篇只回答一个问题:在 RISC-V Sv32 下,TLB miss、page fault 和 data cache miss 为什么是三件不同的事。

这三个词常被混在一起:

  • TLB miss:地址翻译缓存没有现成条目,需要查页表。
  • page fault:页表项或权限检查不允许这次访问,需要陷入软件处理。
  • data cache miss:已经得到物理地址后,数据缓存里没有对应数据块。

一个有效翻译可以 TLB miss,但不 page fault。一次 TLB hit 也可以 data cache miss。反过来,page fault 发生时,数据访问还没有资格进入数据缓存模型。

这里的关键模式是先分清“名字缓存”和“数据缓存”。TLB 缓存的是虚拟页到物理页的翻译和权限信息;data cache 缓存的是物理地址对应的数据块。两个结构都叫 cache,但缓存对象不同,缺失含义也不同。

边界

本文使用 RISC-V Privileged Architecture 的 Sv32 规则作一手依据。2026-09-22 通过可读官方 supervisor 页面核对到 Supervisor-Level ISA 1.13;固定版本 URL 当前不可直接读取,因此正文引用可读官方 URL,不把固定版本 URL 当作本轮已访问证据。规范说明:Sv32 虚拟地址由 20 位 VPN 和 12 位页内偏移组成,经过两级页表把 VPN 翻译成 22 位 PPN,12 位页内偏移保持不变;satp 选择地址翻译模式并给出根页表 PPN;规范允许实现缓存地址翻译,但不规定 TLB 容量、替换策略或命中延迟。

本文的执行证据来自一个有限 Python 模型:

sv32_model.py

输出附件:

sv32_trace.jsonsv32_model_stdout.json

从仓库根目录复跑:

1
python3 examples/computer-architecture/translation/src/sv32_model.py

证据等级:功能执行。

它不是真实 RISC-V hart、不是 Linux 内核页故障记录、不是硬件 TLB 采样,也不是硬件数据缓存采样。模型只覆盖本文用到的 Sv32 小页、一个合法 4 MiB 大页、S/U 权限、SUM 的一部分行为、TLB 条目权限重查,以及一个微型 data cache。MXR、ASID、全局页、PMP、硬件 A/D 位更新和并发页表遍历竞态不在本文证据范围内。

Sv32 地址怎样拆开

取虚拟地址:

1
VA = 0x00401234

Sv32 使用 4 KiB 页。低 12 位是页内偏移:

1
2
3
4
offset = 0x234
VPN = VA >> 12 = 0x401
VPN[1] = 1
VPN[0] = 1

模型设置根页表中 VPN[1]=1 的项指向二级页表 PPN 0x200。因为 PTE 大小是 4 字节,二级页表中 VPN[0]=1 的 PTE 地址为:

1
2
L0 PTE address = 0x200 * 4096 + 1 * 4
= 0x200004

这个叶子 PTE 的 PPN 是 0x300,权限是 R|W,并且 V/A/D 已置位。得到的物理地址是:

1
2
PA = 0x300 * 4096 + 0x234
= 0x300234

输出里对应事件是:

1
2
3
4
5
6
7
8
{
"event": "tlb_miss_page_walk",
"va": "0x401234",
"pte_addresses": ["root + 1 * 4", "0x200004"],
"pte": "0xc00c7",
"pa": "0x300234",
"page_bytes": 4096
}

这里发生的是 TLB miss,不是 page fault。页表项有效,权限允许 S 模式 load,翻译能完成。

判断一次地址访问时,先问“页表是否允许”,再问“缓存是否命中”。不要把“需要查表”误判成“不能访问”。

TLB miss 后还能 data cache miss

同一次访问在翻译完成后才进入数据缓存。模型给同一条访问接了一个很小的 data cache:

1
2
3
4
5
6
7
{
"event": "data_cache_miss",
"label": "first_load_after_tlb_miss",
"pa": "0x300234",
"line_bytes": 64,
"tag": "0xc008"
}

第二次访问同一虚拟地址时,TLB 先命中:

1
2
3
4
5
6
{
"event": "tlb_hit",
"va": "0x401234",
"pa": "0x300234",
"page_bytes": 4096
}

然后同一物理 cache line 在 data cache 中命中:

1
2
3
4
5
{
"event": "data_cache_hit",
"label": "second_load_after_tlb_hit",
"pa": "0x300234"
}

这四个事件说明了两个独立层次:

次数 翻译层 数据层
第一次 TLB miss,页表遍历成功 data cache miss
第二次 TLB hit data cache hit

这不意味着 TLB hit 总会带来 data cache hit。这里只是访问了同一个物理 cache line。换一个已翻译但从未进入 data cache 的物理地址,仍然可以出现 TLB hit + data cache miss。

权限在 TLB hit 时仍要成立

TLB 条目不能只缓存 PPN。它还必须带着足以判断权限的信息,或者命中后能用等价方式重新检查权限。否则会出现一种危险错误:S 模式先访问 supervisor-only 页,把条目装进 TLB;随后 U 模式访问同一 VA,如果实现只看 VPN 命中就直接返回 PA,U 模式就绕过了权限。

模型把这个错误显式堵住:TLB hit 时仍按当前 mode、access 与 SUM 检查权限。

输出里先有 S 模式 load 成功,再有 U 模式访问同一页失败:

1
2
3
4
5
6
7
{
"event": "page_fault",
"scause": "load_page_fault",
"stval": "0x401234",
"reason": "user_to_supervisor_page",
"pte_address": "tlb_cached_pte"
}

pte_address 写成 tlb_cached_pte,表示这不是页表遍历中发现的 PTE 地址,而是 TLB 已缓存条目在当前权限语境下不再允许这次访问。

SUM 只影响 S 模式 load/store 访问 U 页,不允许 S 模式从 U 页取指。模型中的 U 页案例给出三种结果:

访问 结果
S load U 页,SUM=0 page fault
S load/store U 页,SUM=1 允许
S fetch U 页 page fault

缓存结果不能缓存掉安全上下文。只要权限依赖当前模式、访问类型或状态位,命中路径也必须保留等价检查。

大页是另一种叶子位置

Sv32 不只有 4 KiB 页。level-1 PTE 如果已经是叶子,可以表示 4 MiB superpage,但 PPN 的低 10 位必须满足对齐要求。模型实现了一个有限合法路径:

1
2
3
4
5
VA       = 0x01800040
VPN[1] = 6
L1 leaf = PPN 0x3800, R|W|X
PA = 0x3800040
page = 4194304 bytes

输出事件:

1
2
3
4
5
6
7
{
"event": "tlb_miss_superpage_walk",
"va": "0x1800040",
"vpn1": "0x6",
"pa": "0x3800040",
"page_bytes": 4194304
}

随后访问同一个 4 MiB 范围内的 0x01802040,TLB 命中同一个 superpage 条目:

1
2
3
4
5
6
{
"event": "tlb_hit",
"va": "0x1802040",
"pa": "0x3802040",
"page_bytes": 4194304
}

这里不能把“模型没写大页”伪装成硬件 page fault。硬件规范允许合法大页;如果教学模型不支持,应该报告模型能力不足。当前版本选择实现这个有限合法路径,并只在 misaligned superpage 时返回故障。

本篇验收

  • 能从 0x00401234 手算 VPN[1]VPN[0]、offset、PTE 地址和最终 PA。
  • 能解释 TLB miss、page fault、data cache miss 的不同含义。
  • 能指出 TLB hit 仍需要权限检查,不能让 U 模式复用 S 模式 supervisor 页命中。
  • 能说明 SUM 对 S 模式访问 U 页的边界:load/store 与 fetch 不同。
  • 能给出 4 MiB superpage 的对齐要求和本文的有限实现范围。

练习

练习 1

给定 VA=0x00401234,页表设置与本文相同。写出 VPN[1]VPN[0]、offset、L0 PTE 地址和 PA。

答案:

1
2
3
4
5
VPN[1] = 1
VPN[0] = 1
offset = 0x234
L0 PTE address = 0x200004
PA = 0x300234

练习 2

如果 S 模式先 load 一个 supervisor-only 页并填入 TLB,随后 U 模式 load 同一 VA,能否直接使用 TLB 命中的 PPN?

答案:不能。TLB hit 只说明找到了翻译条目,不说明当前权限允许访问。命中路径仍要检查 PTE 的 U 位、当前 privilege mode 和访问类型。本文模型输出 user_to_supervisor_page,并把地址来源标为 tlb_cached_pte

参考资料