[原] KVM 虛擬化原理探究(3)— CPU 虛擬化

KVM 虛擬化原理探究(3)— CPU 虛擬化

標籤(空格分隔): KVM架構


CPU 虛擬化簡介

上一篇文章籠統的介紹了一個虛擬機的誕生過程,從demo中也能夠看到,運行一個虛擬機不再須要像之前想象的那樣,須要用軟件來模擬硬件指令集了。虛擬機的指令集直接運行在宿主機物理CPU上,當虛擬機中的指令設計到IO操做或者一些特殊指令的時候,控制權轉讓給了宿主機(這裏實際上是轉讓給了vm monitor,下面檢查VMM),也就是一個demo進程,他在宿主機上的表現形式也就是一個用戶級進程。app

用一張圖來解釋更爲貼切。函數

vcpu-follow.png-102.9kB

VMM完成vCPU,內存的初始化後,經過ioctl調用KVM的接口,完成虛擬機的建立,並建立一個線程來運行VM,因爲VM在前期初始化的時候會設置各類寄存器來幫助KVM查找到須要加載的指令的入口(main函數)。因此線程在調用了KVM接口後,物理CPU的控制權就交給了VM。VM運行在VMX non-root模式,這是Intel-V或者AMD-V提供的一種特殊的CPU執行模式。而後當VM執行了特殊指令的時候,CPU將當前VM的上下文保存到VMCS寄存器(這個寄存器是一個指針,保存了實際的上下文地址),而後執行權切換到VMM。VMM 獲取 VM 返回緣由,並作處理。若是是IO請求,VMM 能夠直接讀取VM的內存並將IO操做模擬出來,而後再調用VMRESUME指令,VM繼續執行,此時在VM看來,IO操做的指令被CPU執行了。ui

Intel-V 技術

Intel-V 技術是Intel爲了支持虛擬化而提供的一套CPU特殊運行模式。操作系統

Intel-V虛擬化技術結構

Intel-V 在IA-32處理器上擴展了處理器等級,原來的CPU支持ring0~ring3 4個等級,可是Linux只使用了其中的兩個ring0,ring3。當CPU寄存器標示了當前CPU處於ring0級別的時候,表示此時CPU正在運行的是內核的代碼。而當CPU處於ring3級別的時候,表示此時CPU正在運行的是用戶級別的代碼。當發生系統調用或者進程切換的時候,CPU會從ring3級別轉到ring0級別。ring3級別是不容許執行硬件操做的,全部硬件操做都須要系統提供的API來完成。
好比說一個IO操做:線程

int nread = read(fd, buffer, 1024);

當執行到此段代碼的時候,而後查找到系統調用號,保存到寄存器eax,而後會將對應的參數壓棧後產生一個系統調用中斷,對應的是 int $0x80。產生了系統調用中斷後,此時CPU將切換到ring0模式,內核經過寄存器讀取到參數,並完成最後的IO後續操做,操做完成後返回ring3模式。debug

movel  $3,%eax
movel  fd,%ebx
movel  buffer,%ecx
movel  1024,%edx      
int    $0x80

Intel-V 在 ring0~ring3 的基礎上,增長了VMX模式,VMX分爲root和non-root。這裏的VMX root模式是給VMM(前面有提到VM monitor),在KVM體系中,就是qemu-kvm進程所運行的模式。VMX non-root模式就是運行的Guest,Guest也分ring0~ring3,不過他並不感知本身處於VMX non-root模式下。設計

image_1appl048b1jqh1joj5hkthj1kdr29.png-169.9kB

Intel的虛擬架構基本上分兩個部分:指針

  • 虛擬機監視器
  • 客戶機(Guest VM)

虛擬機監視器(Virtual-machine monitors - VMM)

虛擬機監視器在宿主機上表現爲一個提供虛擬機CPU,內存以及一系列硬件虛擬的實體,這個實體在KVM體系中就是一個進程,如qemu-kvm。VMM負責管理虛擬機的資源,並擁有全部虛擬機資源的控制權,包括切換虛擬機的CPU上下文等。

Guest

這個Guest在前面的Demo裏面也提到,多是一個操做系統(OS),也可能就是一個二進制程序,whatever,對於VMM來講,他就是一堆指令集,只須要知道入口(rip寄存器值)就能夠加載。
Guest運行須要虛擬CPU,當Guest代碼運行的時候,處於VMX non-root模式,此模式下,該用什麼指令仍是用什麼指令,該用寄存器該用cache仍是用cache,可是在執行到特殊指令的時候(好比Demo中的out指令),把CPU控制權交給VMM,由VMM來處理特殊指令,完成硬件操做。

VMM 與 Guest 的切換

image_1applkej22o6chnj5q1u6ffpq2m.png-18.5kB

Guest與VMM之間的切換分兩個部分:VM entry 和 VM exit。有幾種狀況會致使VM exit,好比說Guest執行了硬件訪問操做,或者Guest調用了VMCALL指令或者調用了退出指令或者產生了一個page fault,或者訪問了特殊設備的寄存器等。當Guest處於VMX模式的時候,沒有提供獲取是否處於此模式下的指令或者寄存器,也就是說,Guest不能判斷當前CPU是否處於VMX模式。當產生VM exit的時候,CPU會將exit reason保存到MSRs(VMX模式的特殊寄存器組),對應到KVM就是vCPU->kvm_run->exit_reason。VMM根據exit_reason作相應的處理。

