4. TLB 命中与缺失:TLB hit/miss 流程、硬件遍历页表与软件填充

TLB 作为页表的硬件缓存,其命中与缺失处理直接决定了虚拟地址翻译的延迟。本章深入剖析 TLB 命中的快速路径、缺失时的两种处理模式(硬件遍历 vs. 软件填充),以及多核环境下 TLB 缺失处理的同步考量。

4.1 TLB 命中流程:快速地址翻译路径

当 CPU 发出虚拟地址 VA 请求时,MMU 并行查询 TLB。若 TLB 命中,则在一个时钟周期内完成翻译,不产生任何流水线停顿。

TLB 命中关键路径(以 4KB 页、两级页表为例):
  1. 从虚拟地址 VA[31:12] 提取 VPN(虚拟页号)。
  2. TLB 控制器对 VPN 进行索引(Index)和比较(Tag Compare)。
  3. 若 Tag 匹配且有效位(V)为 1,则命中。
  4. 从 TLB 项中读出物理页号(PPN)和权限位(R/W/X)。
  5. 组合 PPN 与页内偏移 VA[11:0] 生成物理地址 PA。
  6. 同时检查权限:若违反(如写只读页),触发缺页异常或保护错误。
TLB 命中流程 TLB 命中快速路径 虚拟地址 VA 提取 VPN TLB 查找 命中? 生成物理地址 PA 权限检查 TLB 命中时,整个翻译过程在 1-2 个 CPU 周期内完成,不产生流水线停顿

4.2 TLB 缺失流程:硬件遍历页表

当 TLB 未命中时,MMU 必须从内存中的多级页表获取页表项(PTE)。硬件遍历模式由 MMU 状态机自动完成,无需软件干预。

步骤 操作 访问资源 延迟(周期)
1 从 CR3 寄存器读取页表基址 CPU 内部寄存器 0
2 VPN[31:22] 索引 L1 页表(PML4) L1 页表(内存) ~100
3 VPN[21:12] 索引 L2 页表(Page Directory) L2 页表(内存) ~100
4 读取 PTE,检查 Present 位 L2 页表项 0(合并)
5 将 PTE 写入 TLB,设置有效位 TLB 硬件 ~10
6 重试原指令,TLB 命中 — 0(重放)
硬件遍历优势: 无需软件异常处理,对操作系统透明;支持页表 walker 缓存(PWC)进一步加速。x86-64 架构采用此模式。
硬件页表遍历流程 硬件页表遍历(x86-64 四级页表) CR3 基址 L1 PML4 L2 PDPT L3 PD L4 PT PTE TLB 填充 硬件遍历流程:MMU 自动从 CR3 开始,逐级索引页表 每级页表访问约 100 周期,四级总计约 400 周期 现代 CPU 使用页表遍历缓存(PWC)缓存中间级页表项 PWC 命中可将遍历延迟降低到 1-2 次内存访问 最终 PTE 写入 TLB,原指令重放执行

4.3 软件填充 TLB:操作系统异常处理

在 RISC 架构(如 MIPS、早期 Alpha)中,TLB 缺失由软件异常处理程序完成。MMU 触发 TLB 缺失异常,操作系统内核接管并手动遍历页表、填充 TLB。

软件填充的代价: 异常处理涉及上下文切换、异常向量查找、内核栈切换,通常需要数百个周期。但软件填充提供了最大的灵活性,允许操作系统实现非标准页表结构或自定义替换策略。
// MIPS TLB 缺失异常处理程序(简化)
tlb_miss_handler:
    // 从 BadVAddr 寄存器读取缺失虚拟地址
    mfc0   $k0, $8          // $k0 = BadVAddr
    // 提取 VPN
    srl    $k0, $k0, 12     // 右移 12 位得到 VPN
    sll    $k0, $k0, 2      // 乘以 4(PTE 大小)
    // 从页表基址寄存器读取
    mfc0   $k1, $2          // $k1 = PageTableBase
    // 计算 PTE 地址
    addu   $k1, $k1, $k0    // $k1 = PTE 地址
    // 加载 PTE
    lw     $k0, 0($k1)      // $k0 = PTE 值
    // 检查 Present 位
    andi   $k1, $k0, 0x1    // 检查最低位
    beq    $k1, $zero, page_fault
    // 写入 TLB
    mtc0   $k0, $2          // 写入 TLB EntryLo
    tlbwr                   // 随机替换 TLB 项
    // 返回
    eret

4.4 硬件遍历 vs. 软件填充:对比分析

特性 硬件遍历(Hardware Walk) 软件填充(Software Fill)
典型架构 x86-64, ARMv8-A MIPS, SPARC, 早期 Alpha
缺失延迟 ~400 周期(四级页表) ~800-1500 周期(含异常开销)
页表结构灵活性 低(硬件固定页表格式) 高(软件可自定义)
TLB 替换策略 硬件 LRU/Random 软件可编程(如 FIFO, Clock)
多核同步复杂度 低(硬件保证原子性) 高(需软件处理 TLB 一致性)
功耗 较高(硬件状态机持续运行) 较低(异常处理时 CPU 全速运行)

4.5 多核环境下的 TLB 缺失处理

在多核系统中,TLB 缺失处理必须考虑页表一致性:一个核可能正在修改页表,而另一个核正在遍历同一页表。硬件遍历通常通过以下机制保证正确性:

  • 页表锁(Page Table Lock): 修改页表前获取自旋锁,确保遍历时页表不被修改。
  • 原子 PTE 更新: 使用 CAS(Compare-And-Swap)或 LL/SC 指令原子更新 PTE 的 Present 位和权限位。
  • TLB 射程无效(TLB Shootdown): 当核 A 修改页表后,必须通过 IPI 通知其他核刷新相关 TLB 项(详见后续章节)。
关键设计原则: 硬件遍历页表时,MMU 必须保证读取的 PTE 是原子一致的。x86-64 通过硬件保证单次 PTE 读取的原子性(8 字节对齐),但多级页表遍历的整体一致性仍需软件通过内存屏障(MFENCE)和页表锁来维护。
多核 TLB 缺失与页表同步 多核 TLB 缺失与页表同步 Core 0 TLB Miss → 硬件遍历 读取页表 Core 1 修改页表 更新 PTE 共享页表 L1/L2/L3/L4 PTE 数组 同步机制 1. 页表锁(Spinlock):修改前获取锁,遍历时检查锁状态 2. 原子 PTE 更新:使用 CMPXCHG 保证 8 字节原子写入 3. TLB Shootdown:修改后发送 IPI,通知其他核刷新 TLB

4.6 实战案例:x86-64 TLB 缺失性能分析

以 Intel Skylake 微架构为例,TLB 缺失的典型延迟如下:

TLB 层级 容量 命中延迟 缺失处理 缺失延迟
L1 DTLB 64 项 1 周期 L2 TLB 命中 ~8 周期
L2 TLB 1536 项 ~8 周期 硬件页表遍历 ~400 周期
页表遍历 — — PWC 命中 ~100 周期
页表遍历 — — PWC 缺失 ~400 周期
优化建议: 使用大页(2MB/1GB)可显著降低 TLB 缺失率。2MB 大页覆盖 512 倍于 4KB 页的地址空间,L2 TLB 可覆盖 3GB 内存,大幅减少页表遍历次数。