虚拟化:初识IOMMU(TODO)

初识IOMMU

最近在尝试给朋友的小主机安装ZStack作为虚拟化管理平台的时候,遇到了一个需求:通过HDMI直接将Windows虚拟机的画面输出到外界显示器。需要解决这个问题自然而然的就需要使用直通的方法将显卡直通给虚拟机。不过之前直通都是直接找别人的博客一步一步傻瓜式执行下去,对于每个指令发生了什么,以及iommu是如何工作的都不清楚。刚好趁着这个机会了解并记录下自己的学习历程

问题来源

我自己现在有一台基于Proxmox VEAll in one小主机了,这里就叫做主机A,而我朋友的主机则称为主机B。在安装ZStack之前,我原以为直通的过程依旧可以无脑用脚本来实现,但是实际执行过程中却发现在PVE中应该成功的ACS的改动在ZStack中却并没有成功。这便引起我了从ACSIOMMU作用的好奇。

启用IOMMU和ACS

首先,在主机A和主机B的BIOS上都启用IOMMU的功能,可以发现原本的iommu分组都十分混乱,大部分设备杂糅在一起。为了解决这个问题,便有了叫做ACS的技术。

ACS的主要功能

  1. 设备隔离:ACS允许对PCIe设备进行更细粒度的控制,增强了设备间的隔离。这在虚拟化环境中尤为重要,因为它可以帮助确保虚拟机之间的安全隔离,防止一个虚拟机访问另一个虚拟机的PCIe设备。
  2. 控制I/O访问:ACS可以控制PCIe设备的I/O访问,例如控制哪些设备可以发起对其他设备或内存的直接内存访问(DMA)。
  3. 提高安全性:通过对设备间访问的更严格控制,ACS有助于提高系统的整体安全性,尤其是在多租户或需要高安全性的环境中。

通过启用iommu的同时启用acs,就可以将系统中iommugroup分成更细的设备单位,具体修改的操作实现参数可能不尽相同,但是基本上都是先对/etc/default/grub中的GRUB_CMDLINE_LINUX进行修改,添加amd_iommu=onpcie_acs_override=downstream,multifunction即可

查看分组情况

对于分组情况的查看,在PCI passthrough via OVMF - ArchWiki (archlinux.org)可以找到一个脚本来列出当前的IOMMU Groups的情况

1
2
3
4
5
6
7
8
#!/bin/bash
shopt -s nullglob
for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do
echo "IOMMU Group ${g##*/}:"
for d in $g/devices/*; do
echo -e "\t$(lspci -nns ${d##*/})"
done;
done;

当我在自己的PVE主机上执行这个脚本之后,可以发现显卡是单独在一个Groups中的

IOMMU分组

但是在ZStack平台上执行以后可以发现核显并不是单独在一个Groups里面的

当时的log没有保存,这里假象一个其他的例子代替,是一个GTX 970显卡的例子,一般来说独显是会有单独的Groups的

1
2
3
4
5
6
7
......
IOMMU Group 13:
06:00.0 VGA compatible controller: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1)
06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)
00:1d.0 USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1
00:1a.0 USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2
......

具体问题的产生原因还不清楚(找到问题以后会来更新博客),不过就IOMMU的分组情况大概是这样。

IOMMU

对于什么是iommu,找到这样一个简单扼要的概括

大家知道,I/O设备可以直接存取内存,称为DMA(Direct Memory Access);DMA要存取的内存地址称为DMA地址(也可称为BUS address)。在DMA技术刚出现的时候,DMA地址都是物理内存地址,简单直接,但缺点是不灵活,比如要求物理内存必须是连续的一整块而且不能是高位地址等等,也不能充分满足虚拟机的需要。后来dmar就出现了。 dmar意为DMA remapping,是Intel为支持虚拟机而设计的I/O虚拟化技术,I/O设备访问的DMA地址不再是物理内存地址,而要通过DMA remapping硬件进行转译,DMA remapping硬件会把DMA地址翻译成物理内存地址,并检查访问权限等等。负责DMA remapping操作的硬件称为IOMMU。做个类比:大家都知道MMU是支持内存地址虚拟化的硬件,MMU是为CPU服务的;而IOMMU是为I/O设备服务的,是将DMA地址进行虚拟化的硬件。

而在这其中,IOMMU分组则是实现设备直通的关键,每个分组都包含了可以共享一同一个虚拟内存映射的设备集合。如果一个设备独占一个IOMMU分组,直通它是很简单的。但是如果多个设备共享同一个分组,比如显卡和USB接口,那么就无法只直通其中一个设备。

TODO

后续就是找时间尝试研究为什么ACSZStack中没有正常被启用,并将结论补充到这篇博客当中。


虚拟化:初识IOMMU(TODO)
https://halc.top/p/4416e368
作者
HalcyonAzure
发布于
2023年11月28日
许可协议