内核虚拟化:CPU虚拟化硬件支持

Intel VT中的VT-x技术扩展了传统的IA32处理器架构,为IA32架构的处理器虚拟化提供了硬件支持。

首先,VT-x引入了两种操作模式,统称为VMX操作模式。

  • 根操作模式(VMX Root Operation):VMM运行所处的模式,以下简称根模式。

  • 非根操作模式(VMX Non-Root Operation):客户机运行所处的模式,以下简称非根模式。

这两种操作模式与IA32特权级0至特权级3是正交的,即每种操作模式下都有相应的特权级03。故在VT-x使用的情况下,描述程序运行在某个特权级,例如特权级0,还必须指出当前是处在根模式还是非根模式

引入两种操作模式的理由很明显。指令的虚拟化是通过“陷入再模拟”的方式实现的,而IA32架构有19条敏感指令不能通过这种方式处理,导致了虚拟化漏洞。最直观的解决办法,是使得这些敏感指令能够触发异常。可惜这种方法会改变这些指令的语义,导致与原有软件不兼容,这是不可接受的。引入新的模式可以很好地解决问题。非根模式下所有敏感指令(包括19条不能被虚拟化的敏感指令)的行为都被重新定义,使得它们能不经过虚拟化就直接运行或通过“陷入再模拟”的方式来处理;在根模式下,所有指令的行为和传统IA32一样,没有改变,因此原有的软件都能正常运行。

VT-x中,非根模式下敏感指令引起的“陷入”被称为VM-Exit。VM-Exit发生时,CPU自动从非根模式切换为根模式。相应地,VT-x也定义了VM-Entry,该操作由VMM发起,通常是调度某个客户机运行,此时CPU从根模式切换成为非根模式。

其次,为了更好地支持CPU虚拟化,VT-x引入了VMCS(Virtual-Machine Control Structure,虚拟机控制结构)。VMCS保存虚拟CPU需要的相关状态,例如CPU在根模式和非根模式下的特权寄存器的值。VMCS主要供CPU使用,CPU在发生VM-Exit和VM-Entry时都会自动查询和更新VMCS。VMM可以通过指令来配置VMCS,进而影响CPU的行为。

最后,VT-x还引入了一组新的指令,包括VMLAUCH/VMRESUME用于发起VM-Entry,VMREAD/VMWRITE用于配置VMCS等。

VMCS

VMCS的概念和虚拟寄存器的概念类似,可以看作是虚拟寄存器概念上在硬件上的应用。虚拟寄存器的操作和更改完全由软件执行,但VMCS却主要由CPU操作。VMCS是保存在内存中的数据结构,包含了虚拟CPU的相关寄存器的内容和虚拟CPU相关的控制信息,每个VMCS对应一个虚拟CPU。

VMCS在使用时需要与物理CPU绑定。在任意给定时刻,VMCS与物理CPU是一对一的绑定关系,即一个物理CPU只能绑定一个VMCS,一个VMCS也只能与一个物理CPU绑定。VMCS在不同的时刻可以绑定到不同的物理CPU,例如在某个VMCS先和物理CPU1绑定,并在某一个时刻解除绑定关系,并重新绑定到物理CPU2。这种绑定关系的变化被称为VMCS的迁移(Migration)。

VT-x提供了两条指令用于VMCS的绑定与解除绑定。

  • VMPTRLD<VMCS地址>:将指定的VMCS与执行该指令的物理CPU绑定。

  • VMCLEAR:将执行该指令的物理CPU与它的VMCS解除绑定。该指令会将物理CPU缓存中的VMCS结构同步到内存中去,从而保证VMCS和新的物理CPU绑定时,内存中的值是最新的。

VMCS的一次迁移过程如下:

  1. 在CPU1上执行VMCLEAR,解除绑定。

  2. 在CPU2上执行VMPTRLD,进行新的绑定。

VT-x定义了VMCS的具体格式和内容。规定它是一个最大不超过4KB的内存块,并要求是4KB对齐。描述了VMCS的格式,各域描述如下。

VMCS块格式如下表所示。

字节偏移描述
0VMCS revision identifier
4VMX-abort indicator
8VMCS data(implementation-specific format)
  1. 偏移0处是VMCS版本标识,表示VMCS数据格式的版本号。

  2. 偏移4处是VMX中止指示,VM-Exit执行不成功时产生VMX中止,CPU会在此处存入VMX中止的原因,以方便调试。

  3. 偏移8处是VMCS数据域,该域的格式是CPU相关的,不同型号的CPU可能使用不同格式,具体使用哪种格式由VMCS版本标识确定。

VMCS主要的信息存放在“VMCS数据域”,VT-x提供了两条指令用于访问VMCS。

  • VMREAD<索引>:读VMCS中“索引”指定的域。

  • VMWRITE<索引> <数据>:写VMCS中“索引”指定的域。

VT-x为VMCS数据域的每个字段也定义了相应的“索引”,故通过上述两条指令也可以直接访问VMCS数据域中的各个域。

