VMX根模式与非根模式的切换与进程间的切换颇为相似,当要从根模式切换到非根模式时,Host上的context保存在VMCS上的host状态域,guest自然是guest域了。
先看host上为即将到来的模式切换所做的准备:
ioctl() -->vmx_create_vcpu()-->vmx_vcpu_setup() -->vmx_set_constant_host_state(vmx)
arch/x86/kvm/vmx.c:
static void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
{
...
vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */
...
vmcs_writel(HOST_RIP, vmx_return); /* 22.2.5 */
...
}
先重点关注下CS:RIP. RIP指向vmx_return, 后者的定义出现在vmx_vcpu_run()中正在做模式切换的汇编代码中,那里是真正进行模式切换的地方:
static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
{
...
/* Enter guest mode */
"jne 1f \n\t"
__ex(ASM_VMX_VMLAUNCH) "\n\t"
"jmp 2f \n\t"
"1: " __ex(ASM_VMX_VMRESUME) "\n\t"
"2: "
...
".pushsection .rodata \n\t"
".global vmx_return \n\t"
"vmx_return: " _ASM_PTR " 2b \n\t"
".popsection"
...
}
里面的VMLAUNCH和VMRESUME指令用来进入non-root(guest)模式,当发生VM-EXIT时,host的入口点从vmx_return处开始执行(vm-exit时,物理cpu加载vmcs上的host状态域所记录的寄存器者,尤其是cs:rip,这个我们之前已经看到在进入non-root模式时,vmcs.rip=vmx_return), 而vmx_return的地址恰在那段汇编代码的label 2处,这意味着一旦vm-exit,host首先会出2:处开始执行,也即:Save guest registers, load host registers, keep flags. 所以这里应该很清楚了,当一个guest因为某种原因导致vm-exit返回到host时,host的入口点即为vmx_return.
但是在第一次进入guest模式时, guest入口点在哪里呢?我记得我以前好像写过