为了解决2.1.2节提到的上下文切换问题,Intel VT-x引入了VMCS。VMCS是内存中的一块区域,用于在VM-Entry和VM-Exit过程中保存和加载Hypervisor和虚拟机的寄存器状态。此外,VMCS还包含一些控制域,用于控制CPU的行为。本节将简要介绍VMCS的组成与使用方式。
在多处理器虚拟机中,VMCS与vCPU一一对应,每个vCPU都拥有一个VMCS。当vCPU被调度到物理CPU上运行时,首先要将其VMCS与物理CPU绑定,物理CPU才能在VM-Entry/VM-Exit过程中将vCPU的寄存器状态保存到VMCS中。Intel VT-x提供了两条指令,分别用于绑定VMCS和解除VMCS绑定:
(1)VMPTRLD <VMCS地址>:将指定VMCS与当前CPU绑定。
(2)VMCLEAR <VMCS地址>:同样以VMCS地址为操作数,将VMCS与当前CPU解除绑定,该指令确保CPU缓存中的VMCS数据被写入内存中。
在发生vCPU迁移时,需要先在原物理CPU上执行VMCLEAR指令,而后在目的物理CPU上执行VMPTRLD指令。此外,VMCS虽然是内存区域,但是英特尔软件开发手册 指出通过读写内存的方式读写VMCS数据是不可靠的,因为VMCS数据域格式与架构实现是相关的,而且部分VMCS数据可能位于CPU缓存中,尚未同步到内存中。Intel VT-x提供VMREAD与VMWRITE指令用于读写VMCS数据域,格式如下:
(1)VMREAD <索引>:读取索引指定的VMCS数据域。
(2)VMWRITE <索引><数据>:将数据写入索引指定的VMCS数据域。
VMCS区域大小不固定,最多占用4KB,VMCS的具体大小可以通过查询MSR(Model Specific Register,特殊模块寄存器)IA32_VMX_BASIC[32∶44]得知。VMCS结构如图2-5所示。
图2-5 VMCS结构
VMCS版本标识符(VMCS revision identifier)指明了VMCS数据域(VMCS data)的格式,VMX中止指示符(VMX-abort indicator)则记录了VMX的中止原因。VMCS数据域则包括以下六部分:
(1)客户机状态域 (Guest-state area)。保存虚拟机寄存器状态的区域,主要包括CR0和CR3等控制寄存器、栈指针寄存器RSP、PC寄存器RIP等重要寄存器的状态。
(2)宿主机状态域 (Host-state area)。与客户机状态域类似,是保存Hypervisor寄存器状态的区域,它包含的寄存器与客户机状态域大致相同。
(3)VM-Execution控制域 (VM-Execution control fields)。控制客户机在非根模式下运行时的行为,如哪些指令会触发VM-Exit、外部中断是否引发VM-Exit等。在2.1.3节提到,将物理中断转化为虚拟中断注入虚拟机要求物理中断能够触发虚拟机下陷,这一特性由VM-Execution控制域中的外部中断退出(External-Interrupt Exiting)字段控制,当该位置为1时,外部中断将会触发VM-Exit,若为0则不会触发VM-Exit,直接由Guest处理。ELI和DID都利用了该特性直接递交中断。
(4)VM-Exit控制域 (VM-Exit control fields)。控制VM-Exit过程中的某些行为,如VM-Exit过程中需要加载哪些MSR。
(5)VM-Entry控制域 (VM-Entry control fields)。控制VM-Entry过程中的某些行为,如VM-Entry后CPU的运行模式。
(6)VM-Exit信息域 (VM-Exit information fields)。用以保存VM-Exit的基本原因及其他详细信息。
从以上描述不难发现,VMCS对硬件辅助虚拟化具有极其重要的意义,几乎影响了虚拟化的方方面面。图2-6主要展示了VMCS在VM-Entry和VM-Exit过程中的作用,后续章节还会涉及部分VMCS域的具体功能。
图2-6 VM-Entry/VM-Exit过程中VMCS的作用
注:①保存客户机状态;②加载宿主机状态;③Hypervisor获取退出原因;④保存宿主机状态;⑤加载客户机状态;⑥指令执行顺序。