图5:显卡直接分配与QEMU虚拟外设技术对比
开源的KVM虚拟机目前已经支持对标准PCI设备的直接透传(需要硬件具备I/O虚拟化能力,即需要硬件对VT-d或IOMMU技术的支持),但还没能够支持显卡的直接透传。主要有两方面原因:一个是因历史遗留问题,X86体系架构下的显卡设备为实现兼容,留下了一些不同于标准PCI设备的内存和I/O端口;另一个是因显卡其自身高速处理需要,各显卡厂商可能会有一些特别的设计(如独立显存和共享显存的设计、特殊访问接口等),针对显卡不能完全像标准PCI设备一样简单的实现设备直接透传。
这里我们借鉴XEN虚拟机下基于VT-d技术的显卡直接分配技术[6],解决了KVM基于直接地址映射技术的显卡设备直接分配难题。在KVM中实现显卡直接分配,需要解决好显卡在虚拟机总线中的注册、PCI配置空间虚拟、显卡资源(显存及I/O地址)映射、VGABIOS调用、DMA映射等一系列问题。本文将针对以上问题展开研究。
6.1 显卡在KVM虚拟机中的注册
KVM使用QEMU用户态进程虚拟外设,显卡如果在虚拟机中使用必须首先在QEMU中注册为一个称为pci-assign的特殊qdev虚拟设备。pci-assign虚拟设备是QEMU中专门为PCI透传定义的虚拟设备类型,每一个被透传到虚拟机中的PCI设备都会被注册为一个pci-assign虚拟设备,客户机操作系统对该虚拟设备进行的MMIO访问等操作都被直接转发到对应的真实物理设备上。该功能的实现
11
已经在QEMU-KVM源代码中包含,只需要在启动KVM时通过命令行指定要映射的PCI设备BDF号(总线号、设备号、功能号)即可实现将该设备注册到虚拟机中。
但是做为显卡设备,仅仅注册为pci-assign虚拟设备并不能完全将显卡启用,虚拟机中能够从PCI资源中看到该显卡,但是显卡依然无法工作,还需要进一步完成后续的工作。
6.2 显卡专用总线的注册
因为其性能需要,X86架构下大部分平台都将物理显卡挂接在独立的一根PCI总线(总线1或总线2)上,有些厂商的显卡驱动会对显卡BDF号进行检测,如果显卡在物理主机上的BDF号与虚拟机中注册的BDF号不一致,将无法正确驱动显卡(笔者试验用的NVIDIA Geforce G205M显卡就存在这个问题)。因此,为确保显卡直接分配技术在各类显卡中能够通用,需要在注册显卡到虚拟机中时确保显卡在虚拟机中的BDF号与真实机器的BDF号保持一致。
QEMU中缺省只虚拟了一条PCI总线(总线0),虚拟的磁盘控制器、CD-ROM驱动器、网卡、显卡、声卡等设备都注册在这条总线上。为满足显卡直接分配的需要,我们要修改QEMU源码多注册两条PCI总线。这里我们利用QEMU中已实现的虚拟PCI桥设备,在虚拟机的系统总线初始化时注册2个QEMU DEC 21154 虚拟PCI桥设备,创建了总线1和总线2。然后我们修改QEMU注册PCI设备的实现方式,指定将透传显卡设备按照其真实主机上BDF相同的总线号、设备号、功能号进行一一对应的注册。这样就实现了显卡在虚拟机中与在真实主机上具有相同的BDF,以使得显卡驱动能够直接驱动显卡。
6.3 显卡资源直接映射
6.3.1 历史遗留资源映射
自第一台IBM PC问世以后,显卡经历了MDA, Mono Hercults, CGA, EGA, VGA, XGA, SVGA等等标准,总线也由ISA, EISA, VESA, PCI, AGP直到现在的PCIE,前前后后共约30年的进程。虽然好多硬件都渐渐湮没在历史的洪流中,但是由于兼
12
容性需要,一些内存或I/O端口还是作为历史遗留资源在X86硬件体系中保留了下来。
在Intel制定PCI总线标准时,在PCI空间保留了从0开始连续1MB的Memory空间和从0开始连续64KB的I/O空间,其中给显卡预留的空间见表1。
表1:PCI显卡历史遗留资源
类型 内存空间 地址范围 0xA0000 ~ 0xAFFFF 0xB0000 ~ 0xB7FFF 0xB8000 ~ 0xBFFFF 0xC0000 ~ 0xCFFFF I/O 空间 0x3B0~0x3DF 用途 VGA显示缓冲区 MDA或Hercults单显卡显示缓冲区 CGA/EGA显示缓冲区 VGA BIOS 专用 显卡控制寄存器I/O空间 在PC机启动的时候,BIOS程序会扫描整个PCI空间,发现有PCI显卡时,会使能它的Mem访问和I/O访问,同时会配置它的内存空间和I/O空间。但是上面提到的那两块保留的内存空间和I/O空间是不需要作专门配置的,PCI显卡可以直接响应落在这两段空间上的PCI访问请求。
进行显卡透传时必须将物理主机特殊的预留内存和I/O地址空间直接映射到虚拟机对应的地址空间中,以保证显卡初始显示。对于0xA0000 ~ 0xBFFFF内存空间向虚拟机的映射,我们借助Linux下特有的/dev/mem设备实现,通过/dev/mem设备可以访问到整个PC的全部物理内存。我们修改QEMU源代码,在分配了虚拟机的内存后(得到一个应用层地址空间的虚地址),直接打开/dev/mem设备,将地址0xA0000到0xBFFFF内存使用mmap方式直接映射到QEMU虚拟机的内存空间对应偏移地址处。
对于I/O端口0x3B0~0x3DF的映射,可直接向QEMU中注册IO读写函数,该函数从应用层空间上转发对应的读写操作到真实主机的I/O端口上。
6.3.2 显卡资源映射
除历史遗留资源外,各种显卡还有其特有的内存和I/O资源,需要将这些资源都映射进虚拟机中。
13
Linux下的SYSFS系统提供了一种从应用层访问内核资源的简单途径。所有的PCI设备资源在系统初始化时都自动映射成/sys/bus/pci目录下的文件,应用层如果访问这些资源可直接打开文件将其mmap到内存中,对映射内存的读写操作都会传送到PCI设备的内存空间中。在注册物理显卡到虚拟机时,需要将对应的显卡资源也映射到虚拟机的地址空间中去。
6.4 显卡的PCI配置空间
在实现显卡直接分配时,最重要的是显卡的PCI配置空间虚拟化。PCI配置空间是用来动态配置PCI设备资源占用的一组寄存器,每个PCI设备都有自己独立的配置空间,在系统初始化时,由BIOS(也可在操作系统中配置)根据一定的算法分配PCI设备所占有的资源,并将资源信息写入PCI设备配置空间。
PCI总线规范[7]定义的配置空间总长度为256个字节,配置信息按一定的顺序和大小依次存放。前64个字节的配置空间称为配置头,对于所有的设备都一样,配置头的主要功能是用来识别设备、定义主机访问PCI卡的方式(I/O访问或者存储器访问,还有中断信息)。其余的192个字节称为本地配置空间,主要定义卡上中断、I/O端口资源、内存基地址及范围等信息。PCI配置空间中的基地址寄存器BAR(Base Address Registers)就是用于配置PCI设备在系统中占用的I/O及内存地址及范围的寄存器。
对于普通PCI设备,可以直接虚拟PCI配置空间,由KVM虚拟机的BIOS在启动时重新配置该空间中的BAR和中断号等信息。但有些厂商的显卡则必须实现虚拟机里基地址寄存器值等于物理设备上基地址寄存器的值(VBAR=PBAR),原厂驱动才能够正确驱动显卡。因此,为保证显卡透传功能的通用性,我们针对显卡都采用VBAR=PBAR的映射方式。这需要为显卡透传专门修改虚拟机BIOS,使得其在开机初始化时针对显卡保留其与PBAR一致的虚拟机IO及内存资源。
针对显卡的透传修改QEMU代码,在注册pci-assign虚拟设备时将设备真实PCI配置空间内容完整复制到虚拟配置空间。然后修改SeaBIOS(KVM虚拟机使用的BIOS)中PCI设备探测与资源分配部分的代码,在虚拟机SeaBIOS设置显卡各配置寄存器时,首先读取虚拟配置空间中的真实设备配置信息,优先为显卡分配虚拟机 “硬件”资源,确保被透传的显卡与真实显卡保持一致的基地址寄存
14
器配置信息。对于显卡中断等配置则可以根据需要由虚拟机进行映射转换,中断号的虚拟不影响显卡透传。
6.5 VGA BIOS
显卡也具有与主板上一样的基本输入输出系统(BIOS),称为VGA BIOS。系统加电启动时,主板BIOS会寻找到显卡,复制显卡中的VGA BIOS到系统预留VGA BIOS专用内存空间中(地址0xC0000 ~ 0xCFFFF),并调用VGA BIOS初始化显卡。
每种显卡都有自己专用的VGA BIOS,存储在显卡ROM存储区或主板BIOS中。如果需要在虚拟机中初始化显卡,则必须在虚拟机BIOS中重新调用VGA BIOS。因此,我们需要提取VGA BIOS文件给虚拟机,由虚拟机启动时将该VGA BIOS代码复制到VGA BIOS专用内存空间中执行显卡的初始化。
显卡VGA BIOS的提取有很多种方式,具体如何提取需要视主板或显卡情况而定。大部分显卡的VGA BIOS可以用工具从内存中提取(如AFLASH、GPU-Z等)。但有些显卡,如NVIDIA显卡,在VGA BIOS执行时会自动修改自己在内存中的部分代码,直接提取到的VGA BIOS无法用来初始化显卡。笔记本电脑集成的显卡通常都会将显卡BIOS集成到主板BIOS中,我们可以通过提取主板BIOS,分析出显卡BIOS存储位置,提取对应的VGA BIOS。
6.6 DMA映射
显卡的DMA映射问题,采用直接地址映射技术技术解决,通过修改Linux操作系统内核,预留从0x0x100000(1M)地址开始的物理内存空间,直接映射给客户机操作系统使用,解决了客户机操作系统下直接对显卡DMA的处理。
7 小结
虚拟机显卡透传技术解决了虚拟客户机操作系统图形显示效果差的难题。在终端安全领域,显卡透传技术通过客户机操作系统直接驱动物理显卡获得高质量显示效果,使得虚拟机中的客户操作系统具有更普遍的适应性,能够满足普通用
15
户的使用需求,为基于全系统虚拟化技术的操作系统安全增强、进程控制、病毒防护等技术的研究成果更进一步的拓展了实用空间。
由于时间和能力所限,本技术的研究成果主要适用于当前主流的独立显存的显卡,对于一些特殊显卡或共享显存的集成显卡还会有些特殊处理,这里不再详述。通过在华硕K40IP笔记本电脑(支持VT-x,不支持VT-d)上验证,主机向客户机操作系统直接分配NVIDIA G205M显卡,并安装原厂驱动进行测试,测试证明虚拟机操作系统的显示效果得到质的提升,获得了和主机显示完全接近的效果。
参考文献
[1] 马文琦. 基于虚拟化的多域安全框架及其关键技术研究[D]. 湖南长沙:国防科学技术大学研究生院,2008
[2]英特尔开源软件技术中心,复旦大学并行处理研究所.系统虚拟化——原理与实现.清华大学出版社,2009
[3]Qumranet.KVM-kernel-based Virtual Machine white paper.2006 [4]How to assign devices with VT-d in KVM[DB/OL].http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM.2010
[5]河秦,王洪涛.Linux2.6内核标准教程.人民邮电出版社,2008
[6]Beng Heng Ng, Billy Lau and Atul Prakash. Direct Access to Graphics Card Leveraging VT-d Technical Report Online July 20, 2009
[7]PCI LOCAL BUS SPECIFICATION,REV 3.0
16