虚拟化:初识IOMMU(TODO)
初识IOMMU
最近在尝试给朋友的小主机安装ZStack
作为虚拟化管理平台的时候,遇到了一个需求:通过HDMI直接将Windows虚拟机的画面输出到外界显示器。需要解决这个问题自然而然的就需要使用直通的方法将显卡直通给虚拟机。不过之前直通都是直接找别人的博客一步一步傻瓜式执行下去,对于每个指令发生了什么,以及iommu
是如何工作的都不清楚。刚好趁着这个机会了解并记录下自己的学习历程
问题来源
我自己现在有一台基于Proxmox VE
的All in one
小主机了,这里就叫做主机A,而我朋友的主机则称为主机B。在安装ZStack
之前,我原以为直通的过程依旧可以无脑用脚本来实现,但是实际执行过程中却发现在PVE
中应该成功的ACS
的改动在ZStack
中却并没有成功。这便引起我了从ACS
到IOMMU
作用的好奇。
启用IOMMU和ACS
首先,在主机A和主机B的BIOS上都启用IOMMU的功能,可以发现原本的iommu
分组都十分混乱,大部分设备杂糅在一起。为了解决这个问题,便有了叫做ACS
的技术。
ACS的主要功能
- 设备隔离:ACS允许对PCIe设备进行更细粒度的控制,增强了设备间的隔离。这在虚拟化环境中尤为重要,因为它可以帮助确保虚拟机之间的安全隔离,防止一个虚拟机访问另一个虚拟机的PCIe设备。
- 控制I/O访问:ACS可以控制PCIe设备的I/O访问,例如控制哪些设备可以发起对其他设备或内存的直接内存访问(DMA)。
- 提高安全性:通过对设备间访问的更严格控制,ACS有助于提高系统的整体安全性,尤其是在多租户或需要高安全性的环境中。
通过启用iommu
的同时启用acs
,就可以将系统中iommu
的group
分成更细的设备单位,具体修改的操作实现参数可能不尽相同,但是基本上都是先对/etc/default/grub
中的GRUB_CMDLINE_LINUX
进行修改,添加amd_iommu=on
和pcie_acs_override=downstream,multifunction
即可
查看分组情况
对于分组情况的查看,在PCI passthrough via OVMF - ArchWiki (archlinux.org)可以找到一个脚本来列出当前的IOMMU Groups
的情况
1 |
|
当我在自己的PVE
主机上执行这个脚本之后,可以发现显卡是单独在一个Groups
中的
但是在ZStack
平台上执行以后可以发现核显并不是单独在一个Groups
里面的
当时的log没有保存,这里假象一个其他的例子代替,是一个GTX 970显卡的例子,一般来说独显是会有单独的Groups的
1 |
|
具体问题的产生原因还不清楚(找到问题以后会来更新博客),不过就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
后续就是找时间尝试研究为什么ACS
在ZStack
中没有正常被启用,并将结论补充到这篇博客当中。