1. 程式人生 > 其它 >qemu-kvm中vcpu虛擬化到底是咋整的?

qemu-kvm中vcpu虛擬化到底是咋整的?

一句話總結

例項化一個vcpu就是在hostOS中建立了一個執行緒,執行緒裡有個while迴圈,迴圈裡不停的呼叫kvm_cpu_exec方法,kvm_cpu_exec方法呼叫通過kvm_vcpu_ioctl(cpu, KVM_RUN, 0)使得kvm切換為no-root模式。在no-root模式下處理特權指令的時候,會退回root模式,然後一步步返回到kvm_cpu_exec中根據不同原因,處理返回異常。

如此一個輪迴結束,周而復始,vcpu。

再補充說一點,記憶體中申請一塊記憶體,根模式和非根模式切換的時候,先把當前暫存器值放到這塊記憶體中,然後設定物理cpu使得進入對應模式,這塊記憶體叫vmcs。

背景

vcpu初始化的時候(qemu_init_vcpu)是啟動了一個執行緒,也就是說vcpu其實就是一個執行緒.執行緒執行方法是qemu_kvm_cpu_thread_fn

kvm_init_vcpu呼叫KVM_CREATE_VCPU建立了vcpu返回vm_fdvcpu的執行是在kvm_cpu_exec裡面的,這裡呼叫如下命令進入kvm

run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);

進入KVM後,KVM會切入Guest OS,假如Guest OS執行執行,需要訪問IO等也就是說要訪問physical device,那麼Qemu與KVM就要進行emulate。如果是KVM emulate的則由KVM emulate,然後切回Guest OS。如果是Qemu emulate的,則從KVM中進入Qemu,等Qemu中的device model執行完emulate之後,再次在Qemu中呼叫kvm_vcpu_ioctl(vcpu_fd, KVM_RUN, xxx)進入KVM執行,然後再切回Guest OS

vm-entrykvm_vcpu_ioctl(kvm_main.c)-->kvm_arch_vcpu_ioctl_run(kvm/x86.c)-->vcpu_run(kvm/x86.c)-->vcpu_enter_guest(kvm/x86.c)在qemu中kvm_vcpu_ioctl(cpu, KVM_RUN, 0)呼叫kvm後代碼層層呼叫最終核心實現的方法是vcpu_enter_guest

vcpu->requests 處理

上次VM-Exit時可能呼叫kvm_make_request設定不同的request下次準備VM-Entry時需要處理這些request.

prepare_guest_switch

 (vmx.c)
.prepare_guest_switch = vmx_save_host_state,
  1. 儲存host的fs和gs的斷選擇子(segment selector)到vmcs
  2. kvm_set_shared_msr設定host對應的msr暫存器 MSR 總體來是為了設定CPU 的工作環境和標示CPU 的工作狀態,包括溫度控制,效能監控等guest的msr在handle_wrmsr 最終是在vmx_set_msr中更新
  3. 判斷當前是否滿足vm-entry vcpu的mode不對,有requests請求,需要重新排程,有pending的訊號有異常任何情況,不進入vm_entry開中斷,開搶佔(在此之前已經關搶佔,關中斷)

4.kvm_x86_ops->run(vcpu)-->vmx_vcpu_run(vmx.c)更新vmcs中的GUEST_RSP和 GUEST_RIP重新整理vmcs中的HOST_CR4欄位(其他暫存器在 kvm_arch_vcpu_ioctl_set_regs時設定)(段暫存器在vmx_vcpu_reset時設定)下面調用匯編程式碼,儲存host相關內容,然後載入vmcs中的guest的暫存器值,跳轉至guest中程式碼

vm-exit

前半部分我們知道了如何vm-entry此時進入no-root非根模式執行guest的指令當指令訪問特權指令如訪問io訪問裝置的時候會vm-exit

1.vmx_vcpu_run後半段

vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
vmx->loaded_vmcs->launched = 1;
vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);

2.加入vm-exit是由於EXIT_REASON_MCE_DURING_VMENTRY或者EXIT_REASON_EXCEPTION_NMI導致的在vmx_complete_atomic_exit方法中需要進行特殊處理(kvm_machine_check)(kvm_before_handle_nmi和kvm_after_handle_nmi)

  1. 如果有事件模擬的virtual nmi中斷,則用vmx_recover_nmi_blocking處理
  2. 獲取與預處理導致的中斷由vmx_complete_interrupts-->__vmx_complete_interrupts處理

(至此退出vmx_vcpu_run重返vmx_vcpu_run)

kvm_x86_ops->handle_exit-->vmx_handle_exit根據不同情況處理異常

至此從kvm中返回到使用者態qemu中kvm_cpu_exec方法

根據不同退出原因,處理異常然後退出到執行緒方法qemu_kvm_cpu_thread_fn繼續執行下一次迴圈