3. 页表项(PTE)结构详解

页表项(Page Table Entry, PTE)是页表的核心数据单元,它记录了虚拟页号(VPN)到物理页号(PPN)的映射关系以及页面的访问控制属性。在 RISC-V Sv39 分页机制中,每个 PTE 占用 64 位(8 字节),其结构清晰划分为两个主要部分:高 54 位的物理页号(PPN)和低 10 位的标志位(Flags)。

关键概念:PTE 是 MMU 进行地址转换的唯一依据。当 CPU 访问虚拟地址时,MMU 逐级遍历页表,读取每一级的 PTE,最终通过叶子节点的 PTE 中的 PPN 拼接偏移量得到物理地址。

3.1 PTE 整体位布局

下表展示了 RISC-V Sv39 中一个 64 位 PTE 的完整位域划分。位编号从 0(最低位)到 63(最高位)。

位域 位范围 宽度 名称 描述
Flags 9:0 10 V, R, W, X, U, G, A, D, RSW 页表项的控制与状态标志位
PPN[0] 18:10 9 物理页号第 0 部分 物理地址的 12-20 位
PPN[1] 27:19 9 物理页号第 1 部分 物理地址的 21-29 位
PPN[2] 53:28 26 物理页号第 2 部分 物理地址的 30-55 位
保留 63:54 10 — 保留位,必须为 0
Sv39 地址空间限制:虽然 PTE 的 PPN 字段总宽度为 9+9+26 = 44 位,但 Sv39 模式下物理地址最大支持 56 位(PPN 实际使用 44 位 + 页内偏移 12 位 = 56 位)。高 10 位保留供未来扩展使用。

3.2 PPN(物理页号):63-10 位

PPN(Physical Page Number)是 PTE 中最重要的数据部分,它指向物理内存中的一个 4KB 页面的起始地址。PPN 被拆分为三个子段:PPN[0]、PPN[1] 和 PPN[2],这种拆分方式与多级页表的索引机制完全对应。

  • PPN[2](位 53:28):最高 26 位,对应物理地址的 30-55 位。
  • PPN[1](位 27:19):中间 9 位,对应物理地址的 21-29 位。
  • PPN[0](位 18:10):最低 9 位,对应物理地址的 12-20 位。

当 MMU 完成地址转换时,会将 PPN 与虚拟地址中的页内偏移(12 位)拼接,形成最终的物理地址:物理地址 = {PPN[2], PPN[1], PPN[0], offset[11:0]}。

PTE 64 位结构布局 Flags (10 bit) PPN[0] (9) PPN[1] (9) PPN[2] (26) 保留 (10) 0 10 19 28 54 63 物理地址 = PPN[2] (30-55) | PPN[1] (21-29) | PPN[0] (12-20) | offset (0-11) PPN 总宽度 = 26 + 9 + 9 = 44 位,支持最大 2^56 字节物理地址空间

3.3 Flags(标志位):8-0 位

PTE 的低 10 位是标志位,它们控制着页面的访问权限、缓存策略和状态信息。这些标志位是操作系统实现虚拟内存管理、进程隔离和页面置换的基础。

位 名称 全称 含义与作用
0 V Valid 有效位。V=1 表示该 PTE 有效,MMU 可以使用;V=0 表示无效,访问将触发页错误。
1 R Readable 可读位。R=1 允许读取该页面;R=0 禁止读取。
2 W Writable 可写位。W=1 允许写入该页面;W=0 禁止写入。
3 X Executable 可执行位。X=1 允许从该页面取指令执行;X=0 禁止执行。
4 U User 用户模式位。U=1 表示用户态(U-mode)可以访问;U=0 表示仅超级用户态(S-mode)可访问。
5 G Global 全局位。G=1 表示该映射是全局的,在 TLB 刷新时不会被 sfence.vma 指令清除(除非指定了 ASID)。
6 A Accessed 访问位。由硬件自动置 1,表示该页面已被访问过(读或写)。操作系统可用来实现页面置换算法(如 LRU 近似)。
7 D Dirty 脏位。由硬件自动置 1,表示该页面已被写入过。操作系统在页面换出时需要将脏页面写回磁盘。
8 RSW Reserved for Supervisor 保留给操作系统使用。xv6 未使用该位,但其他操作系统可用来存储自定义元数据。
9 RSW Reserved for Supervisor 同上,保留给操作系统软件使用。
权限组合规则:R、W、X 三位不能同时为 0(即 R=0, W=0, X=0 是非法的)。这种组合被 MMU 解释为指向下一级页表的指针(非叶子节点),而非最终的页面映射。叶子节点的 PTE 必须至少设置 R 或 X 中的一位。

3.4 权限位组合与页表层级

MMU 通过检查 R、W、X 的组合来判断当前 PTE 是叶子节点还是非叶子节点(指向下一级页表)。这是多级页表遍历的核心判断逻辑。

  • 叶子节点(Leaf PTE):当 R=1 或 X=1 时,该 PTE 是叶子节点,PPN 直接指向物理页面。此时 W 和 U 位决定具体的访问权限。
  • 非叶子节点(Non-leaf PTE):当 R=0, W=0, X=0 时,该 PTE 是中间节点,PPN 指向下一级页表的物理地址。此时 V 位必须为 1,其他权限位被忽略。
