hdy 发表于 2025-5-26 23:38

RISC-V系列——内存页表详解


RISC-V 架构中的内存管理单元 (MMU) 负责将虚拟地址转换为物理地址,这一过程的核心机制就是页表转换。当启用了分页机制后,处理器不再直接访问物理内存,而是通过页表将程序使用的虚拟地址映射到实际的物理内存地址。
一、RISC-V 页表转换流程概述
RISC-V的页表转换是一个多级查找过程。它从一个特殊的控制状态寄存器(CSR)satp 开始,该寄存器指向顶级页表的基地址。处理器使用虚拟地址的不同部分作为索引,逐级查询页表,直到找到包含最终物理页号 (Physical Page Number, PPN) 的页表项 (Page Table Entry, PTE)。然后,将这个物理页号与虚拟地址中的页内偏移量组合,形成最终的物理地址。
二、关键组成部分:
1. satp (Supervisor Address Translation and Protection) 寄存器
satp 寄存器是页表转换的起点。它主要包含以下字段:

[*] MODE:用于选择和启用分页模式。例如,Bare (不进行转换),Sv32, Sv39, Sv48 等,分别对应不同的虚拟地址和物理地址空间大小以及页表级数。
[*]ASID (Address Space Identifier):地址空间标识符,用于区分不同进程的地址空间,使得 TLB (稍后介绍) 可以缓存不同进程的转换条目而不会混淆。
[*]PPN (Physical Page Number):存放根页表(第一级页表)的物理页号。物理地址是通过将此 PPN 左移页大小对应的位数(通常是 12 位,即乘以 4096)得到的。

2. 虚拟地址 (Virtual Address, VA) 结构
一个虚拟地址通常被划分为以下几个部分:

[*] VPN (Virtual Page Number) segments:虚拟页号。根据所选的分页模式 (如 Sv39),VPN 会被进一步划分为多个段,每个段用作一级页表的索引。例如,在 Sv39 模式下,虚拟地址高 39 位是虚拟页号,被分为三段 9 位长的 VPN (VPN, VPN, VPN)。
[*]Page Offset:页内偏移量。通常是虚拟地址的低 12 位 (对于 4KB 的页面大小),它直接用于最终物理地址的低位,表示在目标物理页内的具体字节位置。

3. 页表项 (Page Table Entry, PTE)
页表由一系列页表项组成。每个 PTE 包含以下关键信息:

[*] PPN (Physical Page Number):指向下一级页表或最终数据页的物理页号。
[*]Permission Bits:
    * V (Valid): PTE 是否有效。如果为 0,访问该 PTE 会产生页错误 (PageFault)。
    * R (Read): 是否允许读取。
    * W (Write): 是否允许写入。
    * X (Execute): 是否允许执行。
    * U (User): 是否允许用户模式访问。如果为 0,只有监管者模式 (Supervisor mode) 可以访问。
    * G (Global): 全局映射标记。
    * A (Accessed): 访问位,表示该页最近是否被访问过。由硬件设置,操作系统可以清除。
    * D (Dirty): 脏位,表示该页最近是否被写入过。由硬件设置,操作系统可以清除。
[*]PTE Type:指示该 PTE 是指向下一级页表 (中间节点) 还是指向一个物理页 (叶节点)。如果 R, W, X 位均为 0,则该 PTE 是一个指向下一级页表的指针;否则,它是一个叶节点 PTE,其 PPN 字段直接指向最终的物理页。

三、页表转换步骤 (以 Sv39 为例)
Sv39 使用三级页表结构,页面大小通常为 4KB。
1. 获取根页表基地址:

[*]处理器从 satp 寄存器的 PPN 字段获取根页表 (L2 页表,因为 Sv39 的索引从 2 开始) 的物理页号。
[*]将此 PPN 左移 12 位 (乘以 4096) 得到根页表的物理基地址。

2. 第一级查找 (L2 页表):

[*] 取出虚拟地址中的 VPN (通常是 VA) 作为 L2 页表的索引。
[*]计算 L2 PTE 的物理地址:L2_table_base_address + VPN * PTE_size (PTE 大小在 64 位系统中通常是 8 字节)。
[*]读取该 L2 PTE。

3. 检查 L2 PTE:

[*]检查 PTE 的 V (Valid) 位。如果无效,或权限不足 (如试图写入只读页),则触发页错误异常。
[*]如果 L2 PTE 是一个叶节点 (不常见于 L2,除非使用大页/巨页),则其 PPN 直接指向物理页。转换结束。

[*]如果 L2 PTE 指向下一级页表 (L1 页表),则取出其 PPN 字段。

4. 第二级查找 (L1 页表):


[*]将 L2 PTE 中的 PPN 左移 12 位,得到 L1 页表的物理基地址。

[*]取出虚拟地址中的 VPN (通常是 VA) 作为 L1 页表的索引。
[*]计算 L1 PTE 的物理地址:L1_table_base_address + VPN * PTE_size。
[*]读取该 L1 PTE。

5. 检查 L1 PTE:

[*]类似地检查 L1 PTE 的有效性和权限位,以及它是否是叶节点。
[*]如果 L1 PTE 指向下一级页表 (L0 页表),则取出其 PPN 字段。

6. 第三级查找 (L0 页表):


[*]将 L1 PTE 中的 PPN 左移 12 位,得到 L0 页表的物理基地址。
[*]取出虚拟地址中的 VPN (通常是 VA) 作为 L0 页表的索引。
[*]计算 L0 PTE 的物理地址:L0_table_base_address + VPN * PTE_size。
[*] 读取该 L0 PTE。

7. 检查 L0 PTE (叶节点 PTE):


[*]L0 PTE 必须是一个叶节点 PTE。检查其有效性和权限位。
[*]如果有效且权限允许,则 L0 PTE 中的 PPN 字段就是目标数据页的物理页号。

8. 形成最终物理地址 (Physical Address, PA):


[*]将从叶节点 PTE 中获得的 PPN 左移 12 位。
[*]将虚拟地址中的页内偏移量 (VA) 加到上述结果上。
[*]PA = (Leaf_PTE.PPN << 12) | Page_Offset

不同分页模式:


[*]Sv32: 通常使用两级页表。虚拟地址 32 位,VPN 分为 VPN (10 位) 和 VPN (10 位)。
[*]Sv48: 使用四级页表。
[*]Sv57 (未来可能): 使用五级页表。

转换过程的级数和每级 VPN 的位数会根据所选模式变化,但基本原理(逐级索引、检查 PTE、获取下一级或最终 PPN)是相同的。

四、TLB (Translation Lookaside Buffer) 的作用
由于每次内存访问都进行多级页表查询会非常耗时,RISC-V 处理器(像其他现代处理器一样)使用 TLB (旁路转换缓冲) 来缓存最近使用过的虚拟页号到物理页号的映射。


[*]当需要进行地址转换时,处理器首先在 TLB 中查找该虚拟页号。

[*]TLB 命中 (Hit): 如果在 TLB 中找到了有效的映射,则直接使用该物理页号,跳过耗时的页表遍历过程。
[*]TLB 未命中 (Miss): 如果 TLB 中没有对应的映射,处理器才会执行上述的页表遍历(硬件页表遍历器),并将找到的映射存入 TLB 中以备后用。

当操作系统修改了页表内容(例如,页面换出、权限更改)时,需要确保 TLB 中可能存在的旧的、无效的映射被清除。RISC-V 提供了 sfence.vma 指令来刷新 TLB 条目,以保证地址转换的一致性。

总结来说,RISC-V 的页表转换是一个由 satp 寄存器启动,通过多级页表索引,最终由叶节点 PTE 提供物理页号,并结合页内偏移形成物理地址的过程。TLB 的存在极大地加速了这一转换过程。

页: [1]
查看完整版本: RISC-V系列——内存页表详解