Intel VT学习笔记(三)—— VMCS(上)

  • 要点回顾
  • VMCS
    • 设置字段
    • 错误排查
    • Fields
      • Host-State Area
      • VM-Control Fields
  • 代码实现
  • 参考资料

要点回顾

在上一篇笔记中,我们学习了如何进入VMX模式,并申请了一块4KB的内存,用于保存VMM相关信息。

接下来,我们将学习与虚拟机开始交互前需要做的一些准备工作。

VMCS

全称:virtual-machine control data structures
描述:可参考Intel开发手册卷3第24章。

  1. 逻辑处理器在VMX操作时使用虚拟机控制数据结构(virtual-machine control data structures,VMCSs)。它们管理进入和退出VMX non-root(虚拟机入口和虚拟机出口)的过渡,以及VMX non-root中的处理器行为。这个结构由新的指令VMCLEAR、VMPTRLD、VMREAD和VMWRITE操作。
  2. VMX需要为每个虚拟机分配一个VMCS结构,将虚拟机信息保存在一个4KB对齐的内存页上(称作VMCS region),这块内存的第11:0位必须为0。
  3. 同一时刻,可以存在多个active VMCS,但最多只能存在一个current VMCS。

VMCLEAR:初始化VMCS
VMPTRLD:选中一个VMCS作为current VMCS,需要提供其物理地址作为参数,执行之后,其他VMCS切换到active状态
VMWRITE:用于设置VMCS的各个字段,可以理解为填入VMCS的基本信息。由于在不同版本系统中相同字段的位置可能不同,因此没有采用直接对内存进行读写的方式来设置字段。

设置字段

VMCS字段列表如下(不同版本,各字段的位置可能不同),也可以参考Intel开发手册卷3附录B


错误排查

描述:设置好VMCS字段后,可尝试执行VMLAUNCH指令进行启动,如果失败,可以通过错误码进行排查。

各错误码含义可参考Intel开发手册卷3第30.4小节

以错误码7为例,含义是「VM entry with invalid control field(s)」,就是说控制域字段存在问题。

Fields

描述:VMCS能够大致分为以下几个域(具体可参考Intel开发手册卷3第24.4~24.9小节)

  1. Guest-State Area
  2. Host-State Area
  3. VM-Control Fields
  4. VM-Exit Information Fields

其中,控制域又可以分为三个部分:

  1. VM-Execution Control Fields
  2. VM-Exit Control Fields
  3. VM-Entry Information Fields

Host-State Area

描述:Host-State域用于记录部分CPU的状态信息,因为CPU是在VMM与虚拟机中来回切换运行的,所以在VMCS中既要记录主机CPU的状态,也要记录虚拟机CPU的状态,这样才能保证虚拟机正常运行。

根据Intel手册,目前Host-State域需要设置的字段:

  • 控制寄存器:Cr0、Cr3、Cr4
  • 段寄存器:CS、SS、DS、ES、FS、GS、TR
  • 基址段寄存器:FS、GS、TR、GDTR、IDTR
  • MSR寄存器:IA32_SYSENTER_CS、IA32_SYSENTER_ESP、IA32_SYSENTER_EIP

VM-Control Fields

描述:用于控制虚拟机行为,例如中断方式,是否启用EPT,启用I/O端口,MSR访问限制等等。

控制域相关字段不能够随意设置,需要参考MSR寄存器。

以Pin-Based VM-Execution Control Fields为例,对应PIN_BASED_VM_EXEC_CONTROL字段,它的值参考IA32_VMX_PINBASED_CTLS MSR寄存器(偏移为481H,可参考Intel开发手册卷3附录A.3.1),前32位表示哪些比特位位可以为1,后32位表示哪些比特位必须为1(各比特位含义可参考Intel开发手册卷3第24.6小节)。

因此,在设置PIN_BASED_VM_EXEC_CONTROL字段时,必须将该字段与IA32_VMX_PINBASED_CTLS MSR的前32位进行与运算,与其后32位进行或运算,以保证关键的比特位不出错,其他相关字段同理。

static ULONG  VmxAdjustControls(ULONG Ctl, ULONG Msr)
{LARGE_INTEGER MsrValue;MsrValue.QuadPart = Asm_ReadMsr(Msr);Ctl &= MsrValue.HighPart;     /* bit == 0 in high word ==> must be zero */Ctl |= MsrValue.LowPart;      /* bit == 1 in low word  ==> must be one  */return Ctl;
}

代码实现

