硬件辅助虚拟化
VT-x
VMCS
使用VMM(Virtual Machine Control Structure)
控制虚拟机的状态,它包含了6个部分的内容:
Guest-state area
: 当发生一次VM exit
,CPU
现在的状态被自动保存到这个区域中;VM Entry
时,又将这个区域的内容加载到CPU
中。Host-state area
: 当发生VM exit
时,可这个区域信息加载到CPU中;VM entry
, 相反。VM-execution control field
: 可以控制non-root
模式中虚拟机的行为。VM-exit control field
: 控制VM exit
的行为。VM-entry control field
: 控制VM entry
的行为。VM-exit information field
:VM exit
的原因,方便VMM
进行处理。
VM Entry and VM Exit
VM Entry
会从root
进入Non-root
模式,第一次使用VMLAUNCH
指令,之后会使用VMRESUME
指令。
VM Exit
会回到root
模式,用于敏感指令检测和中断陷入。
ARM 虚拟化技术
VM Entry and VM Exit
对于eret
从VMM
进入VM
,这和操作系统进入用户态的操作是一样的。VMM
虚拟化需要自己准备VM
的上下文并加载,最后通过eret
进入到VM
中。
同样地,在vm exit
时,即执行敏感指令或者受到中断时,需要VMM
保存所有的状态,然后再执行VMM
相关的处理程序。
ARMv8.0 Type-2 VMM架构
在EL2
只能运行VMM
, host os
需要大量修改才能运行。这里的设计在EL2
做了接受转发的lowvisor
, 依靠原本Host OS
的VMM
模块进行处理。
ARMv8.1 Type-2 VMM架构
QEMU/KVM
由ARMv8.1
提出的特性,我们可以设计出如上的架构,QEMU
运行在用户态,负责实际的处理。同时KVM
作为Linux
的一个模块运行在EL2
,负责对于敏感事件的捕捉,同时直接使用Linux
提供的一些功能。
qemu
使用ioctl
向KVM
传递命名,如CREATE_VM
, CREATE_VCPU
, KVM_RUN
等。
open("/dev/kvm");
ioctl(KVM_CREATE_VM);
ioctl(KVM_CREATE_VCPU);
while(true) {
ioctl(KVM_RUN);
exit_reason = get_exit_reason();
switch (exit_reason) {
case KVM_EXIT_IO:
//....
break;
case KVM_EXIT_MMIO:
//...
break;
}
}
- 在
x86
架构中,需要从VCPU
中找到VMCS
结构,使用CPU
指令加载VMCS
,使用VMLAUNCH
或者VMRESUME
进入到Non-root
, 硬件会自动加载VMCS
状态,跳转到GUEST_RIP
执行。 - 对于
ARM
,KVM
会主动加载VCPU
的所有状态,之后使用eret
跳到guest
程序执行。
上图中解释这个过程,KVM
运行在高特权级充当媒介进行切换。下面是一个更加具体的例子
当一个VM
中的程序执行了WFI
时,就会被捕获VM Exit
到KVM
,KVM
处理程序主动将VCPU
信息进行保留,根据handler
执行相应的函数,它可以使用Linux
中现有的一些机制,等待Kernel
结果返回后,KVM
还可以调度下一个VM
程序。
对于一个IO
类型的VM Exit
的陷入还射击QEMU
,QEMU
运行在用户态,但是由于v8.1
中提到的特性这是允许的,QEMU
处理完IO
可以通过系统调用返回。