一、核心概念:什么是 SMMU?
SMMU 的全称是 System Memory Management Unit,即系统内存管理单元。
您可以把它理解为一个为系统外部设备服务的 “MMU”。
-
MMU:我们都知道,CPU 核心有一个 MMU。它的作用是负责虚拟地址到物理地址的转换,为 CPU 上运行的进程提供隔离、安全的内存访问视图。
-
SMMU:它为系统中其他需要直接访问内存的设备(如 GPU、网卡、视频编解码器、存储控制器等)提供同样的地址转换和访问权限管理功能。
简单来说,SMMU 让设备能够像进程一样使用虚拟地址,并由硬件自动、高效地转换为物理地址。
二、为什么需要 SMMU?它的主要作用是什么?
在没有 SMMU 的时代,设备DMA操作使用物理地址,这会带来几个严重问题:
-
安全和隔离问题:
-
一个被恶意控制或存在Bug的设备可以通过DMA读写内存中的任何位置,包括操作系统内核或其他应用程序的内存,这构成了巨大的安全漏洞。
-
无法实现类似CPU的进程间隔离。两个虚拟机(VM)的设备可能互相干扰,无法安全地共享硬件。
-
-
内存碎片化问题:
-
设备DMA需要连续的物理内存缓冲区。但在系统长时间运行后,要分配大块的连续物理内存会非常困难,容易导致分配失败。
-
而CPU侧得益于MMU和虚拟地址,可以轻松地使用零散的物理页来组合成连续的虚拟地址空间。
-
-
虚拟机兼容性问题:
-
在虚拟化环境中,虚拟机(Guest OS)不知道真实的物理地址(Host Physical Address)。它以为自己在操作一段连续的物理地址(Guest Physical Address)。
-
如果没有SMMU,虚拟机无法直接将“客户物理地址”交给设备进行DMA,因为设备无法理解这个地址。这就需要Hypervisor进行复杂的“地址翻译拦截和模拟”,带来巨大的性能开销。
-
SMMU 的核心作用正是为了解决上述问题:
-
地址翻译:将设备发出的IO虚拟地址转换为系统的物理地址。
-
访问权限控制:检查设备是否有权限(读、写)访问它想要访问的内存区域。如果没有权限,SMMU会阻止访问并上报错误。
-
提供设备虚拟化支持:让虚拟机可以直接、安全地将DMA地址传递给设备,极大提升虚拟化I/O的性能(即IOMMU虚拟化)。
三、SMMU 的工作原理
SMMU 的工作原理与 CPU 的 MMU 非常相似,也采用基于页表的地址转换。
-
核心组件:
-
TCB:Translation Control Block,是SMMU中为一个设备或一组设备提供转换服务的上下文,可以理解为MMU中的进程页表基址寄存器(TTBR)。
-
页表:存储在内存中的多级表格,定义了虚拟地址到物理地址的映射关系。通常支持与CPU相同的页大小(如4KB, 2MB, 1GB等)。
-
TLB:Translation Lookaside Buffer,是SMMU内部的地址转换缓存,用于加速翻译过程,类似于CPU的TLB。
-
-
工作流程:
-
设备发起一次DMA请求(读或写),请求中携带一个IO虚拟地址。
-
SMMU 截获这个请求。
-
SMMU 根据发起请求的设备ID和地址,查找对应的TCB(上下文)。
-
SMMU 查询TCB所指向的页表,将IO虚拟地址转换为物理地址。这个过程可能需要多次访问内存(walk the page table)。
-
同时,SMMU 检查页表中定义的访问权限。如果设备无权进行此操作,则终止请求并上报故障。
-
如果转换成功且权限正确,SMMU 将使用转换后的物理地址完成对系统内存的访问。
-
-
ATS 和 PRI(高级特性):
-
ATS:Address Translation Service,允许设备本身缓存SMMU的转换结果(拥有自己的TLB),从而减少对SMMU的翻译请求,进一步提升效率。
-
PRI:Page Request Interface,如果设备访问了一个未被映射的地址,SMMU可以向设备发送一个“页请求故障”,设备可以通过PRI向驱动程序请求建立正确的页表映射,然后重试操作。这对于实现设备驱动的虚拟内存( SVM, Shared Virtual Memory )至关重要。
-
四、SMMU 的主要应用场景
-
虚拟化:
-
这是SMMU最重要的应用场景之一。它使得设备可以直接分配给虚拟机(Direct Device Assignment / PCIe Pass-through),而性能损失极小。虚拟机使用客户物理地址(GPA),SMMU通过IO页表将其转换为宿主物理地址(HPA),实现了近乎原生的I/O性能。
-
-
安全性增强:
-
操作系统可以为每个设备分配独立的、受限的地址空间。例如,一个摄像头控制器只能访问存放视频缓冲区的内存,而无法触及其他数据。这极大地限制了恶意设备可能造成的损害。
-
-
简化驱动开发:
-
驱动程序可以使用
kmalloc
、vmalloc
等标准内核API为设备分配内存,而无需费力地去申请专门的、物理连续的内存(如传统的DMA API:dma_alloc_coherent
)。SMMU会处理物理地址的碎片化问题,设备看到的是一个连续的虚拟地址空间。
-
-
Shared Virtual Memory:
-
GPU 和 CPU 可以共享同一份虚拟地址空间,指针可以在CPU和GPU代码间直接传递,无需繁琐的映射和解映射操作,大大简化了异构编程模型(如OpenCL, CUDA)。
-
五、SMMU 与 IOMMU 的关系
这两个术语经常被混用,但它们略有区别:
-
IOMMU 是一个更通用的概念,指任何为I/O设备提供内存管理功能的硬件单元。它最早由AMD在其CPU架构中提出。
-
SMMU 是Arm公司对其设计的IOMMU的具体实现和命名。它遵循Arm的系统架构。
可以理解为:SMMU 是 Arm 生态体系下的 IOMMU。其功能本质上是相同的。在x86平台,类似的组件通常就直接称为IOMMU(如Intel的VT-d,AMD的VI)。
SMMU 开启与关闭方法
一、开启 SMMU
1. 操作系统级配置(以 Linux 为例)
- 驱动初始化:
- SMMU 驱动在初始化时读取设备树(DTS)中的节点,探测硬件特性并初始化全局资源(如命令队列、事件队列、流表等)。
- 示例 DTS 配置(以 Renesas R8A77961 为例):
dts
iommus = <&ipmmu_vc0 19>; // 绑定设备到 SMMU 实例
- 驱动通过
of_dma_configure()
函数将设备与 SMMU 绑定,并设置 DMA 掩码(如dma_coerce_mask_and_coherent()
)。
- 内存分配与转换表创建:
- 设备驱动通过
dma_alloc_coherent()
分配内存时,SMMU 驱动会自动创建地址转换表(页表),并配置流表(STE)和上下文描述符表(CD)。 - 转换表描述虚拟地址(IOVA)到物理地址(PA)的映射关系。
- 设备驱动通过
- 虚拟化场景:
- 在虚拟机中启用 SMMU 时,需同时配置 Stage 1(虚拟地址→中间物理地址)和 Stage 2(中间物理地址→系统物理地址)转换。
- Hypervisor(如 KVM)通过
SMMU_SMR
和SMMU_S2CR
寄存器配置流映射和转换规则。
2. 硬件级配置(BIOS/UEFI)
- 在 BIOS 或 UEFI 界面中启用 SMMU:
- 重启服务器,按
Delete
或Esc
进入 BIOS 设置。 - 导航至 Advanced → MISC Config。
- 将 Support SMMU 设置为 Enabled。
- 保存并退出(按
F10
)。
- 重启服务器,按
二、关闭 SMMU
1. 操作系统级关闭
- 临时禁用:
- 通过内核参数关闭 SMMU 功能(需重启生效):
# 编辑 GRUB 配置文件
vi /etc/default/grub
# 添加内核参数 iommu.strict=0(仅放松严格模式,非完全禁用)
# 或完全禁用 SMMU(需硬件支持):
# iommu.off=1
# 更新 GRUB 并重启
update-grub
reboot
- 注意:完全禁用 SMMU 可能导致设备无法访问高地址空间或分散内存。
- 通过内核参数关闭 SMMU 功能(需重启生效):
- 永久禁用:
- 在设备树中移除
iommus
属性,或通过驱动参数禁用(如smmu.disable=1
)。
- 在设备树中移除
2. 硬件级关闭(BIOS/UEFI)
- 步骤:
- 重启服务器,按
Delete
或Esc
进入 BIOS 设置。 - 导航至 Advanced → MISC Config。
- 将 Support SMMU 设置为 Disabled。
- 保存并退出(按
F10
)。
- 重启服务器,按
- 适用场景:
- 性能敏感型应用(如 FC 网卡带宽优化)。
- 调试 SMMU 相关故障(如地址转换错误、权限冲突)。
- 兼容不支持 SMMU 的旧设备。
三、关键注意事项
- 性能影响:
- 开启 SMMU 会引入地址转换开销(TLB 未命中时性能下降显著)。
- 华为鲲鹏服务器测试显示,关闭 SMMU 可提升数据库性能 1 倍以上。
- 安全风险:
- 关闭 SMMU 会导致设备直接访问物理内存,可能引发安全漏洞(如 DMA 攻击)。
- 虚拟化场景中必须启用 SMMU 以隔离虚拟机内存。
- 故障排查:
- 命令队列错误:检查
SMMU_GERROR.CMDQ_ERR
中断,修复命令顺序或预取失败。 - 事件队列错误:通过
EVTQ
记录配置错误(如无效 STE/CD)或转换故障(如F_TRANSLATION
)。 - 全局错误:处理
SMMU_GERROR
寄存器中的灾难性事件(如队列溢出)。
- 命令队列错误:检查
- 调试工具:
- Trace32:可视化 SMMU 寄存器、流表和页表(如
SMMU.StreamTable
命令)。 - 内核日志:通过
dmesg
查看 SMMU 驱动初始化错误或设备绑定失败信息。
- Trace32:可视化 SMMU 寄存器、流表和页表(如