2.3 VMCS


VMM 和 Guest OS共享底层的处理器资源,因此硬件需要一个物理内存区域来自动保存或恢复彼此执行的上下文。这个区域称为虚拟机控制块(VMCS),包括客户机状态区(Guest State Area),主机状态区(Host State Area)和执行控制区. VM entry 时,硬件自动从客户机状态区加载 Guest OS 的上下文。并不需要软件来保存 VMM 的上下文.当VMM 开始运行,就不会受到Guest OS的干扰,只有 VMM 将工作彻底处理完毕才可能自行切换到 Guest OS。而 VMM 的下次运行必然是处理一个新的事件,因此每次 VM entry 时, VMM 都从一个通用事件处理函数开始执行;VM exit 时,硬件自动将 Guest OS 的上下文保存在客户机状态区,从主机状态区中加载 VMM 的通用事件处理函数的地址,VMM 开始执行。而执行控制区存放的则是可以操控 VM entry 和 exit 的标志位,例如标记哪些事件可以导致 VM exit,VM entry 时准备自动给 Guest OS 注入哪种中断等等。

2.3.1 VMCS总表

字段名采用vmcs_field 中的定义

类型

字段

含义

VM-Execution

控制字段

 

PIN_BASED_VM_EXEC_CONTROL

控制pin与INTR 和 NMI是否产生VM-Exit 与使能

CPU_BASED_VM_EXEC_CONTROL

处理器的指令是否引起VM-Exit, bit31控制是否启用

SECONDARY_VM_EXEC_CONTROL

SECONDARY_VM_EXEC_CONTROL

EPT, virtual APIC 等使能位; invpcid等指令是否产生vm-exit

EXCEPTION_BITMAP

每位对应一个异常,为一时发生该异常产生vm-exit

IO_BITMAP_A

IO_BITMAP_A_HIGH

IO_BITMAP_B

IO_BITMAP_B_HIGH

每位对应一个io port addr, 为一时访问该port产生vm-exit

TSC_OFFSET

TSC_OFFSET_HIGH

Use TSC offset时, non-root下执行rdtsc, rdtscp, rdmsr时反会该寄存器的值

CR0_GUEST_HOST_MASK

CR0_READ_SHADOW

CR4_READ_SHADOW

CR4_GUEST_HOST_MASK

Mask为为一属于host, 否则属于guest

 

属于Host: Guest读该位返回shadow的值,写该位时如果与shadow值不等,产生vm-exit.

 

属于Guest时,读写不产生vm-exit

CR3_TARGET_VALUE (0-3)

CR3_TARGET_COUNT

当Guest向CR3写时,不等于0 - 3中的值产生vm-exit

APIC_ACCESS_ADDR

APIC_ACCESS_ADDR_HIGH

当virtualize apic为1时, 指向4K apic-access page

VIRTUAL_APIC_PAGE_ADDR

VIRTUAL_APIC_PAGE_ADDR_HIGH

Use tpr shadow为1时,指向4K virtual apic-access page

TPR_THRESHOLD

Use tpr shadow为1时 bit[3:0] > VPTR[7:4]时产生vm-exit

EOI_EXIT_BITMAP (0-3)

EOI_EXIT_BITMAP(0-3)_HIGH

Virtual-interrupt delivery为1时,用于控制Eoi时

是否产生vm-exit

POSTED_INTR_DESC_ADDR

指向posted-interrupt-descriptor结构的地址

POSTED_INTR_NV

Process posted interrupts为1时允许处理器收到一个通知性的外部中断为不产生vm-exit

MSR_BITMAP

为1时,访问产生vm-exit

EPT_POINTER

EPT list的物理地址

VIRTUAL_PROCESSOR_ID

Enable VPID为1时,提供vpid值

PLE_GAP

PLE_WINDOW

设置pause-loop exiting的超时

PAGE_FAULT_ERROR_CODE_MASK     

PAGE_FAULT_ERROR_CODE_MATCH

PAGE fault异常时 (PEFC & PFEC_MASK) == PFEC_MACH时产生vm-exit

Vm-ENTRY控制字段

 

 

 

 

 

VM_ENTRY_CONTROLS              

