do_vmx_vcpu_run函数实现了VM entry和VM exit的处理

1430阅读 0评论2013-12-30 embeddedlwp
分类:LINUX

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
       );
}


上一篇:linux kernel 中的 CPU指令cmpxchg函数=分析
下一篇:KVM地址翻译流程及EPT页表的建立过程