程序集 – 是否可以在VM中使用VMX CPU指令?

VM guest虚拟机中的进程是否可能使用VMX(AMD-V,VT-x)CPU指令,然后由外部VMM而不是直接在CPU上处理?

编辑:假设外部VM使用VMX本身来管理其虚拟客户机(即它在Ring -1中运行).

如果有可能支持模拟/拦截VMX调用(VMware,Parallels,KVM,……)的VMM实现?

最佳答案
英特尔的VT-x和AMD的AMD-V也不支持硬件中的完全递归虚拟化 – 其中CPU以与呼叫/读取对相同的方式保持嵌套虚拟化环境的层次结构.

逻辑处理器仅支持两种操作模式:主机模式(在英特尔术语中称为VMX根模式,在AMD中称为虚拟机管理程序)和访客模式(在AMD的手册和英特尔的VMX非根模式中称为).
这意味着一个扁平化的层次结构,其中每个虚拟化环境由CPU处理相同 – CPU不知道VM的层次结构有多少级别.

尝试在guest虚拟机内使用虚拟化指令将产生对监视器(VMM)的控制.
但是最近出现了一些对加速常用虚拟指令的支持,使得嵌套VM成为可能.

我将尝试分析实现嵌套虚拟化所面临的问题.
我不是在处理整个事情 – 我正在考虑基本情况,只是忽略了处理硬件虚拟化的所有部分;本身与软件虚拟化一样有问题的部分.

注意
我不是虚拟化技术方面的专家,根本没有任何经验 – 欢迎更正.
这个答案的目的是让读者在概念上相信嵌套虚拟化是可能的,并概述要面对的问题.

VT-X

逻辑处理器通过执行vmxon进入VMX操作 – 一旦进入模式,处理器就处于根模式.
根模式是VMM的模式,它可以启动,恢复和处理VM.

然后,VMM使用vmptrld设置当前VMCS(VM控制结构) – VMCS包含虚拟化guest虚拟机所需的所有元数据.
VMCS的读写不是直接内存访问,而是使用vmread和vmwrite指令.

最后,VMM执行vmlaunch以开始执行guest虚拟机.

接受虚拟机

现在,逻辑处理器正在虚拟化环境中执行.
假设guest虚拟机本身就是VMM,我们称之为非root VMM – 它需要重复上述步骤.

但英特尔在其手册中很清楚(手册3 – 第25.1.2章):

The following instructions cause VM exits when they are executed in VMX non-root operation:
[…]
This is also true of instructions introduced with VMX, which include:
[…], VMLAUNCH, VMPTRLD, […] and VMXON

vmxon此指令导致VM退出,根VMM从上一次vmlaunch之后的指令恢复,可以检查VMCS以查找退出的原因并采取适当的操作.
我不是一个经验丰富的VMM编写器所以我不确定根VMM必须做什么才能模拟这条指令 – 因为在VMX根模式下执行vmxon会失败并执行vmxoff后跟一个带有VM Region的vmxon非root VMM似乎是一个安全漏洞(或导致它)我相信所有根VMM必须做的是记录guest虚拟机现在处于“VMX根模式”.
这里需要引号:此模式仅存在于软件中,当根VMM将控制权交还给非根VMM时,CPU将处于非root VMX模式.

之后,非根VMM将尝试使用vmptrld设置当前VMCS.
vmptrld将引发VM退出并且根VMM再次处于控制状态 – 如果CPU不支持VMCS shadowing,则根VMM必须记录非根VMM给出的指针现在是当前VMCS – 如果CPU执行支持VMCS遮蔽VMM将其VMCS的VMCS链接指针字段(用于虚拟化非根VMM的VMCS)设置为非根VMM给出的VMCS.
VMM以这种或那种方式知道哪个虚拟化VMCS是活动的.

非root VMM执行的vmread和vmwrite将会或不会导致VM退出.
如果VMCS阴影处于活动状态,则CPU将不执行VM Exit,而是读取活动VMCS(称为影子VMCS)中的VMCS链接指针所指向的VMCS.
这将加速嵌套VM的虚拟化.
如果VMCS阴影未激活,则CPU将退出VM,并且根VMM必须模拟读/写.