PTE 类型判断:叶子节点 vs 非叶子节点 读取 PTE V=1? 页错误 R=1 或 X=1? 叶子节点(映射) 非叶子节点(下一级)

3.5 xv6 中的 PTE 宏定义

在 xv6 源码的 riscv.h 文件中,PTE 的标志位被定义为宏常量,方便内核代码进行位操作。以下是 xv6 中与 PTE 相关的关键定义:

// 页表项标志位定义 (riscv.h)
#define PTE_V      (1L << 0)   // Valid
#define PTE_R      (1L << 1)   // Readable
#define PTE_W      (1L << 2)   // Writable
#define PTE_X      (1L << 3)   // Executable
#define PTE_U      (1L << 4)   // User
#define PTE_G      (1L << 5)   // Global
#define PTE_A      (1L << 6)   // Accessed
#define PTE_D      (1L << 7)   // Dirty

// 从 PTE 中提取 PPN 的掩码
#define PTE2PA(pte) (((pte) >> 10) << 12)

// 从物理地址构造 PTE
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
宏解析:PTE2PA(pte) 先将 PTE 右移 10 位去掉标志位,再左移 12 位得到物理地址(因为 PPN 是物理页号,需要左移 12 位得到页基址)。PA2PTE(pa) 是逆操作,将物理地址右移 12 位得到 PPN,再左移 10 位放入 PTE 的 PPN 字段。

3.6 A/D 位与硬件辅助的页面管理

Accessed(A)和 Dirty(D)位由 RISC-V 硬件自动维护,为操作系统提供了高效的页面使用统计能力,无需软件模拟。

  • A 位(Accessed):当 MMU 对某个页面进行读或写访问时,硬件会自动将该页面对应 PTE 的 A 位置 1。操作系统可以周期性地扫描页表,检查 A 位来判断页面是否被使用过,用于实现页面置换算法(如 Clock 算法)。
  • D 位(Dirty):当 MMU 对某个页面进行写操作时,硬件会自动将 D 位置 1。操作系统在页面换出时,只需检查 D 位:如果 D=1,则需要将页面内容写回磁盘;如果 D=0,则可以直接丢弃页面(因为磁盘上的副本仍然有效)。
xv6 的简化处理:xv6 作为一个教学操作系统,并未使用 A 和 D 位来实现页面置换或写回策略。xv6 的页面分配是静态的(所有物理页面在启动时被分配),不存在页面换出。但在真实操作系统(如 Linux)中,A/D 位是虚拟内存子系统的核心依赖。

3.7 PTE 在地址转换中的完整角色

结合多级页表遍历过程,PTE 在每个层级的作用可以总结为以下步骤:

  1. 读取根页表寄存器:从 satp CSR 中获取根页表的物理地址。
  2. 逐级索引:使用虚拟地址的 VPN[2]、VPN[1]、VPN[0] 分别索引三级页表。
  3. 检查 V 位:每读取一个 PTE,首先检查 V 位。如果 V=0,触发页错误。
  4. 判断节点类型:检查 R 和 X 位。如果 R=0 且 X=0,则 PPN 指向下一级页表,继续遍历;否则,当前 PTE 是叶子节点。
  5. 权限检查:在叶子节点上,检查 U 位(用户态访问需要 U=1)、W 位(写操作需要 W=1)、X 位(执行需要 X=1)。
  6. 硬件更新 A/D 位:如果访问成功,硬件自动将 A 位置 1;如果是写操作,还将 D 位置 1。
  7. 生成物理地址:将 PPN 与虚拟地址的页内偏移(12 位)拼接,得到最终的物理地址。
PTE 驱动的多级页表地址转换流程 虚拟地址:VPN[2] (9位) | VPN[1] (9位) | VPN[0] (9位) | offset (12位) 第1级页表:使用 VPN[2] 索引 PTE V=1 & 非叶子? PPN → 第2级页表 页错误 第2级页表:使用 VPN[1] 索引 PTE 叶子 PTE:PPN + offset → 物理地址(同时检查 R/W/X/U)

3.8 本章小结

页表项(PTE)是连接虚拟地址和物理地址的桥梁,其结构设计体现了 RISC-V 架构的简洁与高效:

  • PPN(63-10 位):44 位的物理页号,支持最大 2^56 字节的物理地址空间,被拆分为三个子段以匹配多级页表的索引结构。
  • Flags(9-0 位):10 个标志位,涵盖有效性(V)、读写执行权限(R/W/X)、特权级隔离(U)、全局映射(G)、硬件辅助统计(A/D)以及操作系统保留位(RSW)。
  • 节点类型区分:通过 R 和 X 位的组合,MMU 可以区分叶子节点(最终映射)和非叶子节点(指向下一级页表),这是多级页表遍历的核心机制。
  • 硬件自动维护:A 和 D 位由硬件自动置位,为操作系统提供了零成本的页面访问统计能力,是实现页面置换和写回策略的基础。