一、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,原因有三:
- 设备隔离——防止恶意或出错的设备访问不该访问的内存区域
- 地址翻译——让设备也能用虚拟地址,支持IO虚拟化
- 大内存支持——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核心架构图,帮你理清各个模块的关系:
这张图里,我特意把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