最后,非root VMM将启动其VM – 这是一个嵌套的VM.
vmlaunch将触发VM Exit.
根VMM必须做一些事情:

>将VMCS保存在某处.
>合并当前VMCS和非根VMM VMCS – 由于VMCS控制,例如,哪些事件导致VM退出,合并的VM必须是这两者的联合.
>将合并的VMCS加载为CPU的当前VMCS
>做一个vmlaunch / vmresume.

梦想里面

现在CPU正在执行嵌套VM(VVM – 虚拟VM?).
当敏感指令或事件导致VM退出时会发生什么?

从处理器的角度来看,只有两个级别的虚拟化:根VMX模式和非根VMX模式.
由于guest虚拟机处于非root VMX模式,因此控制将转移回根VMX模式代码 – 即根VMM.

根VMM现在必须了解该事件是来自其VM还是来自其VM的VM.
这可以通过跟踪vmlaunch / vmresume的使用并检查VMCS中的位来完成.

如果VM Exit指向非根VMM,则根VMM必须加载其原始VMCS,最终在其中设置非根VMM的链接,更新非根VMM VMCS状态位并执行vmresume.
如果VM Exit指向它,则根VMM将像任何其他VM Exit一样处理它.

梦中的梦想

如果我们想在嵌套VM中创建VM,该怎么办?
一种虚拟虚拟VM(VVVM).

有两件事需要注意:

>根VMM仍然是在每个VM Exit期间调用的VMM.
即使VVVM深度为三级,也不是非根非根VMM是第一个和/或唯一用于虚拟化它的管理器.
从安全角度来看,根VMM是弱链接.
>硬件并不真正支持任意深度嵌套.
VMM可能不需要太多努力就可以从支持1级嵌套到n级嵌套(我再次在这里没有经验丰富),但仍然需要如上所述的特殊支持.
它并不像启动VM那么容易,CPU会处理其他所有事情.

AMD-V

在AMD-v中没有root和非root模式,CPU开始使用vmrun执行VM,该vmrun接收指向VMCB(VM控制块)的指针,该VMCB与Intel的VMCS具有相同的用途.
在vmrun上,CPU处于访客模式.

VMCB已缓存,但只能通过常规内存访问来读取.
vmload / vmsave指令显式加载到缓存中并从缓存中保存受缓存影响的VMCB字段.

这个界面比英特尔的界面更容易,但它同样强大 – 即使在嵌套虚拟化方面也是如此.

假设我们在VM中并且代码执行vmrun – 因此我们正在虚拟化VMM.

从技术上讲,只要vmrun将触发或不触发VM Exit,VMM就可以选择.
然而,实际上,AMD-v目前要求前者始终如此:

The following conditions are considered illegal state combinations:
[…]
* The VMRUN intercept bit is clear

因此,根VMM(我将使用与英特尔案例中相同的术语)将获得控制权并且必须模拟vmrun
(因为硬件仅支持单级虚拟化).

根VMM可以将当前VMCB与非根VMM VMCB保存并合并,并按照英特尔情况继续使用vmrun.

在退出时,root-VMM必须确定退出是指向它还是指向非根VMM,再次可以跟踪vmrun和VMCB中的控制位.

再次做梦

我们在VM中建立了一个相对简单的虚拟机 – 现在虚拟机出口会发生什么?
根VMM接收退出,如果定向到非根VMM,则必须恢复其原始VMCB并恢复运行(即使用vmrun及其原始VMCB).

AMD-v通过考虑其地址访客地址来支持vmsave和vmload指令的快速虚拟化,因此受制于通常的页面嵌套虚拟化.

再次启动Inception

与英特尔的情况一样,只要VMM支持该功能,就可以再次嵌套虚拟化.

针对英特尔案例的重要安全警告也适用于AMD的案例.

‡由于其实现定义的格式以及内存区域可以用作未实时更新的溢出区域这一事实

转载注明原文:程序集 – 是否可以在VM中使用VMX CPU指令? - 代码日志