kvm隨筆系列四:AMD SVM

在qeum/kvm系列文章中分析了Intel VT的實現框架, 這裏對AMD的虛擬化技術框架做一個對比性的小結。


(1) 基本指令

首先是判斷 cpu是否支持svm:

if (CPUID 8000_0001.ECX[SVM] == 0)
return SVM_NOT_AVAIL;
if (VM_CR.SVMDIS == 0)

return SVM_ALLOWED;

實現代碼位於:

下面是虛擬化指令及其opcode:

#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
#define SVM_VMRUN  ".byte 0x0f, 0x01, 0xd8"
#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"
#define SVM_CLGI   ".byte 0x0f, 0x01, 0xdd"
#define SVM_STGI   ".byte 0x0f, 0x01, 0xdc"
#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"

與intel vt類似,AMD-V VMM 通過執行 VMRUN 指令使 CPU 進入“guest”操作模式而執行Guest Os的代碼; Guest在運行時,遇到敏感指令或事件,硬件就執行 VMEXIT 行爲,使 CPU 回到“host”模式而執行 VMM 的代碼。 VMRUN 指令運行的參數是一個物理地址指針,其指向一個Virtual Machine Control Block (VMCB) 的內存數據結構. VMRUN 命令以 VMCB 爲參數,使 CPU 進入“guest”狀態, 按 VMCB.SAVE 的內容恢復虛擬機的 CPU 寄存器狀態,並按 VMCB.SAVE 中 CS:RIP 字段指示的地址開始執行虛擬機 的代碼, 並將之前 VMM 的 CPU 狀態保存在 MSR_VM_HSAVE_PA 寄存器所指向的物理內存區域中。VMRUN 所保存的 VMM 的CPU 狀態的 CS:RIP 實際上就是 VMM 的代碼中 VMCB 的下一個指令, 當虛擬機因某種原因而導致 #VMEXIT 時,VMM 會從 VMRUN 後的一條指令開始執行。 CPU 執行 #VMEXIT 行爲時,會自動將虛擬機的狀態保存到 VMCB.SAVE 區,並從 MSR_VM_HSAVE_PA 指定的區域加載 VMM 的 CPU 狀態。


svm_vcpu_run (svm.c) ==> 

"push %%" _ASM_BP "; \n\t"             
"mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"  //從svm結構體中設置的相應寄存器的值加載到實際寄存器中
"mov %c[rcx](%[svm]), %%" _ASM_CX " \n\t"
"mov %c[rdx](%[svm]), %%" _ASM_DX " \n\t"
"mov %c[rsi](%[svm]), %%" _ASM_SI " \n\t"
"mov %c[rdi](%[svm]), %%" _ASM_DI " \n\t"
"mov %c[rbp](%[svm]), %%" _ASM_BP " \n\t"
#ifdef CONFIG_X86_64
"mov %c[r8](%[svm]),  %%r8  \n\t"
。。。。。。
#endif


/* Enter guest mode */
"push %%" _ASM_AX " \n\t"
"mov %c[vmcb](%[svm]), %%" _ASM_AX " \n\t" //設置vmrun的vmcb地址
__ex(SVM_VMLOAD) "\n\t"
__ex(SVM_VMRUN) "\n\t"
__ex(SVM_VMSAVE) "\n\t"
"pop %%" _ASM_AX " \n\t"


/* Save guest registers, load host registers */
"mov %%" _ASM_BX ", %c[rbx](%[svm]) \n\t"
"mov %%" _ASM_CX ", %c[rcx](%[svm]) \n\t"
"mov %%" _ASM_DX ", %c[rdx](%[svm]) \n\t"
"mov %%" _ASM_SI ", %c[rsi](%[svm]) \n\t"
"mov %%" _ASM_DI ", %c[rdi](%[svm]) \n\t"
"mov %%" _ASM_BP ", %c[rbp](%[svm]) \n\t"
#ifdef CONFIG_X86_64
"mov %%r8,  %c[r8](%[svm]) \n\t"
。。。。。。
#endif
"pop %%" _ASM_BP


VMLOAD 和 VMSAVE 指令是對 VMRUN 的補充,他們用來加載和恢復一些並不需要經常使用的 CPU 狀態,如 FS, GS, TR, LDTR 寄存器以及其相關的隱含的描述符寄存器的內容,VMLOAD 和 VMSAVE 可以讓 VMM 的實現對 “guest”進入和退出的過程進行優化


(2) VMCB

vmcb定義如下,分爲控制區(該區域也包含vm-exit的原因信息)與保存區:

struct __attribute__ ((__packed__)) vmcb {
struct vmcb_control_area control;
struct vmcb_save_area save;
};

vmcb_control_area_control又分爲控制信息與vm-exit info兩類

a. 控制信息

name

description

Linux default setting

Note

intercept_cr

控制CR寄存器的讀寫vm-exit控制

CR0 : RW

CR3: RW

CR4:RW

CR8:W

 

Intercept_dr

控制DR寄存器的讀寫vm-exit控制

D0 to D7 RW

 

intercept_exceptions

異常導致vm-exit

#UD #PF, #MC

 

intercept

指令或條件引起vm-exit

Intr, 受保護的io,msr, invplga,

task切換, shutdown, vmrun,vmcall,vmload, vmsave,stg,clg,skinti,wbinvd,monitor,mwait,xsetbv smi,nmi,rdpmc,cpuid,hld,invd,invplg

 

iopm_base_pa

Io permission map address

 

 

msrpm_base_pa

MSR permission map address

 

 

tlb_ctl

Guest tlb entry flush 控制

01b: Flush entire TLB

 

Int_ctl

中斷控制

V_INTR_MASKING

 

int_vector

注入的中斷向量號

用於中斷注入

 

nested_ctl

嵌套虛擬化控制

 

 

asid

Address Space Identifier

用於區分不同虛擬機的地址空間

 

lbr_ctl

分支預測虛擬化控制

svm_enable_lbrv()

 

 event_inj

 用於異常注入

 bit[63:32] ErrorCode

bit[10:8] type: 

0: External or virtual interrupt

        1: NIM

         2:Excetpion

         3:Software Interrup

bit[7:0] vector

 



b. VM-exit信息

exit_code 參看Appendix C SVM Intercept Exit Codes


小結:AMD-V與Intel-VT基本類似,但沒有intel-vt對APIC access page的實現(本文針對Linux 3.16)


(3) 內存虛擬化

Intel VMX支持EPT技術來加速內存虛擬化,同樣AMD提供了nested paing機制(NPT)

首先,在Guest OS中,當系統開啓一個進程時,OS會爲這個進程配置一個分頁表。此時,Guest Os的線性地址位址)透過gPT (Guest Page Tables)映射到Guest的物理位址(Guest Physical  Address)。其分頁表(gPT)位於Guest的物理內存中,gCR3(Guest中的CR3)相當於硬件的暫存器,負責執行Guest OS中的內存映射。接下來,VMM物理內存中的nPT(nested page tables),將GPA映射到HPA。nPT位於VMM Host中,硬件上則由nCR3(相對於Guest,nCR3可看成是Host OS中的CR3)負責執行映射任務。


由此可見Intel EPT與AMD NPT工作原理完全相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章