🧩 RISC-V 虚拟内存(Virtual Memory)详解


一、为什么需要虚拟内存?

问题 虚拟内存的作用
程序访问的地址从 0 开始,但物理内存不一样大 将每个进程的虚拟地址映射到不同物理地址
程序之间相互隔离 不同进程拥有独立地址空间
操作系统管理更方便 可轻松调度与保护进程
可支持分页机制 按页分配、换页、缓存更高效

💡 简单说: 虚拟内存让程序“以为”自己独占整个内存。


二、RISC-V 的分页模式(Sv32 / Sv39 / Sv48)

RISC-V 定义了多种分页模式,用于不同 XLEN(位宽):

模式 XLEN 地址位数 页大小 层数 用途
Sv32 32 位 32 位虚拟地址 4 KiB 2 层页表 RV32 平台
Sv39 64 位 39 位虚拟地址 4 KiB 3 层页表 RV64 常用(Linux)
Sv48 64 位 48 位虚拟地址 4 KiB 4 层页表 高端服务器
Bare 任意 无分页 裸机/嵌入式系统

💡 Linux 在 RV64 平台上默认使用 Sv39


三、虚拟地址到物理地址的映射

RISC-V 虚拟内存通过 多级页表(Multi-level Page Table) 实现。 每一级页表都是一个 4KB 的数组,包含 512 个条目(8 字节 / PTE)。


🧮 以 Sv39 为例(RV64)

位段 名称 说明
[63:39] Sign Extension 必须与 bit 38 相同(符号扩展)
[38:30] VPN[2] 页表第 1 级索引(L2)
[29:21] VPN[1] 页表第 2 级索引(L1)
[20:12] VPN[0] 页表第 3 级索引(L0)
[11:0] Offset 页内偏移(4KB 页)

VPN = Virtual Page Number 每级索引 9 位 → 512 个条目。


四、页表项(PTE:Page Table Entry)结构

每个页表项(8 字节)描述虚拟页到物理页的映射。

名称 说明
63–54 PBMT 页属性(如缓存策略)
53–10 PPN 物理页号(Physical Page Number)
9 RSW OS 自定义位
8 D Dirty(是否写过)
7 A Accessed(是否访问过)
6 G Global(跨地址空间共享)
5 U User(U 模式可访问)
4 X eXecutable(可执行)
3 W Writable(可写)
2 R Readable(可读)
1 V Valid(条目有效)
0 保留

一个 PTE 中只要 R/W/X 中有一位为 1,就表示这是一个叶子节点(Leaf Entry), 否则它是中间页表(指向下一级页表)


五、地址转换过程(以 Sv39 为例)

假设要访问虚拟地址 VA

  1. satp 寄存器 取出页表根地址;

  2. 使用 VPN[2] 作为第一级索引 → 得到二级页表地址;

  3. 使用 VPN[1] 索引二级页表;

  4. 使用 VPN[0] 索引三级页表;

  5. 找到叶子项(R/W/X 有效);

  6. 从 PPN 拼接物理地址:

    物理地址 = PPN * 4KB + Offset

如果某级页表项无效(V=0),则触发 Page Fault 异常


六、关键控制寄存器

1️⃣ satp — Supervisor Address Translation and Protection

字段 位宽 说明
MODE 4 位 分页模式(0=Bare, 8=Sv39, 9=Sv48)
ASID 16 位 地址空间 ID(区分进程)
PPN XLEN-24 位 根页表物理页号(页表起始地址)

例如(Sv39 模式下):

satp = (MODE << 60) | (ASID << 44) | PPN

设置页表: 1️⃣ 在内存中建立页表结构 2️⃣ 把页表根物理地址写入 satp 3️⃣ 执行 sfence.vma 刷新 TLB


2️⃣ sfence.vma — 刷新 TLB 缓存

当修改页表后需执行:

asm
sfence.vma

确保新的映射生效。


七、示例:64 位地址映射(Sv39)

假设有:

计算:

VPN[2] = bits [38:30]
VPN[1] = bits [29:21]
VPN[0] = bits [20:12]
Offset = bits [11:0]

CPU 根据 VPN 分三次读取页表,最后合成物理地址。


八、RISC-V 的分页层数对比

模式 地址宽度 层数 每级索引位 可寻址空间 常见系统
Sv32 32 位 2 层 10 位 4 GiB RV32
Sv39 64 位 3 层 9 位 512 GiB Linux RV64
Sv48 64 位 4 层 9 位 256 TiB 服务器

九、页表映射类型(段页)

页面大小 说明 实现
4 KiB 普通页 三级页表最后一级
2 MiB 大页 二级页表直接叶子项
1 GiB 超大页 一级页表直接叶子项

🔟 十、Bare 模式(无分页)

嵌入式系统可禁用虚拟内存:

asm
csrw satp, zero   # MODE = 0 (Bare)

此时虚拟地址 == 物理地址 即为“裸机运行模式(Bare Metal)”。


✅ 十一、小结

项目 内容
分页机制 将虚拟地址 → 物理地址的映射
页大小 通常 4KB
控制寄存器 satpmstatusstvec
刷新指令 sfence.vma
常用模式 Sv32(RV32) / Sv39(RV64)
操作系统 Linux、RT-Thread、FreeBSD 等

🔑 一句话总结: RISC-V 的虚拟内存通过多级页表(Sv32 / Sv39 / Sv48)实现, 控制寄存器 satp 决定页表根地址和模式, CPU 按层解析虚拟地址 → 得到物理地址 → 执行访问。