type
status
date
slug
summary
tags
category
icon
password
URL
全系列文章链接
前言
近期所做的项目,与 Linux 内核的 IOMMU 机制有关,因此自己尝试去了解 IOMMU 的相关知识。我在网上多方查找,却总觉得是盲人摸象,难以形成一套系统化的知识体系。并且,许多代码是基于 Linux v2.x、v3.x 内核,而我当前项目是基于较新的 Linux 5.5.4 内核,有一些代码,乃至实现机制,都发生了根本性的变化。最终,还是决定自己研究代码,终于明白了 IOMMU 的初始化流程。现撰文分享,希望之后还有同行遇到此类问题时,能够参考本文,节约学习成本。
本系列包含多篇文章,分别介绍 IOMMU 的基本概念、软件 IOMMU(SWIOTLB)、硬件 IOMMU(Intel IOMMU),以及 IOMMU 的初始化流程。
本系列全部文章均可转载,转载时标明原作者即可。
适用环境
内核版本:Linux 5.5.4(Linux 5.x 版本应该都适用)
硬件:Intel x86-64 处理器;对于硬件 IOMMU 的章节,要求 BIOS 能够支持 Intel IOMMU
IOMMU 简介
关于 IOMMU,网上的资料分析得比较详细,此处仅作简要介绍,以作为后续文章的引子。
IOMMU (Input and Output Memory Management Unit),其名称显然是由 MMU 衍生而来。之所以二者名称如此相似,是因为它们的功能非常相似。以下是一张解释 IOMMU 功能的经典图片:

从上图中不难看出,IOMMU 是 DMA(直接内存访问,即设备与内存直接通信,而无需经过 CPU)过程中的一个环节。本系列的文章更多时候会把 IOMMU 看作一种机制,从这个角度,我们也可以说:IOMMU 是 DMA 的一种实现方式。
愿意阅读本文的读者,相信对于 MMU 并不陌生:MMU 是将 CPU 虚拟地址转换为内存物理地址的硬件单元。类似地,IOMMU 是将设备地址(又称总线地址)转换为内存物理地址的单元。我们完全可以参照虚拟内存机制,来理解 IOMMU 的作用:
① IOMMU 使得设备无法直接访问物理地址,大大增加了设备进行 DMA 攻击的难度。
② 部分设备的引脚数较少,导致其位数较低,无法寻址到整个物理内存空间。以目前主流的 32 位设备为例,其在物理内存中直接寻址的范围是 [0, 4GB)。但是,现代操作系统的内存往往大于 4GB。如果设备申请 DMA 时,内核为设备分配的 DMA buffer 的地址高于 4GB(以下简称为 “high buffer”),则设备将无法寻址到它。
有了 IOMMU 以后,IOMMU 就可以在 [0, 4GB) 范围内分配一段与高地址 buffer 长度相同的内存,让设备能够直接寻址(以下称为 “low buffer”)。设备向 low buffer 写入后,IOMMU 就会将 low buffer 中的内容,复制到 high buffer,而后通知 CPU 从 high buffer 读取内容。反之亦然——CPU 向 high buffer 写入后,IOMMU 就会将 high buffer 中的内容,复制到 low buffer,而后通知设备从 low buffer 读取内容。这样,CPU 和设备都能读取到对方写入的内容。这样在 high buffer 和 low buffer 之间复制内容的操作,在 IOMMU 机制中被称为“sync” 或“bounce”。
