VT-x

VMCS

​ 使用VMM(Virtual Machine Control Structure)控制虚拟机的状态,它包含了6个部分的内容:

  • Guest-state area: 当发生一次VM exitCPU现在的状态被自动保存到这个区域中; 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 fieldVM exit的原因,方便VMM进行处理。

VM Entry and VM Exit

VM Entry会从root进入Non-root模式,第一次使用VMLAUNCH指令,之后会使用VMRESUME指令。

VM Exit会回到root模式,用于敏感指令检测和中断陷入。

ARM 虚拟化技术

VM Entry and VM Exit

​ 对于eretVMM进入VM,这和操作系统进入用户态的操作是一样的。VMM虚拟化需要自己准备VM的上下文并加载,最后通过eret进入到VM中。

​ 同样地,在vm exit时,即执行敏感指令或者受到中断时,需要VMM保存所有的状态,然后再执行VMM相关的处理程序。

ARMv8.0 Type-2 VMM架构

​ 在EL2只能运行VMM, host os需要大量修改才能运行。这里的设计在EL2做了接受转发的lowvisor, 依靠原本Host OSVMM模块进行处理。

ARMv8.1 Type-2 VMM架构

QEMU/KVM

​ 由ARMv8.1提出的特性,我们可以设计出如上的架构,QEMU运行在用户态,负责实际的处理。同时KVM作为Linux的一个模块运行在EL2,负责对于敏感事件的捕捉,同时直接使用Linux提供的一些功能。

qemu使用ioctlKVM传递命名,如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执行。
  • 对于ARMKVM会主动加载VCPU的所有状态,之后使用eret跳到guest程序执行。

​ 上图中解释这个过程,KVM运行在高特权级充当媒介进行切换。下面是一个更加具体的例子

​ 当一个VM中的程序执行了WFI时,就会被捕获VM ExitKVMKVM处理程序主动将VCPU信息进行保留,根据handler执行相应的函数,它可以使用Linux中现有的一些机制,等待Kernel结果返回后,KVM还可以调度下一个VM程序。

​ 对于一个IO类型的VM Exit的陷入还射击QEMUQEMU运行在用户态,但是由于v8.1中提到的特性这是允许的,QEMU处理完IO可以通过系统调用返回。