4. 转换表查找过程:多级页表遍历算法、TLB缓存机制与失效策略
ARMv8-A 64位架构下,虚拟地址空间高达2⁶⁴字节,若采用单级页表,页表项数量将不可接受。因此,硬件采用多级页表(Translation Table Walk)机制,将线性查找转化为树形遍历,配合TLB(Translation Lookaside Buffer)缓存最近使用的转换结果,实现虚拟地址到物理地址的高效转换。
4.1 多级页表层级结构与遍历算法
ARMv8-A 使用 4级页表(Stage 1),分别为:L0、L1、L2、L3。每一级页表包含若干描述符(Descriptor),描述符指向下一级页表的基地址或直接指向物理页框。
| 页表级别 | 粒度(块/页大小) | 覆盖地址范围 | 典型用途 |
|---|---|---|---|
| L0 | — | 512 GiB | 顶级页表,仅包含指向L1的指针 |
| L1 | 1 GiB 块 | 1 GiB | 大块内存映射(设备寄存器、大缓冲区) |
| L2 | 2 MiB 块 | 2 MiB | 中等粒度映射(内核堆、大页) |
| L3 | 4 KiB 页 | 4 KiB | 标准页粒度(进程堆栈、代码段) |
遍历算法核心步骤:
- 提取索引:从虚拟地址中提取 L0、L1、L2、L3 索引位。
- 读取TTBR0_EL1:获取L0页表的基地址(Translation Table Base Register)。
- 逐级查找:
• L0索引 → 读取L0描述符 → 若为表描述符,则获取L1基地址;
• L1索引 → 读取L1描述符 → 若为块描述符,则直接得到物理基址(1 GiB块);
• 否则继续到L2、L3。 - 终止条件:遇到块描述符或页描述符,提取物理地址;遇到无效描述符触发缺页异常。
🔍 关键点: 多级页表并非每次遍历都走满4级。当L1或L2描述符为“块”类型时,遍历提前终止,大幅减少内存访问次数。设备驱动映射大块寄存器区域时,常使用1 GiB或2 MiB块映射,既节省页表空间,又提升TLB覆盖范围。
4.2 TLB缓存机制
TLB 是 MMU 内部的高速缓存,存储最近使用的虚拟地址到物理地址的转换结果。TLB 命中时,MMU 直接获取物理地址,无需遍历页表,延迟从数十纳秒降至1-2个CPU周期。
4.2.1 TLB结构
- 全相联TLB:所有条目可同时比较,命中率高,但功耗大,通常用于L1 TLB。
- 组相联TLB:分多组,每组内全相联,平衡速度与功耗,常用于L2 TLB。
- 指令TLB(ITLB):缓存指令地址转换。
- 数据TLB(DTLB):缓存数据地址转换。
| TLB层级 | 典型容量 | 相联度 | 延迟(周期) | 覆盖范围(4KiB页) |
|---|---|---|---|---|
| L1 ITLB | 32-64 条目 | 全相联 | 1 | 128-256 KiB |
| L1 DTLB | 32-64 条目 | 全相联 | 1 | 128-256 KiB |
| L2 TLB(统一) | 512-2048 条目 | 4-8路组相联 | 2-5 | 2-8 MiB |
💡 驱动开发提示: 使用 大页(HugePage) 映射(如2 MiB或1 GiB)可显著提升TLB覆盖范围。例如,一个L1 TLB条目覆盖2 MiB,64条目即可覆盖128 MiB,而4 KiB页仅覆盖256 KiB。对于设备DMA缓冲区,优先使用大页映射。
4.3 TLB失效策略
当页表内容被修改(如解除映射、更改权限、替换页框)后,TLB中缓存的旧转换结果必须失效(Invalidate),否则MMU可能使用过时的映射,导致数据不一致或安全漏洞。
4.3.1 失效指令
| 指令 | 作用范围 | 典型使用场景 |
|---|---|---|
TLBI VMALLE1 |
所有TLB条目(EL1) | 进程切换、全局映射变更 |
TLBI VAE1, Xn |
指定虚拟地址的TLB条目 | 单页解除映射 |
TLBI ASIDE1, Xn |
指定ASID的所有TLB条目 | 进程退出、ASID回收 |
TLBI VAAE1, Xn |
指定虚拟地址和ASID的条目 | 精确失效,最小化TLB抖动 |
4.3.2 失效策略选择
- 全局失效(VMALLE1):简单粗暴,但会清空所有TLB条目,后续访问将大量未命中,性能损失大。适用于进程切换或全局映射变更。
- 按地址失效(VAE1):仅失效特定虚拟地址的条目,粒度细,对性能影响小。适用于驱动动态映射/解除映射单个缓冲区。
- 按ASID失效(ASIDE1):失效特定地址空间的所有条目,适用于进程退出时清理。
⚠️ 驱动常见错误: 在修改页表后忘记执行TLB失效,导致硬件仍使用旧映射访问已释放的内存,造成use-after-free或访问错误物理地址。在SMP系统中,还需通过跨核TLB失效(TLB shootdown)确保所有核的TLB一致。
4.3.3 TLB失效流程示例(Linux内核)
/* 解除映射并失效TLB */
void unmap_and_flush(struct mm_struct *mm, unsigned long vaddr)
{
/* 1. 清除页表项 */
pte_clear(mm, vaddr, pte_offset_map(...));
/* 2. 刷新TLB(按地址失效) */
flush_tlb_page(vma, vaddr);
/* 3. 在SMP系统中,发送IPI触发其他核的TLB失效 */
smp_call_function(remote_tlb_flush, NULL, 1);
}
4.4 多级页表与TLB协同工作流程
MMU在地址转换时,首先查询TLB:
- TLB命中:直接返回物理地址,零页表遍历。
- TLB未命中:硬件自动启动页表遍历器(Table Walk Unit),执行4级页表查找。
- 遍历成功:将转换结果填入TLB,并返回物理地址。
- 遍历失败:触发缺页异常(Page Fault),由操作系统处理。
🔧 驱动适配要点:
• 设备寄存器映射:使用 ioremap 时,内核自动分配页表并设置缓存属性(Device-nGnRE)。
• DMA缓冲区:使用 dma_alloc_coherent 分配非缓存一致性内存,页表属性为 Normal Non-cacheable。
• 用户态驱动:通过 mmap 映射设备内存时,需在VMA中设置 pgprot_noncached 或 pgprot_writecombine。
• TLB失效时机:在 unmap、remap、mprotect 后必须执行TLB失效,否则硬件可能访问错误物理地址。
• 设备寄存器映射:使用 ioremap 时,内核自动分配页表并设置缓存属性(Device-nGnRE)。
• DMA缓冲区:使用 dma_alloc_coherent 分配非缓存一致性内存,页表属性为 Normal Non-cacheable。
• 用户态驱动:通过 mmap 映射设备内存时,需在VMA中设置 pgprot_noncached 或 pgprot_writecombine。
• TLB失效时机:在 unmap、remap、mprotect 后必须执行TLB失效,否则硬件可能访问错误物理地址。
4.5 本章小结
- 多级页表通过树形遍历将大地址空间映射到物理内存,支持1 GiB/2 MiB/4 KiB多种粒度。
- TLB缓存最近使用的转换结果,是MMU性能的关键。L1 TLB命中仅需1周期,未命中则需遍历页表。
- TLB失效策略需根据场景选择:全局失效用于进程切换,按地址失效用于驱动动态映射管理。
- 驱动开发应善用大页映射、合理选择缓存属性、及时执行TLB失效,避免性能陷阱和安全漏洞。