iommu与virtio
Virtio:虚拟机里的 “虚拟设备总线”
- 作用:让虚拟机(Guest)高效使用宿主机(Host)提供的虚拟设备
- 虚拟网卡:virtio-net
- 虚拟磁盘:virtio-blk
- 虚拟显卡:virtio-gpu
- 虚拟 IOMMU:virtio-iommu
- 本质:前后端通信协议 + 共享内存队列(Virtqueue)
- 特点:半虚拟化,性能远好于纯模拟(e1000、AHCI)
IOMMU:I/O 内存管理单元(硬件 / 虚拟)
- 作用:给外设 DMA 做地址翻译 + 访问控制
- 两种形态:
- 物理 IOMMU:Intel VT-d / AMD-Vi / ARM SMMU
- 虚拟 IOMMU:virtio-iommu(纯软件模拟)
- 核心能力:
- 设备只能访问指定内存区域
- 隔离设备,防止越权 DMA
- 支持 PCI 直通、VFIO
Virtio 和 IOMMU 的关系:三层关系
第一层:普通 Virtio 设备不需要IOMMU
默认情况下:
- virtio-net、virtio-blk 直接读写 Guest 物理内存(GPA)
- Host QEMU 负责翻译 GPA → HPA
- 完全不需要 IOMMU 参与
这是绝大多数云主机的默认状态。
第二层:Virtio 设备可以开启 IOMMU 保护(安全模式)
开启后:
- Guest 内核通过IOMMU 为 virtio 设备分配 IOVA
- 设备 DMA 必须走 IOVA → GPA 翻译
- 即使设备被恶意控制,也只能访问限定内存
- 更安全,符合虚拟化安全规范
QEMU 开启方式:
-device virtio-net-pci,iommu_platform=on第三层:专门的虚拟设备 ——virtio-iommu
这是一个独立的 virtio 设备,功能就是:在 Guest 内部模拟一个完整 IOMMU
它和其他 virtio 设备是并列关系:
- virtio-net:虚拟网卡
- virtio-blk:虚拟磁盘
- virtio-iommu:虚拟 IOMMU
为什么要把 Virtio 和 IOMMU 放一起用?
1. 安全隔离(最重要)
- 不让虚拟设备能访问整个 Guest 内存
- 防止恶意设备 DMA 攻击
- 满足机密计算、安全容器、可信虚拟化要求
2. 兼容 VFIO 框架
- Guest 内部要用 VFIO 把设备给用户态 / 容器
- 必须有 IOMMU 支持
- 无硬件 IOMMU 时,用virtio-iommu模拟
3. 跨架构统一 IOMMU 体验
- x86 VT-d、ARM SMMU 接口不同
- virtio-iommu 提供一套标准协议
- 虚拟机跨平台迁移兼容性更好
4. 嵌套虚拟化需要
在虚拟机里再开虚拟机(嵌套 KVM),需要:
- 内层虚拟机看到一个 IOMMU
- 只能用 virtio-iommu 提供
数据流对比
无 IOMMU 时 Virtio 数据流
Guest 驱动 → Virtqueue → QEMU → 直接读写 GPA无翻译、无隔离。
有 IOMMU 时(物理或虚拟)
Guest 驱动 → IOMMU 分配 IOVA → 设备用 IOVA 发起 DMA → IOMMU 翻译 IOVA → GPA → QEMU 翻译 GPA → HPA多一层地址翻译 + 权限检查。
Virtio 设备 + 物理 IOMMU(VT-d/SMMU)
宿主机开启物理 IOMMU 时:
- Host 用 IOMMU 把虚拟机整体隔离
- Host 限制虚拟机只能访问自己的内存
- 虚拟机内部再用 virtio 或 virtio-iommu
结构:
Host IOMMU(硬件) ↓ VM 隔离 ↓ Guest 内部:virtio-iommu(虚拟) ↓ Virtio 设备典型用于:
- 安全云主机
- 机密虚拟机(SEV/TDX)
- 强隔离多租户环境
物理 IOMMU vs 虚拟 IOMMU
一句话先讲透:
- 物理 IOMMU:真实硬件,负责宿主机 → 物理设备的 DMA 安全与隔离
- 虚拟 IOMMU:软件模拟(QEMU/KVM),负责虚拟机 → 虚拟设备的 DMA 安全与隔离
| 对比项 | 物理 IOMMU | 虚拟 IOMMU |
|---|---|---|
| 实现方式 | 硬件单元(CPU/PCIe 根复合体内置) | 纯软件模拟(QEMU / 虚拟化栈) |
| 工作位置 | Host 侧,管理真实物理设备 | Guest 侧,管理虚拟机里的虚拟设备 |
| 翻译路径 | IOVA → 物理地址 (PA) | IOVA → 虚拟机物理地址 (GPA) |
| 性能 | 极高,硬件并行翻译,无开销 | 较低,需要陷入 Hypervisor、队列交互 |
| 功能完整度 | 完整:ATS/PRI/PASID/ 中断重映射 | 基础:MAP/UNMAP/ATTACH/ 故障上报 |
| 依赖条件 | 必须 CPU + 主板支持 VT-d / AMD-Vi / SMMU | 不依赖硬件,任何机器都能开 |
| 主要作用 | 虚拟机独占物理设备(PCI 直通) | 虚拟机内部做安全隔离、嵌套虚拟化 |
存在位置不同
物理 IOMMU
- 在宿主机硬件上
- Intel VT-d / AMD-Vi / ARM SMMU
- 管控所有真实 PCIe 设备:GPU、网卡、NVMe、HBA
虚拟 IOMMU
- 在虚拟机内部
- 由 QEMU 模拟成一个虚拟设备
- 常见两种:
virtio-iommu(标准通用)intel-iommu(模拟 VT-d,仅 x86)
地址翻译路径完全不同
物理 IOMMU 路径
设备 DMA → IOVA → 物理IOMMU → 物理内存(PA)虚拟 IOMMU 路径
虚拟设备 DMA → IOVA → 虚拟IOMMU → GPA → 物理IOMMU → HPA多一层软件翻译,性能自然更低。
性能差距巨大
- 物理 IOMMU
- 硬件并行处理
- 自带 IOTLB 缓存
- 几乎无性能损耗
- 虚拟 IOMMU
- 每次映射 / 解绑都要 VM Exit / VM Enter
- 依赖 virtqueue 交互
- 高 I/O 场景性能下降明显
功能支持差距
物理 IOMMU 支持
- 多级地址翻译(Stage1 + Stage2)
- PASID / SVA(设备共享进程虚拟地址)
- ATS / PRI(设备 TLB、缺页)
- 中断重映射、防中断注入
- 完整的故障上报与隔离
虚拟 IOMMU(virtio-iommu)
只支持基础功能:
- 映射 / 解绑 IOVA
- 设备绑定到域
- 简单故障上报高级功能基本没有。
使用场景完全不同
物理 IOMMU 用来做什么?
- PCIe 设备直通(Passthrough)把显卡、网卡直接给虚拟机独占
- SR-IOV 硬件虚拟化
- 宿主机强安全隔离
- 防止物理 DMA 攻击
虚拟 IOMMU 用来做什么?
- 虚拟机内部需要IOMMU 驱动的场景
- 虚拟机里跑 VFIO、用户态驱动
- 嵌套虚拟化(虚拟机里再开虚拟机)
- 不支持硬件 IOMMU 的老机器,也要安全 DMA
- 跨平台统一 IOMMU 行为(x86 / ARM 都一样)
总结
- Virtio:虚拟机设备的通用高效通信协议
- IOMMU:给设备 DMA 做地址翻译与内存隔离
- Virtio + IOMMU:
- 要么是给 virtio 设备加安全保护
- 要么是用 virtio-iommu 这个虚拟设备,在 Guest 里模拟一个 IOMMU
