跳转至

虚拟存储的硬件支持

动机:让每个进程拥有自己的地址世界

程序希望地址连续、容量足够且不被其他进程破坏,物理内存却有限而零散。虚拟存储在虚拟地址与物理地址之间加入映射,同时提供:

  • 进程隔离与页级权限;
  • 灵活装载和共享;
  • 按需把冷页面换到外存;
  • 给程序近似连续的地址空间。

操作系统决定映射策略,硬件负责在每次访存的关键路径上快速翻译并检查权限。

页与页表

虚拟地址分为虚拟页号 VPN 和页内偏移:

| virtual page number | page offset |

页表项(PTE)把 VPN 映射到物理页号 PPN,并保存有效位、读写执行权限、访问位和脏位等。页内偏移在翻译前后不变:

| physical page number | same page offset |

若页大小为 4 KiB,页内偏移为 12 位。

为什么需要多级页表

若为巨大虚拟地址空间的每个页都预留 PTE,页表本身会很大。多级页表把 VPN 切成多段,只为实际使用的区域分配下级表,类似稀疏树。

代价是一次 TLB miss 可能需要多次内存访问才能走完页表。页表深度越大,地址空间扩展越容易,遍历代价也越高。

TLB:翻译的 cache

TLB 缓存近期 VPN 到 PPN 的映射与权限。命中时可很快形成物理地址;miss 时由硬件页表遍历器或操作系统查页表,成功后回填 TLB。

若 TLB 命中时间为 \(T_{TLB}\),命中率为 \(h\),页表遍历平均代价为 \(P\),忽略重叠时翻译开销近似:

\[ T_{translate}=T_{TLB}+(1-h)P. \]

真实机器会让 TLB 查询与 cache 索引部分重叠,以缩短关键路径。

TLB miss 不等于缺页

TLB miss

翻译不在小型 TLB,但对应 PTE 可能就在内存中且有效。遍历页表、回填后即可重试,通常不需从磁盘读数据。

page fault

PTE 表示页面不在主存、权限不允许或映射不存在,硬件触发异常。操作系统检查原因;按需调页时可能选择牺牲页、写回脏页、从 SSD 读入目标页、更新 PTE,再重启原指令。其代价可比普通指令高许多个数量级。

最小路径:一次 load

lw x5, 8(x10) 形成虚拟地址后:

  1. VPN 查询 TLB;
  2. 命中则得到 PPN并检查读权限;
  3. PPN 与原页内偏移组成物理地址;
  4. 物理地址查询 L1 data cache;
  5. cache 命中返回数据,最终写 x5

若 TLB miss,先页表遍历;若 cache miss,再访问下级 cache 或 DRAM。两类 miss 独立存在。

大页与覆盖范围

同样数量的 TLB 项,页越大,能覆盖的内存越多,适合大数据和数据库;也能减少页表层级。但大页增加内部碎片、分配困难和换页粒度,未必适合零散小对象。

TLB reach 为:

\[ Reach=N_{entries}\times PageSize. \]

提升 reach 可以增加项数、增大页或混合页大小,各有面积、延迟和管理成本。

cache 与翻译的先后

物理索引物理标记最直观,但必须等翻译后才能索引。虚拟索引可与 TLB 并行,却要处理不同虚拟地址映射同一物理页的同义问题,以及不同进程相同虚拟地址的重名问题。常见 L1 使用“虚拟索引、物理标记”,并让索引只依赖页内偏移范围。

权限、上下文与安全

PTE 的用户/内核、可写、可执行位是硬件隔离基础。切换进程后,旧 TLB 项不能被错误复用,系统可刷新 TLB 或用地址空间标识符区分。

推测执行还可能在权限检查结果确定前触碰 cache,形成侧信道。因此翻译与权限不只是性能机制,也是安全边界。

自测

  1. 4 KiB 页为何对应 12 位页内偏移?
  2. TLB miss、page fault 和 cache miss 各自缺少什么?
  3. 大页提高 TLB reach 的同时会带来哪些代价?