一、SMMU概述:从MMU到系统级IO虚拟化的桥梁

1.1 什么是SMMU?

SMMU,全称System Memory Management Unit,系统内存管理单元。

说白了,它就是给IO设备用的MMU。

你想想看,CPU访问内存有MMU管着,虚拟地址转物理地址,权限检查,一套组合拳打下来,安全又灵活。那DMA控制器呢?网卡呢?GPU呢?这些设备直接读写内存,谁来管?

嗯,这就是SMMU的活儿。

我刚开始接触SMMU时,总觉得它就是个「外设版的MMU」。后来踩过坑才发现——事情没那么简单。SMMU不仅要管地址翻译,还要处理设备隔离、中断重映射、跨片协同……

核心定义:SMMU是位于IO设备与内存总线之间的硬件模块,负责对设备发起的所有内存访问进行地址转换和权限检查。

1.2 为什么需要SMMU?

没有SMMU的世界,是什么样的?

我举个例子。假设你有一台服务器,上面跑了10个虚拟机。每个虚拟机里的网卡驱动,都以为自己直接操作的是物理网卡。如果没有SMMU,任何一个虚拟机里的驱动写错了DMA地址——好家伙,它可以直接把数据写到宿主机内核里,甚至写到别的虚拟机的内存里。

这还了得?

所以,我们需要SMMU,原因有三:

  1. 设备隔离——防止恶意或出错的设备访问不该访问的内存区域
  2. 地址翻译——让设备也能用虚拟地址,支持IO虚拟化
  3. 大内存支持——32位设备通过SMMU访问64位地址空间

我在项目中遇到过一台老旧的FPGA加速卡,它只支持32位DMA地址。但服务器装了512GB内存,FPGA的DMA根本访问不到高地址区域。怎么办?加个SMMU,把设备发起的32位地址翻译成64位物理地址,问题就解决了。

避坑指南:我曾经以为SMMU只是虚拟化场景才需要。后来做嵌入式裸机系统时发现,有些SoC里即便不跑虚拟机,SMMU也能用来做安全隔离——把敏感外设的DMA访问限制在安全内存区域内。

1.3 SMMU在虚拟化中的角色

虚拟化场景下,SMMU的地位就更加关键了。

你想想看,虚拟机里的设备驱动,它发出的DMA地址是客户机物理地址(GPA)。但宿主机真正需要的是主机物理地址(HPA)。谁来转?

SMMU。

具体来说,SMMU在虚拟化中扮演三个角色:

角色 说明 我的一点体会
地址翻译器 将设备发出的IO虚拟地址(IOVA)翻译为物理地址 这一步和MMU的页表遍历很像,但SMMU的页表格式和MMU不完全一样,踩过坑才知道
设备隔离器 确保每个虚拟机只能访问分配给它的设备 PCIe的ACS特性+SMMU的Stream ID过滤,双保险
中断重映射器 将设备中断重新映射到正确的虚拟机 很多人只关注地址翻译,忽略了中断这块,结果虚拟机收不到中断,排查半天

我记得有一次调试VFIO直通场景,虚拟机里的NVMe驱动死活认不到盘。查了一圈,发现是SMMU的Stream ID配置错了——设备发出的请求被SMMU拦截了,因为Stream ID没匹配到正确的STE(Stream Table Entry)。

嗯,从那以后,我每次配SMMU都会先确认Stream ID的映射关系。

1.4 SMMU与MMU的对比

很多人问我:SMMU和MMU到底有啥区别?

我一般这么回答:MMU是给CPU用的,SMMU是给设备用的。但这么说太笼统了,咱们来张表对比一下:

对比维度 MMU SMMU
服务对象 CPU核心 IO设备(DMA、网卡、GPU等)
地址来源 CPU发出的虚拟地址 设备发出的IO虚拟地址或物理地址
页表格式 通常使用VMSA(虚拟内存系统架构)页表 支持VMSA页表,也支持自定义格式
上下文数量 每个CPU核心一个当前上下文 支持数千个Stream上下文
中断处理 触发缺页异常给CPU 触发SMMU中断或转发给指定虚拟机
性能要求 极低延迟(CPU流水线关键路径) 高吞吐量(设备DMA通常是大块传输)

你看,虽然都是做地址翻译,但设计哲学完全不同。

MMU追求的是低延迟——CPU每取一条指令都要查TLB,慢了就卡住。SMMU追求的是高吞吐——设备一次DMA可能传几MB数据,翻译一次能用很久,TLB命中率天然就高。

我个人的习惯是:调试MMU问题用perf看TLB miss率,调试SMMU问题用IOMMU的trace事件看DMA映射耗时。两个工具链完全不同。

特别注意:SMMU的页表遍历可能比MMU慢一个数量级。因为SMMU通常挂在系统总线上,访问页表需要走更长的路径。所以,SMMU的TLB设计得比MMU更大,缓存更多条目。我在项目中见过因为SMMU TLB太小导致DMA性能暴跌的案例——网卡吞吐从10Gbps掉到2Gbps,排查了三天才发现是TLB thrashing。

1.5 SMMU的核心架构

说了这么多,咱们来看看SMMU内部长什么样。

下面这张图是我自己画的SMMU核心架构图,帮你理清各个模块的关系:

SMMU核心架构图 设备域 PCIe设备 / DMA引擎 GPU / 网卡 / NVMe 发出IOVA或物理地址 Stream ID + 地址 SMMU核心 Stream Table (STE) 页表遍历单元 (PTW) TLB缓存 物理地址 内存域 系统内存 DMA缓冲区 页表也在内存中 配置接口 (MMIO) 由驱动/Hypervisor配置 中断输出 缺页/错误/完成 设备 SMMU 内存 配置 中断 数据流 → 控制流 →

这张图里,我特意把Stream Table放在最上面——因为它是SMMU的入口。设备发来的每个请求都带一个Stream ID,SMMU拿着这个ID去查STE,找到对应的页表基地址和配置信息,然后才开始地址翻译。

页表遍历单元(PTW)负责在内存中查找页表。如果TLB命中,PTW就省了,直接返回翻译结果。这就是为什么SMMU性能调优的核心是提高TLB命中率。

我的经验:调试SMMU问题时,先看STE配置对不对,再看TLB有没有刷新过。这两个地方出问题的概率占了80%。剩下的20%是中断路由和页表权限设置。

1.6 小结

这一章我们聊了SMMU是什么、为什么需要它、它在虚拟化中的角色,以及和MMU的对比。

说白了,SMMU就是IO世界里的MMU。没有它,虚拟化场景下的设备直通就是空中楼阁——你不敢让虚拟机直接操作物理设备,因为没法保证安全隔离。

我个人觉得,理解SMMU最好的方式就是动手配一次。找个有SMMU的板子,写个驱动把设备DMA地址映射到不同物理区域,看看SMMU是怎么拦截和翻译的。纸上得来终觉浅,绝知此事要躬行。

嗯,下一章我们深入SMMU的硬件架构,看看Stream Table和Context Descriptor到底长什么样。


公众号:蓝海资料掘金营,微信deep3321