具体而言,VMCS数据域包括下列6大类信息。

  1. 客户机状态域:保存客户机运行时,即非根模式时的CPU状态。当VM-Exit发生时,CPU把当前状态存入客户机状态域;当VM-Entry发生时,CPU从客户机状态域恢复状态。

  2. 宿主机状态域:保存VMM运行时,即根模式时的CPU状态。当VM-Exit发生时,CPU从该域恢复CPU状态。

  3. VM-Entry控制域:控制VM-Entry的过程。

  4. VM-Execution控制域:控制处理器在VMX非根模式下的行为。

  5. VM-Exit控制域:控制VM-Exit的过程。

  6. VM-Exit信息域:提供VM-Exit原因和其他信息。VM-Exit信息域是只读的。

VMX操作模式

作为传统IA32架构的扩展,VMX操作模式这个功能在默认情况下时关闭的,因为传统的操作系统不需要这个功能。

当VMM需要使用这个功能时,可以使用VT-x提供新的指令来打开与关闭这个功能:

image-20230721160609812

X86处理有4个特权级别Ring0~Ring3,只有运行在 Ring0 ~ 2级时,处理器才可以访问特权资源或执行特权指令。 运行在 Ring 0 级时,处理器可以访问所有的特权状态。Linux只使用Ring 0和Ring 3这两个级别, 操作系统运行在Ring 0级,用户进程运行在Ring 3级。

Intel硬件虚拟化技术VT-x。VT-x为处理器增加了两种操作模式:VMX root operation 和 VMX non-root operation。 VMM 自己运行在VMX root operation 模式,VMX non-root operation 模式则由Guest OS 使用。 两种操作模式都支持Ring 0 ~ Ring 3 这 4 个特权级,因此VMM和 Guest OS 都可以自由选择它们所期望的运行级别。

VMX(Virtual Machine Extension)通过引入根运行模式(VMX root operation) 和非根模式(VMX non-root operation),直接让vCPU运行在逻辑CPU上,在软件上省去了对vCPU运行的模拟,大大提升了性能。 剩下的就是对vCPU状态的记录了,为此Intel引入了VMCS(Virtual Machine Control Structure)功能。

VM-Entry/VM-Exit

VMM在机器加电引导后,会进行类似操作系统一样的初始化工作,并在准备就绪时通过VMXON指令进入根模式。在创建客户机时,VMM会通过VMLAUNCH或VMRESUME指令切换到非根模式运行客户机,客户机引起VM-Exit后又切换回根模式运行VMM。

VM-Entry

VM-Entry是指CPU由根模式切换到非根模式,从软件角度看,是指CPU从VMM切换到客户机执行。这个操作通常由VMM主动发起。在发起之前,VMM会设置好VMCS相关域的内容,例如客户机状态域、宿主机状态域等,然后执行VM-Entry指令。

VT-x为VM-Entry提供了两条指令。

  • VMLAUNCH:用于刚执行过VMCLEAER的VMCS的第一次VM-Entry。

  • VMRESUME:用于执行过VMLAUNCH的VMCS的后续VM-Entry。

VM-Entry的具体行为由VM-Entry控制域规定,该域的具体定义如下图。

VMCS VM-Entry控制域

VM-Entry控制域中的“事件注入控制”用到了VM-Entry Interruption-Information字段,下图列出该字段的格式。

VM-Entry Interruption-Information字段的格式

每次VM-Entry时,在切换到客户机环境后即将执行客户机指令前,CPU会检查这个32位字段的最高位(即bit31)。如果为1,则根据bit10:8指定的中断类型和bit7:0指定的向量号在当前的客户机中引发一个异常、中断或NMI。此外,如果bit11为1,表示要注入的事件有一个错误码(如Page Fault事件),错误码由另一个VMCS的寄存器VM-Entry exception error code指定。注入的事件最终是用客户机自己的IDT里面指定的处理函数来处理的。这样在客户机虚拟CPU看来,这些事件就和没有虚拟化的环境里面对应的事件没有任何区别。

VM-Entry的过程

当CPU执行VMLAUNCH/VMRESUME进行VM-Entry时,处理器要进行下面的步骤。

  1. 执行基本的检查来确保VM-Entry能开始。

  2. 对VMCS中的宿主机状态域的有效性进行检查,以确保下一次VM-Exit发生时可以正确地从客户机环境切换到VMM环境。

  3. 检查VMCS中客户机状态域的有效性;根据VMCS中客户机状态域来装载处理器的状态。

  4. 根据VMCS中VM-Entry MSR-load区域装载MSR寄存器。

  5. 根据VMCS中VM-Entry事件注入控制的配置,可能需要注入一个事件到客户机中。

第1~4步的检查如果没有通过,CPU会报告VM-Entry失败,这通常意味着VMCS中某些字段的设置有错误。如果所有这些步骤都正常通过了,处理器就会把执行环境从VMM切换到客户机环境,开始执行客户机指令。

VM-Exit

VM-Exit是指CPU从非根模式切换到根模式,从客户机切换到VMM的操作。引发VM-Exit的原因很多,例如在非根模式执行了敏感指令、发生了中断等。处理VM-Exit时间是VMM模拟指令、虚拟特权资源的一大任务。

