原文为vfio mediated device内核文档[5],我翻译一下。 1. Virtual Function I/O (VFIO) Mediated devices[1] 对没有内置SR-IOV功能的设备进行DMA虚拟化的需求越来越多。以前,为了虚拟化一个这样的设备,开发者需要自己开发管理接口和API,然后把它们集成到用户态应用中。为了简化这种用户空间软件集成,我们找出了这种设备公共需求然后开发了一种统一的接口。 VFIO驱动框架为直接设备访问提供了统一的API。它将设备直接访问安全地(以一种IOMMU保护的环境)暴露给用户,是一种IOMMU/设备无关的框架。此框架用于多种设备,如GPU、网卡和计算加速器等。有了这种直接设备访问,虚拟机或者用户态应用可以直接访问物理设备。Mdeiated devices便是重用了VFIO这种框架。 Mediated core driver为mdiated device提供了一个公共的管理接口,它可以被不同类型的设备驱动所利用。这个模块提供了的通用接口可以进行如下操作: 创建和删除mediated device 把一个mediated deivce加入或移出某个总线驱动 把一个mediated device加入或移出某个IOMMU group Mediated core driver也提供注册总线驱动的接口。比如,一个mediated VFIO mdev驱动就是为mediated devices设计的,并且支持VFIO的API。Mediated bus driver可以将一个mediated device加入或者移出一个VFIO group。 以下的上层图展示了VFIO mediated driver框架的主要组件和接口。这张图展示了NVIDIA、Intel和IBM设备,因为这些设备是首先使用这些模块的。 +—————+ | | | +———–+ | mdev_register_driver() +————–+ | | | +<————————+ | | | mdev | | […]

本文是VFIO内核文档[1]的翻译。 很多现代系统提供DMA和中断重映射工具来帮助保证IO在被指定的界限中进行。包括x86硬件的AMD-Vi和Intel VT-d,POWER系统的Partitionable Endpoints (PEs)和嵌入式的PowerPC系统(如Freescale PAMU)。VFIO driver是IOMMU/设备不可知的一个框架,它只是专门用于将设备在安全的、IOMMU保护的环境下直接暴露给userspace。换句话说,VFIO允许安全且非特权的用户态驱动。 我们为什么需要VFIO?一个原因是虚拟机经常时用直接设备访问(“device assignment”)来获得尽可能高的IO性能。从设备和host的角度,这其实就是把VM变成了一个用户态驱动,VM也因此获得了这个IO设备的低延迟、高带宽和全虚拟化原生(bare-metal)设备驱动的直接应用。 一些应用场景中(特别是这高性能计算领域),也会从低开销的从用户空间的直接设备访问获得好处。例子包括网卡(通常基于非TCP/IP)和计算加速器等IO设备。在VFIO之前,这些驱动必须经过很长的开发周期来成为上游驱动、单独分支维护,或者使用UIO框架(UIO并不支持IOMMU保护,并且对中断支持有限,还需要root权限来访问PCI配置空间等东西)。 VFIO驱动框架用来将所有东西统一起来,代替KVM PCI设备assignment的代码,并提供一个比UIO更安全、功能更丰富的用户态驱动环境。 Groups、Devices和IOMMUs 设备是任何IO驱动的主要目标。设备一般会创建包括IO访问、中断和DMA在内的编程接口。不讨论每个驱动的细节,DMA通常是保证安全环境的最重要的部分,这是由于如果不对设备向物理内存的读写操作不设限制,将会造成对整个系统造成极大威胁。 为了减小这种风险,很多现代IOMMU将隔离特性加入到负责地址转换的接口中,这解决了设备在受限制的地址空间的寻址问题。有了这种介质,设备之间或者设备和某块内存间可以实现有效的隔离,这也允许了设备到虚拟机的安全直接管理。 这种隔离性的粒度并不总是单个设备,即使IOMMU可以做到这点,设备的属性、连接方式和IOMMU拓扑结构都可能会减弱这种隔离性。比如,一个独立的设备可能是一个更大范围设备集合的子集,那么即使IOMMU可以辨识出在这一集合中的不同设备,这个集合中的transactions也不会需要经过IOMMU。例如,从一个functions之间有后门的多function PCI设备,到一个non-PCI-ACS (Access Control Services)bridge的任何东西都允许不经过IOMMU的重定向。拓扑结构也在隐藏设备这件事中扮演着很重要的角色。一个PCIe-to-PCI的bridge隐藏了它之后的所有设备,让transaction看起来就来自bridge本身。显然,IOMMU也承担了主要的任务。 因此,虽然大多数情况下IOMMU可以达到设备级的隔离粒度,系统一般也是容忍这个粒度被放宽的。IOMMU API也因此支持IOMMU group的概念。一个group就是一组设备的集合,这组设备隔离于系统的其他设备。Group因此也是VFIO所用的ownership的单元。 虽然group是保证用户访问安全的最小粒度,它并不一定是最好的粒度。在使用page tables的IOMMU中,多个groups之间共享一组page table是可能的,这减小了硬件平台的开销(减少TLB thrashing、减少重复page table等),也减小了用户的开销(只编写一个set的转换即可)。因此,VFIO使用了一个container的概念,一个class可以包括一个或者多个groups。创建一个container很简单,只要打开/dev/vfio/vfio字符设备即可。 Container自身只提供很少的功能,。。。 用户需要将group加到container中来获得下一级的功能。要这样做,用户首先需要找到所关心设备所属的group,这可以用下边例子中的sysfs链接办到。通过将设备从host驱动解绑并绑定到VFIO驱动上,一个新的VFIO group会出现为/dev/vfio/$GROUP,其中$GROUP是IOMMU的group number,目标的设备是这个group的成员。如果IOMMU group有多个设备,那么这个VFIO group可用前,每个设备都需要绑定到一个VFIO驱动上(只是将所有设备从host驱动解绑也可以,这也会让group可用,但是没有绑定VFIO设备的特定设备不可用)。待定:禁用驱动probing/locking一个设备的接口。 如果group准备好了,可以通过open这个VFIO group字符设备(/dev/vfio/$GROUP)将这个group加入到container中,并用ioctl的VFIO_GROUP_SET_CONTAINER参数将打开的container文件描述符fd传入。如果需要在多个group间分享IOMMU上下文中,过个group可以被设置(set)到一个相同的container。如果一个group无法被set到一个container,那么一个空的container将被使用。 如果一个或多个group被加入到一个container,那么剩下的ioctl参数就可用了,可以访问VFIO IOMMU接口了。而且,现在在VFIO group的fd上用ioctl可以得到每个设备的文件描述符。 VFIO设备的API包括描述设备、描述IO region、描述设备描述符上read/write/mmap偏移量的ioctl参数,也包括描述和注册中断通知的机制。 VFIO使用实例 假如我们想访问PCI设备0000:06:0d.0: $ readlink /sys/bus/pci/devices/0000:06:0d.0/iommu_group ../../../../kernel/iommu_groups/26 因此这个设备在IOMMU group 26。这个设备在pci bus上,所以用户会用vfio-pci管理这个组: # modprobe vfio-pci 绑定这个设备到vfio-pci驱动并为这个group创建VFIO […]