1. SMMU概述:它在SoC中的位置、与MMU的异同、为什么需要它

各位同学,咱们今天开篇先聊个基础问题——SMMU到底是什么?

我刚开始接触这个模块时,也觉得很困惑。MMU不是已经在CPU里管得好好的吗?为什么还要搞个SMMU?这不是重复造轮子吗?

嗯,等你真正做过几个SoC项目,就会明白——没有SMMU,整个系统的安全性和灵活性都会出大问题。

1.1 SMMU在SoC中的位置

先看一张图,这是我个人习惯用的方式——先看全局,再抠细节。

核心观点:SMMU是连接“非CPU主设备”与“内存系统”之间的地址翻译与访问控制桥梁。

SMMU在SoC中的位置 CPU Cluster (含MMU) GPU (需要SMMU) DMA控制器 (需要SMMU) 其他主设备 SMMU 地址翻译 权限检查 TLB缓存 事务过滤 DDR内存 系统物理地址空间 图例说明 → 主设备发起访问请求 → SMMU翻译后访问内存 CPU自带MMU,不走SMMU

从图上你能看到,CPU Cluster自己带着MMU,它访问内存不需要经过SMMU。但GPU、DMA、网卡这些设备,都得先经过SMMU这道关卡。

说白了,SMMU就是给“非CPU主设备”准备的MMU。我在一个手机SoC项目中见过,GPU直接访问物理内存导致系统崩溃——就是因为没配好SMMU的页表。

1.2 SMMU与MMU的异同

很多初学者会问:SMMU和MMU到底有什么区别?

咱们直接上表格对比,这样最清楚。

对比维度 MMU(CPU侧) SMMU(系统侧)
服务对象 CPU核心(软件视角) 外设/DMA/GPU(硬件视角)
页表格式 通常使用VMSA(虚拟内存系统架构) 兼容VMSA,但可配置多种格式
TLB管理 由CPU硬件自动维护 需要软件通过命令队列维护
异常处理 触发Page Fault,由OS处理 触发SMMU中断或事件
地址空间 每个进程独立虚拟地址空间 每个设备/Stream独立地址空间
性能要求 极低延迟(CPU流水线关键路径) 中等延迟(可容忍一定延迟)

我的经验:调试SMMU时,最常犯的错误就是把MMU那套思维直接搬过来。MMU的页表切换由OS在进程切换时自动完成,但SMMU的StreamID和页表绑定需要你手动配置——我因为这个bug调了整整两天。

1.3 为什么需要SMMU?

好,现在回答那个核心问题——为什么非CPU设备也需要地址翻译和访问控制?

我总结了三个最根本的原因:

  1. IO虚拟化——虚拟机场景下,每个VM的设备都需要独立的地址空间
  2. 安全隔离——防止恶意设备直接读取物理内存中的敏感数据
  3. 连续物理内存——让不连续的物理内存对设备呈现为连续的IO虚拟地址

举个例子,你在云服务器上跑虚拟机。宿主机有4个VM,每个VM都认为自己独占了一块GPU。如果没有SMMU,GPU的DMA操作会直接访问物理地址——那一个VM就能读到另一个VM的数据,这还得了?

避坑指南:我曾经在一个项目中,因为没有启用SMMU的StreamID过滤,导致一个低权限的外设DMA写坏了内核关键数据结构。系统随机崩溃,查了整整一周才定位到问题。从那以后,我养成了一个习惯——所有支持SMMU的设备,必须配好StreamID和页表再启用DMA。

1.4 SMMU的核心能力

咱们再深入一点,看看SMMU到底能做什么。我习惯把它拆成三个层次:

  • 地址翻译层:将设备发起的IO虚拟地址(IOVA)翻译为物理地址(PA)
  • 权限控制层:检查设备是否有权限访问目标内存区域
  • 缓存管理层:维护TLB和配置缓存,提升翻译性能

这三个层次缺一不可。地址翻译是基础,权限控制是安全保证,缓存管理是性能关键。

你想想看,如果一个设备每次访问内存都要查一遍页表,那性能得差到什么程度?所以SMMU内部有TLB,跟CPU的TLB原理类似,但管理方式完全不同。

关键点:SMMU的TLB不会像CPU那样自动维护。当页表被修改后,你必须通过SMMU的命令队列发送TLB invalidate指令——这个操作如果漏了,系统就会读到过期的翻译结果,造成数据损坏。

1.5 本章小结

咱们这一章把SMMU的定位讲清楚了。它不是什么神秘的东西,说白了就是给外设准备的MMU。但它的配置和管理比CPU MMU更复杂,因为你要面对的是多种设备、多个Stream、以及更灵活的安全策略。