前言:
IOMMU(输入输出内存管理单元)的原理与CPU中的MMU(内存管理单元)相似。它的作用是管理设备的内存访问请求,允许安全、高效地在设备和内存之间直接传输数据。IOMMU通常用于支持高速数据传输的设备,如图形卡、网络卡和存储设备。 IOMMU与MMU相似,IOMMU是把外部设备地址到存储器地址的转换。IOMMU中存放了IO页表虚实地址转换关系和访问权限,而且处理器加速虚实地址转换,还设置了IOTLB作为IO页表的Cache。
SMMU 专指在ARM架构中使用的内存管理单元,具有与x86/x64架构中的IOMMU相似的功能。它同样实现了设备的地址转换、内存保护、DMA重映射及虚拟化支持等功能。
尽管二者在功能上相似,它们在实现方式、接口和可能使用的特定命名上有所不同。在ARM系统中,通常采用"SMMU"这个术语,而在x86/x64系统中,则更多使用"IOMMU"这个术语。
简而言之,SMMU和IOMMU在概念上是类似的,都提供设备对内存访问的管理,但SMMU特指ARM架构,而IOMMU则是更广泛使用的术语,可包含多种架构,包括x86/x64和ARM。
一、 IOMMU的原理:
地址转换:
IOMMU实现了从设备发出的DMA(直接内存访问)请求中的I/O虚拟地址到物理地址的转换。这能够在设备和系统内存之间提供保护和隔离。
内存保护:
通过确保设备不能读取或写入它们没有权限的内存区域,IOMMU有助于防止恶意设备驱动程序或硬件故障引起的系统崩溃和安全问题。
DMA重映射:
IOMMU可以重映射DMA请求,允许设备看起来像是连续内存区域的非连续物理内存。
支持虚拟化:
IOMMU对于虚拟化也非常重要,因为它允许虚拟机直接且安全地访问硬件设备,而没有性能上的显著损失。
二、 SMMU 工作原理
地址转换:
SMMU负责将设备发出的DMA请求的I/O虚拟地址(IOVA)转换为系统物理地址(PA)。这个转换关系由SMMU内部的转换表维护,类似于CPU中MMU的页表机制。
内存访问控制:
SMMU提供内存访问控制功能,以确保设备只能访问授权的内存区域。这有助于提高系统的安全性,防止未授权的内存访问导致的安全漏洞。
上下文银行和流ID:
SMMU支持多个“上下文银行”(Context Bank),每个银行关联到一个或多个设备,设备通过流ID(Stream ID)被识别。不同的设备DMA请求可以通过不同的上下文银行进行管理,每个上下文银行包含自己的转换表。
虚拟化支持:
SMMU支持虚拟化技术,允许虚拟机(VM)可直接且安全地访问其虚拟设备的硬件资源。SMMU负责为每个VM管理独立的地址映射和内存保护,使得设备可以在不同的VM间高效切换。
缓存维护:
SMMU可以管理和维护一致性缓存以支持DMA操作。这样设备可以使用缓存来提高DMA操作的性能。
中断重映射:
SMMU也能重新映射来自设备的中断,让中断信号能够正确地传递到宿主机或虚拟机中。
在使用中,SMMU的典型工作流程包括:
设备需要执行DMA传输时,发起带有I/O虚拟地址的请求。
SMMU根据内部转换表将IOVA转换为相应的物理地址。
如果转换合法,SMMU允许DMA传输继续;如果地址转换不合法,则可能会生成一个错误报告,并可中断CPU。
传输完成后,SMMU可以确保任何相关缓存都保持一致。
三、ATS (Address Translation Services)
ATS 是 PCI Express (PCIe) 设备支持的一项特性,它允许设备在内部缓存它自己的 I/O 虚拟地址 (IOVA) 到系统物理地址 (PA) 的翻译,这可以减少对 IOMMU 重复地址翻译的需求。具体来说,启用 ATS 的设备可以执行以下操作
3.1 TLP中AT字段
PCIe总线在TLP中设置了AT字段支持ATS机制,并且只有处理器支持IOMMU时,PCIe设备才可以使用ATS机制。
AT字段为0b00:
当AT字段为0b00时,表示TLP的Address没有通过ATC转换,存放是PCI总线域的物理地址。
1.不支持ATS 机制,处理器不支持IOMMU;TLP的Address是PCI总线域的物理地址,进行DMA操作时,该地址被RC转换为存储器域的物理地址,然后对存储器进行读写操作。
2. 不支持ATS机制,处理器支持IOMMU;TLP的Address是PCI总线域的物理地址,进行DMA操作时,该地址被TA根据I/O页表转换为存储器域的物理地址,然后对存储器进行读写操作。
3. 支持ATS机制,处理器支持IOMMU;进行DMA操作时,该数据被传送到对存储器进行读写操作。
AT字段为0b01:
支持ATS机制的设备必须支持0b01报文,该报文为“Translation Request”,该报文由PCIe设备通过存储器读请求TLP发出,其目的为TA。TA收到报文后将根据I/O页表设置,将合适的地址转换关系通过存储器读完成TLP,发送给PCIe设备,PCIe设备收到这个地址转换关系后,将更新ATC。该TLP有64位和32位两种格式。
3.2 ATS 和 IOMMU 的联系
ATS 与 IOMMU 一起工作时,可以为 PCIe 设备和系统 bieding 更高效的地址翻译服务:
效率改善:
当启用 ATS 的设备需要执行 DMA 操作时,它首先在本地 ATC 中查找地址翻译。如果找到合适的翻译,就不需要再与 IOMMU 通信,提高了效率。
IOMMU的降低负担:
ATS 减少了设备对 IOMMU 的依赖,从而可以减轻 IOMMU 的压力。对 IOMMU 的查询减少意味着总体的系统性能可能提高,特别是在多设备频繁进行 DMA 操作的环境中。
缓存无效化协议:
如果系统内存中的 IOVA 到 PA 的映射发生更改,IOMMU 需要通知所有启用 ATS 的设备更新或无效化它们的 ATC。这是通过一种特定的缓存无效化协议完成的。
安全和一致性:
即使设备使用 ATS 缓存地址翻译,在访问内存之前第一次的地址翻译仍由 IOMMU 管理,确保了系统的安全性。同样,IOMMU 保证即使在使用 ATS 的情况下,系统内存的保护和隔离依然起效。
四、IOMMU/SMMU enable
4.1 x86 架构下
打开BIOS中的虚拟化开关(Intel VT-d)将Disabled置为Enable
路径 PCI Subsystem Configuration/Intel® VT for Directed I/O置为disable,这里默认置灰,不可修改,需要先修改Processor Configuration/X2APIC 置为Disable才可修改Intel® VT for Directed I/O,将XAPIC置为Disable之后打开Intel® VT for Directed I/O
激活linux内核的VT-d开关。
编辑/etc/sysconfig/grub文件(系统引导文件),找到rhgb quiet,在后面添加intel_iommu=on或者amd_iommu=on。
使用grub-mkconfig –o /boot/grub/grub.cfg生成新的系统引导菜单(或者是grub2-mkconfig)
重启使设置生效
使用dmesg | grep -e DMAR -e IOMMU,查看IOMMU是否启用
4.2 arm架构下
在bios中打开smmu
其余CPU /etc/default/grub GRUB_CMDLINE_LINUX=iommu.passthrough=1 iommu.strict=0配置
生成配置文件grub-mkconfig -o /boot/grub/grub.cfg,
重启系统
dmesg | grep -e DMAR -e smmu查看IOMMU是否打开,下图为打开状态: