kvm随笔系列四:AMD SVM

来源:互联网 发布:zip解压密码破解软件 编辑:程序博客网 时间:2024/05/05 13:02

在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工作原理完全相同。

0 0
原创粉丝点击