控制VM-Entry进入的模式SMM, IA-32E,等

VM_ENTRY_EXCEPTION_ERROR_CODE

VM_ENTRY_INSTRUCTION_LEN

VM_ENTRY_INTR_INFO_FIELD

控制中断与异常注入

VM_ENTRY_MSR_LOAD_COUNT

VM_ENTRY_MSR_LOAD_ADDR

VM-Entry时加载load_addr提供的msr值

VM-EXIT控

制字段

 

VM_EXIT_CONTROLS                        

VM-Exit时寄存的保存控制

VM_EXIT_MSR_STORE_COUNT

VM_EXIT_MSR_LOAD_COUNT

VM-Exit时保存msr

Guest State字段

GUEST_CR0                      

GUEST_CR3                      

GUEST_CR4

 

GUEST_DR7                                        

 

GUEST_RSP                       GUEST_RIP

GUEST_RFLAGS

 

GUEST_ES_BASE                  

GUEST_CS_BASE                  

GUEST_SS_BASE                  

GUEST_DS_BASE                  

GUEST_FS_BASE                  

GUEST_GS_BASE

GUEST_LDTR_BASE                

GUEST_TR_BASE                  

GUEST_GDTR_BASE                

GUEST_IDTR_BASE

 

GUEST_ES_LIMIT                 

GUEST_CS_LIMIT                 

GUEST_SS_LIMIT                 

GUEST_DS_LIMIT                 

GUEST_FS_LIMIT                 

GUEST_GS_LIMIT                 

GUEST_LDTR_LIMIT               

GUEST_TR_LIMIT                 

GUEST_GDTR_LIMIT               

GUEST_IDTR_LIMIT

 

GUEST_ES_AR_BYTES              

GUEST_CS_AR_BYTES               GUEST_SS_AR_BYTES              

GUEST_DS_AR_BYTES               GUEST_FS_AR_BYTES             

GUEST_GS_AR_BYTES        

GUEST_LDTR_AR_BYTES            

GUEST_TR_AR_BYTES

 

GUEST_IA32_PAT         

GUEST_IA32_PAT_HIGH    

GUEST_IA32_EFER        

GUEST_IA32_EFER_HIGH       

GUEST_IA32_PERF_GLOBAL_CTRL =

GUEST_IA32_PERF_GLOBAL_CTRL_HIGH

 

 

GUEST_SYSENTER_ESP             

GUEST_SYSENTER_EIP 

GUEST_SYSENTER_CS

 

GUEST_INTERRUPTIBILITY_INFO    

记录vcpu是否可以响应中断

GUEST_PENDING_DBG_EXCEPTION

记录与设置guest peding的 #DB异常

GUEST_PDPTR (0-3)

EPT时页目录指针

GUEST_BNDCFGS

 

GUEST_IA32_DEBUGCTL            

GUEST_IA32_DEBUGCTL_HIGH

 

VMCS_LINK_POINTER              

VMCS_LINK_POINTER_HIGH

SMM时使用

GUEST_INTR_STATUS

Virtual-interrupt delivery时,记录local apic的状态值

VMX_PREEMPTION_TIMER_VALUE

Preemption timer的值, 0时产生vm-exit

GUEST_ACTIVITY_STATE

指示虚拟处理器的状态  active, hlt, shutdown, wait-for-sipi

Host State

HOST_CR0                       

HOST_CR3                       

HOST_CR4

 

HOST_FS_BASE                   

HOST_GS_BASE                   

HOST_TR_BASE                   

HOST_GDTR_BASE             

HOST_IDTR_BASE                 

 

HOST_ES_SELECTOR               

HOST_CS_SELECTOR               

HOST_SS_SELECTOR               

HOST_DS_SELECTOR               

HOST_FS_SELECTOR               

HOST_GS_SELECTOR               

HOST_TR_SELECTOR

 

HOST_IA32_SYSENTER_ESP         

HOST_IA32_SYSENTER_EIP

HOST_IA32_SYSENTER_CS

 

HOST_IA32_PAT           =

HOST_IA32_PAT_HIGH      =

HOST_IA32_EFER          =

HOST_IA32_EFER_HIGH     =

HOST_IA32_PERF_GLOBAL_CTRL  =

HOST_IA32_PERF_GLOBAL_CTRL_HIGH

 

HOST_RSP                       

HOST_RIP

 

VM-EXIT 信息字段

VM_EXIT_REASON

导致vm-exit的原因

GUEST_PHYSICAL_ADDRESS

导致vm-exit GPA值

EXIT_QUALIFICATION             

提供进一步的vm-exit信息

GUEST_LINEAR_ADDRESS

导致vm-exit 线性地址

VM_EXIT_INTR_INFO

VM_EXIT_INTR_ERROR_CODE

外部中断信息

IDT_VECTORING_INFO_FIELD       

IDT_VECTORING_ERROR_CODE

引起vm-exit的vector信息

VM_EXIT_INSTRUCTION_LEN        

VMX_INSTRUCTION_INFO

VM_INSTRUCTION_ERROR

引起vm-exit的指令信息

 

底层访问代码如下:

static void vmcs_writel(unsigned long field, unsigned longvalue)

{

    u8 error;

 

    asm volatile(__ex(ASM_VMX_VMWRITE_RAX_RDX) "; setna %0"

              : "=q"(error) :"a"(value), "d"(field) : "cc");

    if (unlikely(error))

       vmwrite_error(field,value);

}

 

//64位访问

static void vmcs_write64(unsigned long field, u64 value)

{

    vmcs_writel(field,value);

#ifndef CONFIG_X86_64

    asm volatile("");

    vmcs_writel(field+1,value >> 32);

#endif

}

//32位访问

static void vmcs_write32(unsigned long field, u32 value)

{

    vmcs_writel(field,value);

}

2.3.2 到2.3.4将分别讲解控制字段的设置代码,信息字段将在VM-Exit与VM-Entry中分析

 

2.3.2 KVM中VM-Execution控制字段的设置

Name

Function Flow

Set Bits

Description

Note

PIN_BASED_VM_EXEC_CONTROL

setup_vmcs_config

BIT0

BIT3

BIT6

BIT7

外部中断 VM-Exit

NMI时VM-Exit

启用 VMX preemtion timer

启用post-intrs处理虚拟中断

这些bit与MSR_IA32_VMX_PINBASED_CTLS能力取And

CPU_BASED_VM_EXEC_CONTROL

setup_vmcs_config

BIT3

BIT7

BIT9

BIT10

BIT11

BIT15 BIT16

BIT25

BIT21

BIT23

BIT27

Bit28

BIT31

Use TSC offset

Hlt产生vm-exit

inpLPG产生vm-exit

mwait产生vm-exit

RDPMC产生vm-exit

读写CR3时

Use Iobitmap

USE TPR SHADOW

读写DR寄存器

启用mtf调试功能

启用msr bitmap

启用second process base vm-execution

1. 64位CR8 读写产生Vm-Exit(bit[19:18]

 

2. 这些bit与MSR_IA32_VMX_PROCBASED_CTLS 取and

SECONDARY_VM_EXEC_CONTROL

setup_vmcs_config

BIT0

BIT1

BIT3

BIT4

BIT5

BIT6

BIT7

BIT8

BIT9

BIT10

BIT12

Enable apic-access page

Enable EPT

RDTSCP产生#UD异常

Enable x2APIC MSR

Enable VPID

Wbinvd产生vm-exit

Guest可以使用非分页模式

支持virtual-apic page虚拟寄存器

支持虚拟中断delivery

Pause timeout时vm-exit

Invpcid产生vm-exit

1. 这些bit与MSR_IA32_VMX_PROCBASED_CTLS2 and

EXCEPTION_BITMAP

update_exception_bitmap

#PF

#UD

#MC

#NM

#DB

 

当Guest模式发生变化时,update_exception_bitmap会调用来更新这些bit

IO_BITMAP

Vmx_init

 

memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE);

 

clear_bit(0x80, vmx_io_bitmap_a);

memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);

 

TSC_OFFSET

kvm_arch_vcpu_load ==>kvm_x86_ops->compute_tsc_offse

 

vcpu->arch.last_guest_tsc - native_read_tsc

 

CR0_GUEST_HOST_MASK

CR0_READ_SHADOW

CR4_READ_SHADOW

CR4_GUEST_HOST_MASK

(1) vmx_cpu_reset:

vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu));

 

vmx_set_cr4(&vmx->vcpu, 0);

 

(2) kvm_arch_vcpu_ioctl_set_sregs==>kvm_x86_ops->set_cr0 cr4

 

(3)异常处理时

 

    vmx_set_cr0

    vmx_set_cr4

根据模式发生变化

CR3_TARGET_COUNT

vmx_vcpu_setup

0

 

非nested时为0

APIC_ACCESS_ADDR

 

 

vmcs_write64(APIC_ACCESS_ADDR,              page_to_phys(vmx->vcpu.kvm->arch.apic_access_page));

 

VIRTUAL_APIC_PAGE_ADDR

Vmx_vcpu_reset

 

vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,

                     __pa(vmx->vcpu.arch.apic->regs)

 

TPR_THRESHOLD

1. kvm_vcpu_ioctl_set_lapic ==》update_cr8_intercept

 

2.vmx_vcpu_reset 初始化为0

 

 

Local apic相关

EOI_EXIT_BITMAP

vcpu_enter_guest ==>vcpu_scan_ioapic==>

kvm_ioapic_scan_entry 取得

kvm_x86_ops->load_eoi_exitmap 设置

 

 

 

POSTED_INTR_NV

vmx_vcpu_setup

 

0xf2

 

 

 

 

 

 

POSTED_INTR_DESC_ADDR

__apic_accept_irq ==>vmx_deliver_posted_interrupt

 

vmx->pi_desc

 

MSR_BITMAP

变量地址初始化

vmx_set_msr_bitmap

 

vmx_init时初始化

 

msr_bitmap

初始化根据irqchip_in_kernel

 apic_x2apic_mode

定义

VIRTUAL_PROCESSOR_ID

Vmx_vcpu_reset时初始化

 

vmx->vpid 由allocate_vpid动态分配

 

PLE_GAP

PLE_WINDOW

static int ple_gap = KVM_VMX_DEFAULT_PLE_GAP;

 

static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW;

 

Vmx模块初始化定义

#define KVM_VMX_DEFAULT_PLE_GAP    128

#define KVM_VMX_DEFAULT_PLE_WINDOW 4096

 

PAGE_FAULT_ERROR_CODE_MASK     

PAGE_FAULT_ERROR_CODE_MATCH

vmx_vcpu_setup

0

 

Page  Fault固定产生vm-exit

 

Note1:表中的使能位为KVM最大支持的bits

Note2: Nested Case是指在虚拟机上再跑虚拟机;本文由于篇幅原因,只讨论真实机上直接运行虚拟机的case.

 

2.3.3 KVM中VM-Entry & VM-Exit 控制字段设置

Name

Function Flow

Set Bits

Description

Note

VM_ENTRY_CONTROLS

setup_vmcs_config

设置

vmx_vcpu_setup ==>vm_entry_controls_init

BIT1

 

BIT1

Vm-ENTRY时从 guest-state加载dr7 dbg_ctrl

Vm-ENTRY时从 guest-state加载 IA32_PAT

这些bit与MSR_IA32_VMX_ENTRY_CTLS and

VM_ENTRY_EXCEPTION_ERROR_CODE

VM_ENTRY_INSTRUCTION_LEN

VM_ENTRY_INTR_INFO_FIELD

vmx_queue_exception

 

 

动态注入

VM_ENTRY_MSR_LOAD_COUNT

VM_ENTRY_MSR_LOAD_ADDR

vmx_vcpu_reset==》setup_msrs

和模式切换时

根据vmx_msr_index 变量

 

Vmx_init==>     for (i = 0; i < NR_VMX_MSR; ++i)

        kvm_define_shared_msr(i, vmx_msr_index[i]);

VM_EXIT_CONTROLS

setup_vmcs_config

设置

vmx_vcpu_setup ==>vm_exit_controls_init

BIT15

BIT18

BIT19

VM-EXIT时处理器响应中断控制器
vm-exit时保存到guest_stateI232_PAT

Vm-exit时加载host-state IA32_PAT

 

VM_EXIT_MSR_STORE_COUNT

0

 

 

 

VM_EXIT_MSR_LOAD_COUNT

vmx_vcpu_reset==》setup_msrs

和模式切换时

 

 

 

 

VM_ENTRY_INTR_INFO_FIELD :

bit[7:0] vector

bit[10:8] event type

bit11 error code

bit31 valid

 

2.3.4 VM-Exit Info

(1) Exit Reason

bit[15:0] Exit 退出原因arch\x86\include\asm\vmx.h

#define EXIT_REASON_EXCEPTION_NMI       0

#define EXIT_REASON_EXTERNAL_INTERRUPT  1

#define EXIT_REASON_TRIPLE_FAULT        2

.......

#define EXIT_REASON_XSETBV              55

#define EXIT_REASON_APIC_WRITE          56

#define EXIT_REASON_INVPCID             58

 

同时arch\x86\kvm\vmx.c定义了每个Vm-exit推出原因的处理函数

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_MWAIT_INSTRUCTION]       =handle_mwait,

    [EXIT_REASON_MONITOR_INSTRUCTION]     = handle_monitor,

    [EXIT_REASON_INVEPT]                  = handle_invept,

}

 

bit[28] 为1表明Vm-exit时,存在pending MTF事件

bit[29]为1表明 vm-exit有root-operation环境中产生

bit[31]为1表明, VM-Entry中发生vm-exit

 

(2) EXIT_QUALIFICATION 

记录退出原因的明细信息, KVM支持的类别如下

a)  指令引发的:invplg 保存操作数线性地址, mwait 则为0或1,其它指令记录内存操作数偏移

 

b)  #DB 引发: bit[3:0]对应断点0-3,bit3 异常由访问DR造成, bit14表示单步调试

 

c)  #PF引发: 引起异常的线性地址

d)  接收SIPI引发 bit[7:0]为向量号

 

e)  接收SMI引发: bit[2:0] io operand size, bit[3] io direction; bit[4] charoperation, bit[5] rep prefix; bit[6] 1 立即数, 0 DX寄存器。 bit[31:16] io port.

 

f)  任务切换引发bit[15:0] TSS selector, bit[31:30] 0 call , 1 iret, 2 jmp, 3 task gate.

 

g)  访问控制寄存器引发

bit[3:0]访问控制寄存器; bit[5:4] 访问类型;lmswoperand 指令操作数;

bit[11:8]记录使用的通用寄存器; bit[31:16]指令的源操作数值

 

h)  mov-dr指令引发: bit[2:0] 调试寄存器,bit4 方向。 bit[11:8]记录通用寄存器

 

i)  访问 I/O 引发: bit[2:0] io operand size, bit[3] io direction; bit[4] charoperation, bit[5] rep prefix; bit[6] 1 立即数, 0 DX寄存器。 bit[31:16] io port.

 

j)  访问apic-accesspage引发 bit[11:0] apic-access page 内偏移; bit[15:12] type

 

k)  eptviolation引发

bit0read, bit1 write, bit2 execute

bit3readable, bit4 wirtable, bit5 executable

bit7:存在guest-linear address;

bit81 gpa->hpa  0 guest paging-structure

 

l)  eoi虚拟化引发, bit[7:0]中断向量号

m)  apic-write引发bit[11:0] apic-access page 内偏移

 

 

(3) 向量信息

直接向量

vm-exit interrupt information

bit[7:0]异常或中断号,bit[10:8]中断或异常类别,bit11: error code, bit12 表示blocking by nmi被解除, bi31 valid

 

vm-exit interruption error code

vm-exit interrupt information bit11 为1时有效,记录错误码

 

间接向量信息:当一个向量事件delivery间产生一个异常,那么产生一个直接向量(后面产生的异常)和一个间接向量事件(原始事件)。

idt-vector information; idt-vector error code

 

(4) 指令信息

vm-exit instruction length 分为两类

a. 指令引起vm-exit

b. 向量引起vm-exit

vm-exit instruction information, 根据指令不同而区别

你可能感兴趣的:(虚拟化)