do_vmx_vcpu_run函数实现了VM entry和VM exit的处理
/*
* We put this into a separate noinline function to prevent the compiler
* from duplicating the code. This is needed because this code
* uses non local labels that cannot be duplicated.
* Do not put any flow control into this function.
* Better would be to put this whole monstrosity into a .S file.
*/
static void noinline do_vmx_vcpu_run(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
asm volatile(
/* Store host registers */
"push %%"R"dx; push %%"R"bp;"
"push %%"R"cx /n/t"
"cmp %%"R"sp, %c[host_rsp](%0) /n/t"
"je 1f /n/t"
"mov %%"R"sp, %c[host_rsp](%0) /n/t"
__ex(ASM_VMX_VMWRITE_RSP_RDX) "/n/t"
首先完成host os状态在VMCS中的保存。目前保存rsp,其他三个寄存器为什么需要保存不理解?
"1: /n/t"
/* Reload cr2 if changed */
"mov %c[cr2](%0), %%"R"ax /n/t"
"mov %%cr2, %%"R"dx /n/t"
"cmp %%"R"ax, %%"R"dx /n/t"
"je 2f /n/t"
"mov %%"R"ax, %%cr2 /n/t"
"2: /n/t"
加载cr2,从guest os中对应vcpu的vmcs中获取数据,放到cr2寄存器中。
/* Check if vmlaunch of vmresume is needed */
"cmpl $0, %c[launched](%0) /n/t"
判断是否需要vm launch,对于上次就是从对应vmcs退出的情况,不需要vm launch,使用vm resume,否则需要。
/* Load guest registers. Don't clobber flags. */
"mov %c[rax](%0), %%"R"ax /n/t"
"mov %c[rbx](%0), %%"R"bx /n/t"
"mov %c[rdx](%0), %%"R"dx /n/t"
"mov %c[rsi](%0), %%"R"si /n/t"
"mov %c[rdi](%0), %%"R"di /n/t"
"mov %c[rbp](%0), %%"R"bp /n/t"
#ifdef CONFIG_X86_64
"mov %c[r8](%0), %%r8 /n/t"
"mov %c[r9](%0), %%r9 /n/t"
"mov %c[r10](%0), %%r10 /n/t"
"mov %c[r11](%0), %%r11 /n/t"
"mov %c[r12](%0), %%r12 /n/t"
"mov %c[r13](%0), %%r13 /n/t"
"mov %c[r14](%0), %%r14 /n/t"
"mov %c[r15](%0), %%r15 /n/t"
#endif
"mov %c[rcx](%0), %%"R"cx /n/t" /* kills %0 (ecx) */
加载guest os相关的寄存器,从vcpu对应的结构体中获取。
/* Enter guest mode */
"jne .Llaunched /n/t"
__ex(ASM_VMX_VMLAUNCH) "/n/t"
"jmp .Lkvm_vmx_return /n/t"
".Llaunched: " __ex(ASM_VMX_VMRESUME) "/n/t"
调用VM launch或者vm resume进入non root state,运行vcpu。
".Lkvm_vmx_return: "
/* Save guest registers, load host registers, keep flags */
发生vm exit,导致vcpu退出。
"xchg %0, (%%"R"sp) /n/t"
"mov %%"R"ax, %c[rax](%0) /n/t"
"mov %%"R"bx, %c[rbx](%0) /n/t"
"push"Q" (%%"R"sp); pop"Q" %c[rcx](%0) /n/t"
"mov %%"R"dx, %c[rdx](%0) /n/t"
"mov %%"R"si, %c[rsi](%0) /n/t"
"mov %%"R"di, %c[rdi](%0) /n/t"
"mov %%"R"bp, %c[rbp](%0) /n/t"
#ifdef CONFIG_X86_64
"mov %%r8, %c[r8](%0) /n/t"
"mov %%r9, %c[r9](%0) /n/t"
"mov %%r10, %c[r10](%0) /n/t"
"mov %%r11, %c[r11](%0) /n/t"
"mov %%r12, %c[r12](%0) /n/t"
"mov %%r13, %c[r13](%0) /n/t"
"mov %%r14, %c[r14](%0) /n/t"
"mov %%r15, %c[r15](%0) /n/t"
#endif
"mov %%cr2, %%"R"ax /n/t"
"mov %%"R"ax, %c[cr2](%0) /n/t"
保存guest os对应寄存器的值到对应变量中。
"pop %%"R"bp; pop %%"R"bp; pop %%"R"dx /n/t"
恢复host os的寄存器取值。
"setbe %c[fail](%0) /n/t"
: : "c"(vmx), "d"((unsigned long)HOST_RSP),
[launched]"i"(offsetof(struct vcpu_vmx, launched)),
[fail]"i"(offsetof(struct vcpu_vmx, fail)),
[host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)),
[rax]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RAX])),
[rbx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBX])),
[rcx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RCX])),
[rdx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDX])),
[rsi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RSI])),
[rdi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDI])),
[rbp]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBP])),
#ifdef CONFIG_X86_64
[r8]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R8])),
[r9]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R9])),
[r10]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R10])),
[r11]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R11])),
[r12]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R12])),
[r13]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R13])),
[r14]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R14])),
[r15]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R15])),
#endif
[cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2))
: "cc", "memory"
, R"ax", R"bx", R"di", R"si"
#ifdef CONFIG_X86_64
, "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
#endif
);
}