非根模式下的敏感指令

当成功执行VM-Entry后,CPU就进入了非根模式。敏感指令如果运行在VMX非根操作模式,其行为可能会发生变化。具体来说有如下三种可能。

  1. 行为不变化,但不引起VM-Exit:这意味着虽然是敏感指令,但是它不需要被VMM截获和模拟,例如SYSENTER指令。

  2. 行为变化,产生VM-Exit:这就是典型需要截获并模拟的敏感指令。

  3. 行为变化,产生VM-Exit可控:这类敏感指令是否产生VM-Exit,可以通过VM-Execution域控制。出于优化的目的,VMM可以让某些敏感指令不产生VM-Exit,以减小模式切换带来的上下文开销。

由此可见,使用VT-x技术实现的VMM,并不需要对所有敏感指令进行模拟,这大大减小了VMM实现的复杂性。VM-Execution域的存在又为VMM的实现带来了灵活性。

VM-Execution控制域

VM-Execution控制域用来控制CPU在非根模式运行时的行为,根据虚拟机的实际应用,VMM可以通过配置VM-Execution控制域达到性能优化等目的。VM-Execution控制域主要控制三个方面。

  1. 控制某条敏感指令是否产生VM-Exit,如果产生VM-Exit,则由VMM模拟该指令。

  2. 在某些敏感指令不产生VM-Exit时,控制该指令的行为。

  3. 异常和中断是否产生VM-Exit。

下图列举出一些典型的VM-Execution控制域。

VM-Execution控制域

VM-Exit控制域

VM-Exit控制域规定了VM-Exit发生时CPU的行为,下图描述了该域的内容。

VM-Exit控制域

VM-Exit信息域

VMM除了要通过VM-Exit控制域来控制VM-Exit的行为外,还需要知道VM-Exit的相关信息(如退出原因)。VM-Exit信息域满足了这个要求,其提供的信息可以分为如下4类。

基本的VM-Exit信息,包括如下内容。

  • Exit Reason:提供了VM-Exit的基本原因,如下表所示。

字段描述
Basic exit reasonVM-Exit的基本原因,如果VM-Entry failure为1,该字段表示VM-Entry失败的原因
VM-Exit from VMX root operation该位为1,表示一此VM-Exit发生在CPU处于根模式时
VM-Entry failure该位为1,表示一次VM-Entry失败了
  • Exit qualification:提供VM-Exit的进一步原因。这个字段的值根据VM-Exit基本退出原因的不同而不同。例如,对于因为访问CR寄存器导致的VM-Exit,Exit qualification提供的信息包括:是哪个CR寄存器、访问类型时读还是写、访问的内容等。同样的,VT-x规范也完整地定义了所有VM-Exit退出原因所对应的Exit qualification。对于某些不需要额外信息的退出原因,没有相应的Exit qualification的定义。

  • 事件触发导致的VM-Exit的信息。事件是指外部中断、异常(包括INT3/INTO/BOUND/UD2导致的异常)和NM1。对于此类VM-Exit,VMM可以通过VM-Exit interruption information字段和VM-Exit interruption error code字段获取额外信息,例如事件类型、实现相关的向量号等。

  • 事件注入导致的VM-Exit的信息。一个事件在注入客户机时,可能由于某种原因暂时不能成功,而触发VM-Exit。此时,VMM可以从IDT-vectoring information字段和IDT-vectoring error code中获取此类VM-Exit的额外信息,例如事件类型、时间向量号等。

  • 执行指令导致的VM-Exit的信息。除了第一类中列出的信息外,客户机在执行敏感指令导致VM-Exit时,VMCS中还有三个字段可以提供额外的信息。Guest linear address字段给出了导致VM-Exit指令的客户机线性地址,VM-Exit instruction length字段给出了该指令的长度,VM-Exit instruction information字段给出了该指令为VMX指令时的额外信息。

VM-Exit的具体过程

当一个VM-Exit发生时,依次执行下列步骤。

  1. CPU首先将此次VM-Exit的原因信息记录到VMCS相应的信息域中,VM-Entry interruption-information字段的有效位(bit 31)被清零。

  2. CPU状态被保存到VMCS客户机状态域。根据设置,CPU也可能将客户机的MSR保存到VM-Exit MSR-store区域。

  3. 根据VMCS中宿主机状态域和VM-Exit控制域中的设置,将宿主机状态加载到CPU相应寄存器。CPU也可能根据VM-Exit MSR-store区域来加载VMM的MSR。

  4. CPU由非根模式切换到了根模式,从宿主机状态域中CS:RIP指定的VM-Exit入口函数开始执行。

在VMM处理完VM-Exit后,会通过VMLAUNCH/VMRESUME指令发起VM-Entry进而重新运行客户机。当下一次VM-Exit发生后,又会重复上述处理流程。虚拟化的所有内容就在VMM -> 客户机 -> VMM -> ……的不断切换中完成。

参考

向往的系统虚拟化(四) - Wang kuntian's Blog

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值