MMIO、IOMAP 和 IOMMU 全面解析
📌 本文将深入浅出地梳理 Linux 驱动开发中常见的三大术语:MMIO、iomap、IOMMU。它们看似相似,其实职责完全不同,是理解 SoC 系统架构、DMA 安全性和驱动开发的基础。
一、MMIO(Memory-Mapped I/O)
定义:
MMIO 是将外设的寄存器映射到内存地址空间中的一种机制,使得 CPU 可以像读写内存一样访问硬件寄存器。
特点:
-
地址固定,由硬件在 SoC 设计时分配(如 0xF000_0000)
-
访问方式为普通内存操作(
load/store
) -
对于 CPU 而言:访问的是虚拟地址,但最终会映射到 MMIO 的物理地址
Linux 中使用方式:
void __iomem *base = ioremap(0xF9000000, 0x1000);
writel(0x01, base + 0x04); // 写寄存器
二、iomap(或 ioremap)
定义:
ioremap()
是 Linux 内核提供的一个函数,用于将 MMIO 物理地址映射到内核虚拟地址空间,让驱动能用指针读写设备寄存器。
注意:
-
它并不是内核页表的一部分(无法被用户态访问)
-
一般只在内核驱动中使用
-
返回值是
__iomem
类型,强调它是特殊内存(不可随便 deref)
使用流程:
-
从设备树中读取 reg(物理地址)
-
调用
ioremap()
-
使用
readl()/writel()
操作寄存器 -
使用完后
iounmap()
三、IOMMU(I/O Memory Management Unit)
定义:
IOMMU 是为设备提供地址转换的 MMU,作用是在设备访问内存(DMA)时,将其使用的虚拟地址(IOVA)翻译为实际的物理地址(PA)。
和 MMU 类似:
-
CPU 使用虚拟地址 → MMU → 物理地址
-
设备使用 IOVA → IOMMU → 物理地址
好处:
-
安全隔离(防止 DMA 越界)
-
虚拟地址空间抽象(方便设备驱动管理 buffer)
-
支持虚拟化(guest VM 可以有独立 IOVA)
四者关系与对比
特性 | MMIO | iomap / ioremap | IOMMU |
---|---|---|---|
涉及角色 | CPU 访问设备寄存器 | CPU 访问寄存器的方式 | 设备访问内存的 MMU |
管理对象 | 寄存器地址(物理) | 虚拟地址 ←→ MMIO 映射 | IOVA ←→ RAM地址 |
是否在设备树 | ✅ reg 字段 | ✅ 用 reg 映射 | ✅ stream-id/domain |
是否需驱动调用 | ❌ 自动决定 | ✅ 手动 ioremap | ✅ DMA 调用会启用 |
是否用于 DMA | ❌ 否 | ❌ 否 | ✅ 是 |
示例场景:ISP 拍照设备
CPU → 配置 ISP 控制寄存器(0xF900_0000)↑ ioremap(iomap)
ISP → 把拍到的图像写入 DDR(0x12340000 IOVA)↑ 通过 IOMMU 做地址转换 → 实际写入物理内存
-
寄存器访问用
MMIO + iomap
-
内存访问(DMA)用
IOMMU
图示建议
CPU ←─(ioremap)────→ MMIO(设备寄存器)│ ↑│ ││ 控制设备 │↓ │DDR(内存) ←────(IOMMU)────← DMA ← 设备(ISP/VPU)