康华 :主要从事 Linux 操作系统内核、虚拟机、Linux 技术标准、计算机安全、软件测试等领域的研究与开发工作,曾就职 MII-HP 软件实验室 、瞬联软件公司/MOTOROLA,现就职于Lenovo研究院 。其所合写的Linux专栏见http://www.csdn.net/subject/linux/。 如果需要可以联系通过 [email protected] (MSN)联系我.
摘要:本文首先将对虚拟机中各种设备访问方式进行介绍与分析,然后在此基础上重点介绍了虚拟机中模拟光驱的实现,最后进一步分析虚拟机中如何使得虚拟光驱设备具备刻录能力。
Guest系统之所以能运行在虚拟机之上是因为虚拟机为其提供了看来和真实硬件无异的模拟硬件环境。这些硬件环境包含有CPU,总线,时钟,以及各种可能的外设,如显卡,硬盘,光驱,网卡等等。那么Guest 系统具体又是如何访问这些设备呢?或者说这些设备具体如何模拟和实现I/O虚拟化呢? 下面我们就先来归纳一下虚拟机中的设备实现和访问方式。
1 纯模拟设备,如PIT,PCI总线,中断控制器等。这类设备完全由软件模拟,并不和真实的硬件打交道。之所以要将其和真实硬件脱离关系,是因为毕竟虚拟机作为软件需要运行于宿主操作系统之上,而宿主操作系统(Host OS)又必须独占性的使用某些硬件设备,比如系统时钟,总线,中断控制器等(这些设备不同声卡等外设,可以共享使用)。可以想象,如果虚拟机之上Guest 系统也对上述设备访问(比如写中断控制器),那么两个系统的状态就会发生“撞车”,宿主系统就会发生崩溃,Guest系统自然也不可幸免。所以无法将上述设备给Guest OS访问,因此必须完全模拟这些设备。
至于具体有那些设备需要纯模拟实现呢?这要看具体环境。原则上宿主系统独占使用的都应属于这类设备。(引申一下,宿主系统这里理解成直接操作硬件的最下端操作系统。除了传统的操作系统外,虚拟机监控程序(VMM)从某种意义上说也可看是一种宿主系统,不过一般不这么叫)。
2 寄生性设备(找不到合适的名在,暂且这么叫吧),如硬盘,声卡,显卡,光驱等。这类设备需要在虚拟机中先模拟出来(模拟设备目的是为了让Guest系统看到设备的资源信息,以便加载驱动和访问资源),然后虚拟机会将Guest系统对这些设备的访问命令和数据截获,然后转发给真实硬件(主要通过虚拟机截获io、mmio等的访问请求获得命令和数据)。
这是较为笼统的说法,如果细分又可分成两种情况:1 在模拟设备中直接转发I/O请求到物理设备,这里需要做的是将发给VDI(virtual device interface)的参数转化成发给HDI(hardware device interface)参数且下发给HDI(同样道理请求的数据也是从真实硬件获得)。例如,将对虚拟设备的in/out操作直接转发到物理设备对应的端口上。可以想象如果我们模拟的是IDE设备,而真实设备是SCSI设备,那么转换则必须了解IDE和SCSI设备的具体端口和内存映射信息,才又可能建立起正确的转换关系。显然这点不但费力,且移植性不好。2 借助操作系统提供的较高级的用户接口完成虚拟到真实设备的I/O转发。比如借助Linux操作系统的用户驱动接口(如read/ioctl接口等),实现最终对硬件操作。利用操作系统提供的接口访问不需要具体熟悉硬件细节(端口,内存映射信息不必知道),因此具有更强的移植性和方便性。比如vmware系统实现CDROM模拟设备访问:当VMMonitor截获了GUEST 系统给模拟光驱下发的 I/O指令后, 如果发现HOST系统支持光驱设备,那么VMAPP会通过HOST系统提供的用户接口(比如windows上的read接口)对光驱进行读操作,而不需要VMMonitor 自己去具体操作任何cdrom的端口。
寄生性设备一般都不是宿主系统运行必须仰仗的设备,Guest 系统对其的访问不会破坏宿主系统的正常运行。比如声卡,宿主设备不用的时候,可以让Guest系统使用(你用一时,我用一时);硬盘你用一块,我用一块互相不影响。这类设备是可共享使用的。
3 前后端设备, 如网卡,块设备(如硬盘),TPM。这种设备访问方式出现在XEN等虚拟环境中。在XEN环境中,在VMM之上还存在一个叫做domain 0的虚拟机用于管理硬件设备(该虚拟机运行修改过的Linux操作系统,是特权系统,可以直接操作硬件设备),其它domain(称为domainU,非特权)若要访问硬件,则需要经过domain0中qemu模拟设备(如光驱,时钟等,当然模拟代码也可以放在xen中)或者就要通过一种被称为前后端机制的设备访问方式。这种机制的服务对象是那些需要在domain0和domainU中并发共享,而且要求高性能的设备。
前后端机制是指将设备驱动分成后端(backend)和前端(frontend),后端处于domain0;而前端则处于domainU,作为后端的代理,并不需要接触具体硬件细节。前后端通讯通过共享内存等方法,前端设备驱动收到I/O请求后会将请求转发给后端设备,而后端设备会负责对以硬件最终操作的(准确的将它也不直接操作,最后直接操作的应该时Linux自带的网卡驱动)。在我系统中其调用过程如下:dom1 front-end driver -> dom0 back-end driver -> dom0 e1000 driver。
注意:前后端程序都是驱动,运行在内核态直接截获,修改协议栈以达到高速(相比qemu的传统寄生性网卡访问方式速度要高不少)。
4 访问真实设备(在xen中被称作pass through方式)。这种技术出现在VT处理器面世之后(主要用于intel推出的EIT方案),其特点是虚拟机不再需要提供设备模拟,而是让GUEST 系统直接看到真实设备,并操作真实设备。这样做的优点有:1 由于不需要模拟设备进行请求转换,所以访问速度高;2 GUEST系统能根据最新硬件,加载对应驱动,可充分发挥硬件功能;而使用模拟设备时,只能加载模拟的驱动,如果模拟设备功能落后,显然无法充分利用真实硬件的全部潜能。当然缺点也很显然:真实设备只能供一个Guest系统使用 ,而且要注意VMM使用的设备无法pass through 给GUEST 系统。
从原理上来讲PASS THROUGH方式是将PCI设备的资源(中断,IO,MMIO)直接暴露给GUEST OS并允许其直接访问。具体做法是,对于IO资源,VT技术可以允许GUEST系统直接访问而不会被VMM捕获;对于MMIO,则需要处理相对页表,使得GUEST能直接访问到物理设备真实的MMIO空间;中断则需要将真实中断注射到虚拟中断控制器中,以便GUEST能收到真实中断。(除此以外还有很多细节,诸如DMA操作/IOMMU,BIOS操作等,这里步多说了,进一步细节请看VT手册和Xen代码)。
--待续