VMM 的生命週期

如上圖所示,VMM 開始於VMXON 指令,結束與VMXOFF指令。
第一次啓動Guest,經過VMLAUNCH指令加載Guest,這時候一切都是新的,好比提及始的rip寄存器等。後續Guest exit後再entry,是經過VMRESUME指令,此指令會將VMCS(後面會介紹到)所指向的內容加載到當前Guest的上下文,以便Guest繼續執行。

VMCS (Virtual-Machine control structure)

顧名思義,VMCS就是虛擬機控制結構,前面提到過不少次,Guest Exit的時候,會將當前Guest的上下文保存到VMCS中,Guest entry的時候把VMCS上下文恢復到VMM。VMCS是一個64位的指針,指向一個真實的內存地址,VMCS是以vCPU爲單位的,就是說當前有多少個vCPU,就有多少個VMCS指針。VMCS的操做包括VMREAD,VMWRITE,VMCLEAR。

Guest exit Reason

下面是qemu-kvm定義的exit reason。能夠看到有不少可能會致使Guest轉讓控制權。選取幾個解釋一下。

static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
    [EXIT_REASON_EXCEPTION_NMI]           = handle_exception, 
    [EXIT_REASON_EXTERNAL_INTERRUPT]      = handle_external_interrupt, 
    [EXIT_REASON_TRIPLE_FAULT]            = handle_triple_fault,
    [EXIT_REASON_NMI_WINDOW]              = handle_nmi_window,
     // 訪問了IO設備
    [EXIT_REASON_IO_INSTRUCTION]          = handle_io,
     // 訪問了CR寄存器,地址寄存器,和DR寄存器(debug register)同樣,用於調試
    [EXIT_REASON_CR_ACCESS]               = handle_cr,
    [EXIT_REASON_DR_ACCESS]               = handle_dr, 
    [EXIT_REASON_CPUID]                   = handle_cpuid,
    // 訪問了MSR寄存器
    [EXIT_REASON_MSR_READ]                = handle_rdmsr,
    [EXIT_REASON_MSR_WRITE]               = handle_wrmsr,
    [EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
    // Guest執行了HLT指令,Demo開胃菜就是這個指令
    [EXIT_REASON_HLT]                     = handle_halt,
    [EXIT_REASON_INVD]                    = handle_invd,
    [EXIT_REASON_INVLPG]                  = handle_invlpg,
    [EXIT_REASON_RDPMC]                   = handle_rdpmc,
    // 不太清楚如下VM系列的指令有什麼用,猜想是遞歸VM(虛擬機裏面運行虛擬機)
    [EXIT_REASON_VMCALL]                  = handle_vmcall, 
    [EXIT_REASON_VMCLEAR]                 = handle_vmclear,
    [EXIT_REASON_VMLAUNCH]                = handle_vmlaunch,
    [EXIT_REASON_VMPTRLD]                 = handle_vmptrld,
    [EXIT_REASON_VMPTRST]                 = handle_vmptrst,
    [EXIT_REASON_VMREAD]                  = handle_vmread,
    [EXIT_REASON_VMRESUME]                = handle_vmresume,
    [EXIT_REASON_VMWRITE]                 = handle_vmwrite,
    [EXIT_REASON_VMOFF]                   = handle_vmoff,
    [EXIT_REASON_VMON]                    = handle_vmon,
    
    [EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold,
    // 訪問了高級PCI設備
    [EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
    [EXIT_REASON_APIC_WRITE]              = handle_apic_write,
    [EXIT_REASON_EOI_INDUCED]             = handle_apic_eoi_induced,
    [EXIT_REASON_WBINVD]                  = handle_wbinvd,
    [EXIT_REASON_XSETBV]                  = handle_xsetbv,
    // 進程切換
    [EXIT_REASON_TASK_SWITCH]             = handle_task_switch,
    [EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
    // ept 是Intel的一個硬件內存虛擬化技術
    [EXIT_REASON_EPT_VIOLATION]           = handle_ept_violation,
    [EXIT_REASON_EPT_MISCONFIG]           = handle_ept_misconfig,
    // 執行了暫停指令
    [EXIT_REASON_PAUSE_INSTRUCTION]       = handle_pause,
    [EXIT_REASON_MWAIT_INSTRUCTION]       = handle_invalid_op,
    [EXIT_REASON_MONITOR_INSTRUCTION]     = handle_invalid_op,
    [EXIT_REASON_INVEPT]                  = handle_invept,
};

總結

KVM的CPU虛擬化依託於Intel-V提供的虛擬化技術,將Guest運行於VMX模式,當執行了特殊操做的時候,將控制權返回給VMM。VMM處理完特殊操做後再把結果返回給Guest。 CPU虛擬化能夠說是KVM的最關鍵的核心,弄清楚了VM Exit和VM Entry。後續的IO虛擬化,內存虛擬化都是創建在此基礎上。下一章介紹內存虛擬化。

相關文章
相關標籤/搜索