3. IOMMU 硬件架构:页表结构、地址转换流程、TLB 与缓存一致性

IOMMU(Input/Output Memory Management Unit)是 DMA 子系统中的核心硬件单元,负责将设备发起的 I/O 虚拟地址(IOVA)转换为系统物理地址(PA)。本章深入剖析 IOMMU 的硬件架构,包括多级页表结构、地址转换流水线、TLB 缓存机制以及缓存一致性协议,为后续驱动配置打下坚实的硬件基础。

3.1 IOMMU 多级页表结构

IOMMU 采用与 CPU MMU 类似的多级页表结构,以支持大地址空间和细粒度映射。典型的 ARM SMMU 使用 4 级页表(Level 0 ~ Level 3),每级页表包含页表项(PTE),最终指向 4KB 或 64KB 的数据页。

关键概念: 页表级数决定了地址转换的深度和灵活性。级数越多,支持的地址空间越大,但转换延迟也越高。实际 SoC 中常根据系统需求选择 2 级或 3 级页表以平衡性能。
页表级别 页表项粒度 覆盖地址范围 典型用途
L0(根页表) 512 项 × 8 字节 最高 512GB 顶级目录,指向 L1 页表
L1 512 项 × 8 字节 1GB 块映射 大块连续内存映射
L2 512 项 × 8 字节 2MB 块映射 中等粒度映射
L3(叶页表) 512 项 × 8 字节 4KB 页映射 细粒度映射,典型 DMA 缓冲

页表项(PTE)结构包含物理页帧号(PFN)、访问权限位(读/写/执行)、缓存属性(可缓存/非缓存)、以及脏位/有效位等控制信息。驱动通过配置页表基地址寄存器(TTBR)来切换不同设备的地址空间。

IOMMU 多级页表结构(4级) L0 根页表 L1 页表 L2 页表 L3 叶页表 4KB 数据页 说明: • 每级页表包含 512 个 PTE,每个 PTE 8 字节,共 4KB 大小。 • L3 叶页表直接映射到物理内存页,支持 4KB/64KB 页粒度。

3.2 地址转换流程

当 DMA 设备发起一次内存访问时,IOMMU 硬件自动执行地址转换。转换流程分为以下关键步骤:

  1. 设备标识与上下文获取: IOMMU 根据设备总线号(如 PCIe RID)查找 StreamID/SubstreamID,定位对应的上下文描述符(Context Descriptor),其中包含页表基地址和转换配置。
  2. 页表遍历(Page Walk): 硬件从根页表开始,逐级解析 IOVA 中的索引位,读取 PTE,直到找到叶页表项。
  3. 权限与属性检查: 检查 PTE 中的读/写权限、安全属性(Secure/Non-Secure)、缓存属性(Cacheable/Device)等,若权限不匹配则触发缺页异常(Page Fault)。
  4. 物理地址生成: 将叶页表项中的 PFN 与 IOVA 页内偏移拼接,生成最终的物理地址(PA),发送到内存控制器。
性能提示: 页表遍历是 IOMMU 转换的主要延迟来源。对于延迟敏感的 DMA 流(如音频、网络),建议使用大页(2MB/1GB)减少页表级数,或通过预取机制提前加载页表项到 TLB。
IOMMU 地址转换流程 DMA 设备 StreamID → 上下文 页表遍历(4级) 权限检查 物理地址 PA 缺页异常处理 流程说明: 1. 设备发起 DMA 请求,携带 IOVA 和 StreamID。 2. IOMMU 查找上下文描述符,获取页表基地址。 3. 硬件自动遍历页表,若权限不足或页表无效则触发缺页异常。

3.3 TLB 与缓存一致性

为了加速地址转换,IOMMU 内部集成了 TLB(Translation Lookaside Buffer),缓存最近使用的页表项。TLB 的命中率直接影响 DMA 性能。同时,IOMMU 必须与 CPU 缓存保持一致,避免 DMA 访问到过时的数据。

3.3.1 TLB 结构与操作

TLB 类型 缓存内容 失效粒度 典型容量
微 TLB(μTLB) 单条页表项 单条目失效 8~64 项
主 TLB(Main TLB) 多级页表项 全失效 / ASID 失效 256~1024 项
共享 TLB(Shared TLB) 跨设备共享 全局失效 512~2048 项

驱动在修改页表后,必须通过 IOMMU 的 TLB 无效化命令(如 ARM SMMU 的 CMD_TLBI)使失效对应的 TLB 条目,否则硬件可能使用过期的转换结果。TLB 失效操作分为:

  • 全局失效(Global Invalidate): 清除所有 TLB 条目,开销最大,但适用于地址空间切换。
  • ASID 失效(ASID-based Invalidate): 仅清除指定地址空间的条目,适用于进程切换。
  • VA 范围失效(VA-based Invalidate): 仅清除指定虚拟地址范围的条目,粒度最细,适用于动态映射更新。

3.3.2 缓存一致性协议

IOMMU 必须保证 DMA 访问与 CPU 缓存之间的数据一致性。现代 SoC 通过以下机制实现:

  1. 硬件一致性(Hardware Coherency): IOMMU 在地址转换时检查页表项的缓存属性(如 ARM 的 Shareable 属性),若标记为 Inner Shareable,则 IOMMU 自动参与缓存一致性协议(如 AMBA CHI),DMA 读写直接与 CPU 缓存交互。
  2. 软件一致性(Software Coherency): 对于非一致性设备,驱动在 DMA 操作前后手动执行缓存刷新(Cache Flush)或失效(Cache Invalidate),确保数据可见性。
  3. IO 一致性(IO Coherency): 部分 SoC 提供 IO 一致性端口,IOMMU 通过 snoop 过滤器监听 CPU 缓存行状态,减少软件干预。
常见陷阱: 在非一致性系统中,驱动若未在 DMA 启动前执行缓存刷新,CPU 写入的数据可能仍停留在缓存中,导致设备读到陈旧数据。反之,DMA 完成后未执行缓存失效,CPU 可能读到过时的缓存行。务必在 DMA 操作前后正确调用 dma_map_single() / dma_unmap_single() 等 API,这些函数会自动处理缓存一致性。
TLB 与缓存一致性交互 CPU 核心 L1/L2 缓存 IOMMU TLB 缓存 DMA 设备 物理内存 缓存一致性总线(Snoop / CHI) • 硬件一致性:IOMMU 通过 snoop 总线直接与 CPU 缓存交互,无需软件刷新。 • 软件一致性:驱动调用 cache flush/invalidate 保证数据可见性。

3.4 实战要点总结

  • 页表配置: 根据设备内存需求选择合适的页表级数和页大小。大页减少 TLB 压力,但可能造成内存浪费。
  • TLB 管理: 每次页表更新后,必须调用对应的 TLB 无效化命令。批量更新时优先使用 VA 范围失效以减少开销。
  • 缓存一致性: 在非一致性系统中,使用 DMA API 自动处理缓存操作;在硬件一致性系统中,确保页表属性设置为 Shareable。
  • 调试手段: 通过 IOMMU 的缺页异常寄存器(如 SMMU 的 EVTQ)捕获地址转换错误,快速定位映射问题。