//vtasm.h
#ifndef VTASM_H
#define VTASM_Htypedef union
{struct{unsigned SSE3 : 1;unsigned PCLMULQDQ : 1;unsigned DTES64 : 1;unsigned MONITOR : 1;unsigned DS_CPL : 1;unsigned VMX : 1;unsigned SMX : 1;unsigned EIST : 1;unsigned TM2 : 1;unsigned SSSE3 : 1;unsigned Reserved : 22;};}_CPUID_ECX;typedef struct _IA32_FEATURE_CONTROL_MSR
{unsigned Lock : 1;     // Bit 0 is the lock bit - cannot be modified once lock is setunsigned Reserved1 : 1;       // Undefinedunsigned EnableVmxon : 1;       // Bit 2. If this bit is clear, VMXON causes a general protection exceptionunsigned Reserved2 : 29; // Undefinedunsigned Reserved3 : 32;    // Undefined} IA32_FEATURE_CONTROL_MSR;typedef struct _VMX_BASIC_MSR
{unsigned RevId : 32;unsigned szVmxOnRegion : 12;unsigned ClearBit : 1;unsigned Reserved : 3;unsigned PhysicalWidth : 1;unsigned DualMonitor : 1;unsigned MemoryType : 4;unsigned VmExitInformation : 1;unsigned Reserved2 : 9;
} VMX_BASIC_MSR, * PVMX_BASIC_MSR;typedef union
{struct{unsigned PE : 1;unsigned MP : 1;unsigned EM : 1;unsigned TS : 1;unsigned ET : 1;unsigned NE : 1;unsigned Reserved_1 : 10;unsigned WP : 1;unsigned Reserved_2 : 1;unsigned AM : 1;unsigned Reserved_3 : 10;unsigned NW : 1;unsigned CD : 1;unsigned PG : 1;//unsigned Reserved_64:32;};}_CR0;typedef union
{struct {unsigned VME : 1;unsigned PVI : 1;unsigned TSD : 1;unsigned DE : 1;unsigned PSE : 1;unsigned PAE : 1;unsigned MCE : 1;unsigned PGE : 1;unsigned PCE : 1;unsigned OSFXSR : 1;unsigned PSXMMEXCPT : 1;unsigned UNKONOWN_1 : 1;       //These are zerounsigned UNKONOWN_2 : 1;        //These are zerounsigned VMXE : 1;          //It's zero in normalunsigned Reserved : 18;       //These are zero//unsigned Reserved_64:32;};
}_CR4;typedef union
{struct{unsigned CF : 1;unsigned Unknown_1 : 1; //Always 1unsigned PF : 1;unsigned Unknown_2 : 1;   //Always 0unsigned AF : 1;unsigned Unknown_3 : 1;   //Always 0unsigned ZF : 1;unsigned SF : 1;unsigned TF : 1;unsigned IF : 1;unsigned DF : 1;unsigned OF : 1;unsigned TOPL : 2;unsigned NT : 1;unsigned Unknown_4 : 1;unsigned RF : 1;unsigned VM : 1;unsigned AC : 1;unsigned VIF : 1;unsigned VIP : 1;unsigned ID : 1;unsigned Reserved : 10;    //Always 0//unsigned Reserved_64:32;    //Always 0};
}_EFLAGS;void Asm_CPUID(ULONG uFn, PULONG uRet_EAX, PULONG uRet_EBX, PULONG uRet_ECX, PULONG uRet_EDX);ULONG64 Asm_ReadMsr(ULONG uIndex);ULONG Asm_GetEflags();
ULONG Asm_GetCs();
ULONG Asm_GetDs();
ULONG Asm_GetEs();
ULONG Asm_GetFs();
ULONG Asm_GetGs();
ULONG Asm_GetSs();
ULONG Asm_GetTr();ULONG Asm_GetGdtBase();
ULONG Asm_GetIdtBase();ULONG Asm_GetCr0();
ULONG Asm_GetCr3();
ULONG Asm_GetCr4();void Asm_SetCr4(ULONG uNewCr4);void Vmx_VmxOn(ULONG LowPart, ULONG HighPart);
void Vmx_VmxOff();void Vmx_VmClear(ULONG LowPart, ULONG HighPart);
void Vmx_VmPtrld(ULONG LowPart, ULONG HighPart);
ULONG Vmx_VmRead(ULONG uField);
void Vmx_VmWrite(ULONG uField, ULONG uValue);
void Vmx_VmLaunch();#endif
//vtasm.asm
.686p
.model flat, stdcall
option casemap:none.data.codeAsm_CPUID  Proc    uses ebx esi edi fn:dword, ret_eax:dword, ret_ebx:dword, ret_ecx:dword, ret_edx:dwordmov    eax, fncpuidmov esi, ret_eaxmov dword ptr [esi], eaxmov esi, ret_ebxmov dword ptr [esi], ebxmov esi, ret_ecxmov dword ptr [esi], ecxmov esi, ret_edxmov dword ptr [esi], edxret
Asm_CPUID   EndpAsm_ReadMsr     Proc    Index:dwordmov  ecx,Indexrdmsrret
Asm_ReadMsr     EndpAsm_GetCr0      Procmov     eax, cr0ret
Asm_GetCr0      EndpAsm_GetCr3      Procmov     eax, cr3ret
Asm_GetCr3      EndpAsm_GetCr4      Procmov     eax, cr4ret
Asm_GetCr4      EndpAsm_SetCr4      Proc    NewCr4:dwordmov     eax,NewCr4mov   cr4, eaxret
Asm_SetCr4      EndpVmx_VmxOn Proc LowPart:dword,HighPart:dwordpush HighPartpush LowPartVmxon qword ptr [esp]add esp,8ret
Vmx_VmxOn EndpVmx_VmxOff ProcVmxoffret
Vmx_VmxOff EndpAsm_GetEflags PROCpushfdpop      eaxret
Asm_GetEflags ENDPVmx_VmClear Proc LowPart:dword,HighPart:dwordpush HighPartpush LowPartvmclear qword ptr [esp]add esp,8ret
Vmx_VmClear endpVmx_VmPtrld Proc LowPart:dword,HighPart:dwordpush HighPartpush LowPartvmptrld qword ptr [esp]add esp,8ret
Vmx_VmPtrld endpVmx_VmRead Proc uses ecx Field:dwordmov eax,Fieldvmread ecx,eaxmov eax,ecxret
Vmx_VmRead endpVmx_VmWrite Proc uses ecx Field:dword,Value:dwordmov eax,Fieldmov ecx,Valuevmwrite eax,ecxret
Vmx_VmWrite endpAsm_GetCs PROCmov       eax, csret
Asm_GetCs ENDPAsm_GetDs PROCmov     eax, dsret
Asm_GetDs ENDPAsm_GetEs PROCmov     eax, esret
Asm_GetEs ENDPAsm_GetSs PROCmov     eax, ssret
Asm_GetSs ENDPAsm_GetFs PROCmov     eax, fsret
Asm_GetFs ENDPAsm_GetGs PROCmov     eax, gsret
Asm_GetGs ENDPAsm_GetTr PROCstr eaxret
Asm_GetTr ENDPAsm_GetGdtBase PROCLOCAL  gdtr[10]:BYTEsgdt   gdtrmov     eax, dword PTR gdtr[2]ret
Asm_GetGdtBase ENDPAsm_GetIdtBase PROCLOCAL idtr[10]:BYTEsidt   idtrmov     eax, dword PTR idtr[2]ret
Asm_GetIdtBase ENDPVmx_VmLaunch Procvmlaunchret
Vmx_VmLaunch endpEND
//vtsystem.h
#ifndef VTSYSTEM_H
#define VTSYSTEM_H
#include <ntddk.h>/*MSR definition*/
#define MSR_IA32_FEATURE_CONTROL        0x03a
#define MSR_IA32_VMX_BASIC              0x480
#define MSR_IA32_VMX_PINBASED_CTLS      0x481
#define MSR_IA32_VMX_PROCBASED_CTLS     0x482
#define MSR_IA32_VMX_EXIT_CTLS          0x483
#define MSR_IA32_VMX_ENTRY_CTLS         0x484#define MSR_IA32_SYSENTER_CS            0x174
#define MSR_IA32_SYSENTER_ESP           0x175
#define MSR_IA32_SYSENTER_EIP           0x176typedef struct _VMX_CPU
{PVOID               pVMXONRegion;PHYSICAL_ADDRESS    pVMXONRegion_PA;PVOID               pVMCSRegion;PHYSICAL_ADDRESS    pVMCSRegion_PA;PVOID               pStack;BOOLEAN             bVTStartSuccess;
}VMX_CPU, * PVMX_CPU;/* VMCS Encordings */
enum
{VIRTUAL_PROCESSOR_ID = 0x00000000,POSTED_INTR_NV = 0x00000002,GUEST_ES_SELECTOR = 0x00000800,GUEST_CS_SELECTOR = 0x00000802,GUEST_SS_SELECTOR = 0x00000804,GUEST_DS_SELECTOR = 0x00000806,GUEST_FS_SELECTOR = 0x00000808,GUEST_GS_SELECTOR = 0x0000080a,GUEST_LDTR_SELECTOR = 0x0000080c,GUEST_TR_SELECTOR = 0x0000080e,GUEST_INTR_STATUS = 0x00000810,HOST_ES_SELECTOR = 0x00000c00,HOST_CS_SELECTOR = 0x00000c02,HOST_SS_SELECTOR = 0x00000c04,HOST_DS_SELECTOR = 0x00000c06,HOST_FS_SELECTOR = 0x00000c08,HOST_GS_SELECTOR = 0x00000c0a,HOST_TR_SELECTOR = 0x00000c0c,IO_BITMAP_A = 0x00002000,IO_BITMAP_A_HIGH = 0x00002001,IO_BITMAP_B = 0x00002002,IO_BITMAP_B_HIGH = 0x00002003,MSR_BITMAP = 0x00002004,MSR_BITMAP_HIGH = 0x00002005,VM_EXIT_MSR_STORE_ADDR = 0x00002006,VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,VM_EXIT_MSR_LOAD_ADDR = 0x00002008,VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,TSC_OFFSET = 0x00002010,TSC_OFFSET_HIGH = 0x00002011,VIRTUAL_APIC_PAGE_ADDR = 0x00002012,VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,APIC_ACCESS_ADDR = 0x00002014,APIC_ACCESS_ADDR_HIGH = 0x00002015,POSTED_INTR_DESC_ADDR = 0x00002016,POSTED_INTR_DESC_ADDR_HIGH = 0x00002017,EPT_POINTER = 0x0000201a,EPT_POINTER_HIGH = 0x0000201b,EOI_EXIT_BITMAP0 = 0x0000201c,EOI_EXIT_BITMAP0_HIGH = 0x0000201d,EOI_EXIT_BITMAP1 = 0x0000201e,EOI_EXIT_BITMAP1_HIGH = 0x0000201f,EOI_EXIT_BITMAP2 = 0x00002020,EOI_EXIT_BITMAP2_HIGH = 0x00002021,EOI_EXIT_BITMAP3 = 0x00002022,EOI_EXIT_BITMAP3_HIGH = 0x00002023,VMREAD_BITMAP = 0x00002026,VMWRITE_BITMAP = 0x00002028,XSS_EXIT_BITMAP = 0x0000202C,XSS_EXIT_BITMAP_HIGH = 0x0000202D,GUEST_PHYSICAL_ADDRESS = 0x00002400,GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401,VMCS_LINK_POINTER = 0x00002800,VMCS_LINK_POINTER_HIGH = 0x00002801,GUEST_IA32_DEBUGCTL = 0x00002802,GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,GUEST_IA32_PAT = 0x00002804,GUEST_IA32_PAT_HIGH = 0x00002805,GUEST_IA32_EFER = 0x00002806,GUEST_IA32_EFER_HIGH = 0x00002807,GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808,GUEST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002809,GUEST_PDPTR0 = 0x0000280a,GUEST_PDPTR0_HIGH = 0x0000280b,GUEST_PDPTR1 = 0x0000280c,GUEST_PDPTR1_HIGH = 0x0000280d,GUEST_PDPTR2 = 0x0000280e,GUEST_PDPTR2_HIGH = 0x0000280f,GUEST_PDPTR3 = 0x00002810,GUEST_PDPTR3_HIGH = 0x00002811,GUEST_BNDCFGS = 0x00002812,GUEST_BNDCFGS_HIGH = 0x00002813,HOST_IA32_PAT = 0x00002c00,HOST_IA32_PAT_HIGH = 0x00002c01,HOST_IA32_EFER = 0x00002c02,HOST_IA32_EFER_HIGH = 0x00002c03,HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04,HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05,PIN_BASED_VM_EXEC_CONTROL = 0x00004000,CPU_BASED_VM_EXEC_CONTROL = 0x00004002,EXCEPTION_BITMAP = 0x00004004,PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,CR3_TARGET_COUNT = 0x0000400a,VM_EXIT_CONTROLS = 0x0000400c,VM_EXIT_MSR_STORE_COUNT = 0x0000400e,VM_EXIT_MSR_LOAD_COUNT = 0x00004010,VM_ENTRY_CONTROLS = 0x00004012,VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,VM_ENTRY_INTR_INFO_FIELD = 0x00004016,VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,TPR_THRESHOLD = 0x0000401c,SECONDARY_VM_EXEC_CONTROL = 0x0000401e,PLE_GAP = 0x00004020,PLE_WINDOW = 0x00004022,VM_INSTRUCTION_ERROR = 0x00004400,VM_EXIT_REASON = 0x00004402,VM_EXIT_INTR_INFO = 0x00004404,VM_EXIT_INTR_ERROR_CODE = 0x00004406,IDT_VECTORING_INFO_FIELD = 0x00004408,IDT_VECTORING_ERROR_CODE = 0x0000440a,VM_EXIT_INSTRUCTION_LEN = 0x0000440c,VMX_INSTRUCTION_INFO = 0x0000440e,GUEST_ES_LIMIT = 0x00004800,GUEST_CS_LIMIT = 0x00004802,GUEST_SS_LIMIT = 0x00004804,GUEST_DS_LIMIT = 0x00004806,GUEST_FS_LIMIT = 0x00004808,GUEST_GS_LIMIT = 0x0000480a,GUEST_LDTR_LIMIT = 0x0000480c,GUEST_TR_LIMIT = 0x0000480e,GUEST_GDTR_LIMIT = 0x00004810,GUEST_IDTR_LIMIT = 0x00004812,GUEST_ES_AR_BYTES = 0x00004814,GUEST_CS_AR_BYTES = 0x00004816,GUEST_SS_AR_BYTES = 0x00004818,GUEST_DS_AR_BYTES = 0x0000481a,GUEST_FS_AR_BYTES = 0x0000481c,GUEST_GS_AR_BYTES = 0x0000481e,GUEST_LDTR_AR_BYTES = 0x00004820,GUEST_TR_AR_BYTES = 0x00004822,GUEST_INTERRUPTIBILITY_INFO = 0x00004824,GUEST_ACTIVITY_STATE = 0X00004826,GUEST_SYSENTER_CS = 0x0000482A,VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,HOST_IA32_SYSENTER_CS = 0x00004c00,CR0_GUEST_HOST_MASK = 0x00006000,CR4_GUEST_HOST_MASK = 0x00006002,CR0_READ_SHADOW = 0x00006004,CR4_READ_SHADOW = 0x00006006,CR3_TARGET_VALUE0 = 0x00006008,CR3_TARGET_VALUE1 = 0x0000600a,CR3_TARGET_VALUE2 = 0x0000600c,CR3_TARGET_VALUE3 = 0x0000600e,EXIT_QUALIFICATION = 0x00006400,GUEST_LINEAR_ADDRESS = 0x0000640a,GUEST_CR0 = 0x00006800,GUEST_CR3 = 0x00006802,GUEST_CR4 = 0x00006804,GUEST_ES_BASE = 0x00006806,GUEST_CS_BASE = 0x00006808,GUEST_SS_BASE = 0x0000680a,GUEST_DS_BASE = 0x0000680c,GUEST_FS_BASE = 0x0000680e,GUEST_GS_BASE = 0x00006810,GUEST_LDTR_BASE = 0x00006812,GUEST_TR_BASE = 0x00006814,GUEST_GDTR_BASE = 0x00006816,GUEST_IDTR_BASE = 0x00006818,GUEST_DR7 = 0x0000681a,GUEST_RSP = 0x0000681c,GUEST_RIP = 0x0000681e,GUEST_RFLAGS = 0x00006820,GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,GUEST_SYSENTER_ESP = 0x00006824,GUEST_SYSENTER_EIP = 0x00006826,HOST_CR0 = 0x00006c00,HOST_CR3 = 0x00006c02,HOST_CR4 = 0x00006c04,HOST_FS_BASE = 0x00006c06,HOST_GS_BASE = 0x00006c08,HOST_TR_BASE = 0x00006c0a,HOST_GDTR_BASE = 0x00006c0c,HOST_IDTR_BASE = 0x00006c0e,HOST_IA32_SYSENTER_ESP = 0x00006c10,HOST_IA32_SYSENTER_EIP = 0x00006c12,HOST_RSP = 0x00006c14,HOST_RIP = 0x00006c16,
};extern VMX_CPU g_VMXCPU;//检查当前处理器是否支持VT
BOOLEAN IsVTEnabled();
//开启VT
NTSTATUS StartVirtualTechnology();
//关闭VT
NTSTATUS StopVirtualTechnology();#define Log(message,value) {{KdPrint(("[MinVT] %-40s [%p]\n",message,value));}}#endif
//vtsystem.c
#include "vtsystem.h"
#include "vtasm.h"
#include "exithandler.h"VMX_CPU g_VMXCPU;BOOLEAN IsVTEnabled()
{ULONG       uRet_EAX, uRet_ECX, uRet_EDX, uRet_EBX;_CPUID_ECX  uCPUID;_CR0        uCr0;_CR4    uCr4;IA32_FEATURE_CONTROL_MSR msr;//1. CPUIDAsm_CPUID(1, &uRet_EAX, &uRet_EBX, &uRet_ECX, &uRet_EDX);*((PULONG)&uCPUID) = uRet_ECX;if (uCPUID.VMX != 1){Log("ERROR: 这个CPU不支持VT!", 0);return FALSE;}// 2. MSR*((PULONG)&msr) = (ULONG)Asm_ReadMsr(MSR_IA32_FEATURE_CONTROL);if (msr.Lock != 1){Log("ERROR:VT指令未被锁定!", 0);return FALSE;}// 3. CR0 CR4*((PULONG)&uCr0) = Asm_GetCr0();*((PULONG)&uCr4) = Asm_GetCr4();if (uCr0.PE != 1 || uCr0.PG != 1 || uCr0.NE != 1){Log("ERROR:这个CPU没有开启VT!", 0);return FALSE;}if (uCr4.VMXE == 1){Log("ERROR:这个CPU已经开启了VT!", 0);Log("可能是别的驱动已经占用了VT,你必须关闭它后才能开启。", 0);return FALSE;}Log("SUCCESS:这个CPU支持VT!", 0);return TRUE;
}static ULONG  VmxAdjustControls(ULONG Ctl, ULONG Msr)
{LARGE_INTEGER MsrValue;MsrValue.QuadPart = Asm_ReadMsr(Msr);Ctl &= MsrValue.HighPart;     /* bit == 0 in high word ==> must be zero */Ctl |= MsrValue.LowPart;      /* bit == 1 in low word  ==> must be one  */return Ctl;
}void SetupVMCS()
{ULONG GdtBase, IdtBase;GdtBase = Asm_GetGdtBase();IdtBase = Asm_GetIdtBase();//// 1.Guest State Area////// 2.Host State Area//Vmx_VmWrite(HOST_CR0, Asm_GetCr0());Vmx_VmWrite(HOST_CR3, Asm_GetCr3());Vmx_VmWrite(HOST_CR4, Asm_GetCr4());Vmx_VmWrite(HOST_ES_SELECTOR, Asm_GetEs() & 0xFFF8);Vmx_VmWrite(HOST_CS_SELECTOR, Asm_GetCs() & 0xFFF8);Vmx_VmWrite(HOST_DS_SELECTOR, Asm_GetDs() & 0xFFF8);Vmx_VmWrite(HOST_FS_SELECTOR, Asm_GetFs() & 0xFFF8);Vmx_VmWrite(HOST_GS_SELECTOR, Asm_GetGs() & 0xFFF8);Vmx_VmWrite(HOST_SS_SELECTOR, Asm_GetSs() & 0xFFF8);Vmx_VmWrite(HOST_TR_SELECTOR, Asm_GetTr() & 0xFFF8);// Get Tr.BaseULONGLONG TSS_Descriptor = *(PULONGLONG)(GdtBase + (Asm_GetTr() & 0xFFF8));ULONG Tr_Base = 0;Tr_Base |= (TSS_Descriptor & 0xff00000000000000) >> 32;Tr_Base |= (TSS_Descriptor & 0x000000ff00000000) >> 16;Tr_Base |= (TSS_Descriptor & 0x00000000ffff0000) >> 16;//DbgPrint("TSS Descriptor = %I64x \r\n", TSS_Descriptor);//DbgPrint("Tr.Base = %x \r\n", Tr_Base);Vmx_VmWrite(HOST_TR_BASE, Tr_Base);Vmx_VmWrite(HOST_GDTR_BASE, GdtBase);Vmx_VmWrite(HOST_IDTR_BASE, IdtBase);Vmx_VmWrite(HOST_IA32_SYSENTER_CS, Asm_ReadMsr(MSR_IA32_SYSENTER_CS) & 0xFFFFFFFF);Vmx_VmWrite(HOST_IA32_SYSENTER_ESP, Asm_ReadMsr(MSR_IA32_SYSENTER_ESP) & 0xFFFFFFFF);Vmx_VmWrite(HOST_IA32_SYSENTER_EIP, Asm_ReadMsr(MSR_IA32_SYSENTER_EIP) & 0xFFFFFFFF); // KiFastCallEntryVmx_VmWrite(HOST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x1000);     //Host 临时栈Vmx_VmWrite(HOST_RIP, (ULONG)VMMEntryPoint);                  //这里定义我们的VMM处理程序入口//// 3.虚拟机运行控制域//Vmx_VmWrite(PIN_BASED_VM_EXEC_CONTROL, VmxAdjustControls(0, MSR_IA32_VMX_PINBASED_CTLS));Vmx_VmWrite(CPU_BASED_VM_EXEC_CONTROL, VmxAdjustControls(0, MSR_IA32_VMX_PROCBASED_CTLS));//// 4.VMEntry运行控制域//Vmx_VmWrite(VM_ENTRY_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_ENTRY_CTLS));//// 5.VMExit运行控制域//Vmx_VmWrite(VM_EXIT_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_EXIT_CTLS));
}NTSTATUS StartVirtualTechnology()
{PVOID pVMXONRegion;PVOID pVMCSRegion;PVOID pStack;VMX_BASIC_MSR Msr;ULONG uRevId;_CR4 uCr4;_EFLAGS uEflags;if (!IsVTEnabled())return STATUS_NOT_SUPPORTED;//VMXE*((PULONG)&uCr4) = Asm_GetCr4();uCr4.VMXE = 1;Asm_SetCr4(*((PULONG)&uCr4));//VMX version*((PULONG)&Msr) = (ULONG)Asm_ReadMsr(MSR_IA32_VMX_BASIC);uRevId = Msr.RevId;//VMXON regionpVMXONRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmon'); //4KBif (!pVMXONRegion){Log("ERROR:申请VMXON内存区域失败!", 0);return STATUS_MEMORY_NOT_ALLOCATED;}RtlZeroMemory(pVMXONRegion, 0x1000);g_VMXCPU.pVMXONRegion = pVMXONRegion;g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(pVMXONRegion);*((PULONG)g_VMXCPU.pVMXONRegion) = uRevId;//VMXONVmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart, g_VMXCPU.pVMXONRegion_PA.HighPart);// if CF = 0*((PULONG)&uEflags) = Asm_GetEflags();if (uEflags.CF != 0){Log("ERROR:VMXON指令调用失败!", 0);return STATUS_UNSUCCESSFUL;}Log("SUCCESS:VMXON指令调用成功!", 0);//VMCSpVMCSRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmon'); //4KBif (!pVMCSRegion){Log("ERROR:申请VMCS内存区域失败!", 0);return STATUS_MEMORY_NOT_ALLOCATED;}RtlZeroMemory(pVMCSRegion, 0x1000);*((PULONG)pVMCSRegion) = uRevId;g_VMXCPU.pVMCSRegion = pVMCSRegion;g_VMXCPU.pVMCSRegion_PA = MmGetPhysicalAddress(pVMCSRegion);Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart);Vmx_VmPtrld(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart);//StackpStack = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'stck'); //4KB就够用了if (!pStack){Log("ERROR:申请Stack内存区域失败!", 0);return STATUS_MEMORY_NOT_ALLOCATED;}RtlZeroMemory(pStack, 0x1000);g_VMXCPU.pStack = pStack;//SetupSetupVMCS();    //设置VMCS字段//LaunchVmx_VmLaunch();//===================================================//正常情况下,VMLAUNCH执行后,CPU会进入虚拟机中//如果走到这里,说明执行失败//===================================================Log("ERROR:VmLaunch指令调用失败!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", Vmx_VmRead(VM_INSTRUCTION_ERROR))return STATUS_SUCCESS;
}NTSTATUS StopVirtualTechnology()
{_CR4 uCr4;Vmx_VmxOff();*((PULONG)&uCr4) = Asm_GetCr4();uCr4.VMXE = 0;Asm_SetCr4(*((PULONG)&uCr4));ExFreePool(g_VMXCPU.pVMXONRegion);ExFreePool(g_VMXCPU.pVMCSRegion);ExFreePool(g_VMXCPU.pStack);Log("SUCCESS:VMXOFF指令调用成功!", 0);return STATUS_SUCCESS;
}
//exithandler.h
#ifndef EXITHANDLER_H
#define EXITHANDLER_Hvoid VMMEntryPoint(void);#endif
//exithandler.c
#include "exithandler.h"
#include "vtsystem.h"
#include "vtasm.h"void __declspec(naked) VMMEntryPoint(void)
{__asm{//需要设置fs和gs,否则无法正常运行mov ax, fsmov fs, axmov ax, gsmov gs, ax}Log("VM Exit", 0);__asm int 3;
}
//driver.c
#include <ntddk.h>
#include "vtasm.h"
#include "vtsystem.h"VOID DriverUnload(PDRIVER_OBJECT pDriver)
{StopVirtualTechnology();DbgPrint("Driver unload. \r\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{DbgPrint("Driver load. \r\n");StartVirtualTechnology();pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

运行结果:

可以看到,现在VMLAUNCH已经执行成功,但是系统直接走到了退出部分,这是由于目前并未给到有关Guest的任何信息,因此刚进入Guest就立马退出了。

关于Guest信息如何填写将留到下一篇学习。

参考资料

  • VT虚拟化架构编写视频教程①~⑥课
  • 周壑《VT技术入门》系列视频教程
  • github项目:VT_Learn
  • github项目: HyperPlatform
  • Intel开发手册 卷3:Chapter 23 ~ Chapter 33
  • x86内部函数列表

Intel VT学习笔记(三)—— VMCS(上)相关推荐

  1. Intel VT学习笔记(四)—— VMCS(下)

    Intel VT学习笔记(四)-- VMCS(下) 要点回顾 VM-Exit Information Guest state fields 代码实现 参考资料 要点回顾 在上一篇中,我们了解了如何设置 ...

  2. Intel VT学习笔记(七)—— EPT物理地址转换

    Intel VT学习笔记(七)-- EPT物理地址转换 要点回顾 EPT 支持检测 9-9-9-9-12分页 实验:EPT物理地址转换 参考资料 要点回顾 在上一篇中,已经初步实现了最小VT框架,但实 ...

  3. Intel VT学习笔记(二)—— VMXEVMXON

    Intel VT学习笔记(二)-- VMXE&VMXON VT生命周期 VMXE VMXON 准备工作 VMXON region 代码实现 参考资料 VT生命周期 描述: 软件通过执行VMXO ...

  4. Intel VT学习笔记(六)—— VM-Exit Handler

    Intel VT学习笔记(六)-- VM-Exit Handler Reutrn To DriverEntry VM-Exit Handler External interrupt I/O instr ...

  5. Intel VT学习笔记(五)—— 调试技巧

    Intel VT学习笔记(五)-- 调试技巧 要点回顾 INT 3失效 调试技巧 参考资料 要点回顾 在上一篇中,我们主要学习了如何填写Guest state fields的各项字段,以及如何对错误码 ...

  6. Intel VT学习笔记(九)—— EPT应用示例

    Intel VT学习笔记(九)-- EPT应用示例 内存保护 EPT violation 代码实现 参考资料 内存保护 描述:尝试使用EPT将一块特定的物理内存保护起来. 先来选择一块物理地址,那么这 ...

  7. J2EE学习笔记三:EJB基础概念和知识 收藏

    J2EE学习笔记三:EJB基础概念和知识 收藏 EJB正是J2EE的旗舰技术,因此俺直接跳到这一章来了,前面的几章都是讲Servlet和JSP以及JDBC的,俺都懂一些.那么EJB和通常我们所说的Ja ...

  8. Ethernet/IP 学习笔记三

    Ethernet/IP 学习笔记三 原文为硕士论文: 工业以太网Ethernet/IP扫描器的研发 知网网址: http://kns.cnki.net/KCMS/detail/detail.aspx? ...

  9. 吴恩达《机器学习》学习笔记三——多变量线性回归

    吴恩达<机器学习>学习笔记三--多变量线性回归 一. 多元线性回归问题介绍 1.一些定义 2.假设函数 二. 多元梯度下降法 1. 梯度下降法实用技巧:特征缩放 2. 梯度下降法的学习率 ...

最新文章

  1. 所有表单对象_Laravel 表单方法伪造与 CSRF 攻击防护
  2. Focal Loss升级:让Focal Loss动态化,类别极端不平衡也可以轻松解决
  3. 我眼中的Linux设备树(一 概述)
  4. 【Tomcat】Unrecognized Windows Sockets error: 10106: Socket creation failed
  5. DL之DNN:基于神经网络(从1层~50层)DNN算法实现对非线性数据集点进行绘制决策边界
  6. hprofile教程
  7. 如何使用代码区分service contract和service contract quotation
  8. 5分钟部署一个Hello World Servlet到CloudFoundry
  9. 博世豪掷10亿欧元德国建半导体工厂,要掌握自动驾驶芯片化核心竞争力?
  10. 获取本地沙盒文件的MIMEType
  11. 关于session.auto_start报警的问题
  12. 020:闭区间上连续函数性质之零点定理、介值定理
  13. Ubuntu 18.04 安装 deepin 微信
  14. php无极分类的效果,php 无极分类(递归)的简单示例
  15. 用python来编写TSP问题
  16. 用XMind做读书笔记的方法
  17. Anti-pattern
  18. threejs指南针【控制中心计算角度】
  19. Stata数据处理:import-fred-命令导入联邦储备经济数据库-FRED
  20. 中国电信天翼开放平台应用内计费SDK助力IP产业升级

热门文章

  1. 互联网晚报 | 7月9日 星期六 |马斯克终止收购推特;​B 站回应 2 亿余条用户账号疑泄露传闻;上海逐步开放电影院和演出场所...
  2. 网管软件禁止网购木马偷梁换柱
  3. [fyne] build constraints exclude all Go files in
  4. 计网实验七:应用层协议服务配置(DNS,HTTP,FTP)
  5. Ubuntu 阿里源更新 amp;amp; nvidia驱动安装 amp;amp; cuda 安装
  6. JNA二次开发华视身份证阅读器
  7. 从零开始安卓端相机功能开发(二)让我们来开发一个相机
  8. 用格布拉斯准则剔除异常值,求不确定度
  9. Unity学习之Human fall flat创意工坊地图制作
  10. 项目 调度 服务器,(2)项目构建(Reactor部分)【Lars-基于C++负载均衡远程服务器调度系统教程】...