From fb720ed1064ee162738377ab6e56342aa177c1c9 Mon Sep 17 00:00:00 2001 From: Thomas Oltmann Date: Tue, 11 Mar 2025 01:40:28 +0100 Subject: [PATCH] Setting up guest state --- include/x86/cr.h | 59 +++++++++++++++---------- include/x86/msr.h | 16 ++++--- include/x86/vmx.h | 4 +- src/vintel.c | 110 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 155 insertions(+), 34 deletions(-) diff --git a/include/x86/cr.h b/include/x86/cr.h index 83b3bf2..e2649e4 100644 --- a/include/x86/cr.h +++ b/include/x86/cr.h @@ -5,34 +5,47 @@ #define CR4_VMXE (1 << 13) -static inline uint64_t -readcr0(void) -{ - uint64_t v; - __asm__ ("mov %%cr0, %0\n\t" : "=a"(v)); - return v; -} +#define DECLARE_REGISTER_ACCESSORS(regname)\ + static inline uint64_t read##regname(void) {\ + uint64_t v;\ + __asm__ ("mov %%" #regname ", %0\n\t" : "=a"(v));\ + return v;\ + }\ + static inline void write##regname(uint64_t v) {\ + __asm__ ("mov %0, %%" #regname "\n\t" :: "a"(v));\ + } + +/* Segment Selectors */ +DECLARE_REGISTER_ACCESSORS(es) +DECLARE_REGISTER_ACCESSORS(cs) +DECLARE_REGISTER_ACCESSORS(ss) +DECLARE_REGISTER_ACCESSORS(ds) +DECLARE_REGISTER_ACCESSORS(fs) +DECLARE_REGISTER_ACCESSORS(gs) + +/* Control Registers */ +DECLARE_REGISTER_ACCESSORS(cr0) +DECLARE_REGISTER_ACCESSORS(cr1) +DECLARE_REGISTER_ACCESSORS(cr2) +DECLARE_REGISTER_ACCESSORS(cr3) +DECLARE_REGISTER_ACCESSORS(cr4) + +/* Debug Registers */ +DECLARE_REGISTER_ACCESSORS(dr0) +DECLARE_REGISTER_ACCESSORS(dr1) +DECLARE_REGISTER_ACCESSORS(dr2) +DECLARE_REGISTER_ACCESSORS(dr3) +DECLARE_REGISTER_ACCESSORS(dr4) +DECLARE_REGISTER_ACCESSORS(dr5) +DECLARE_REGISTER_ACCESSORS(dr6) +DECLARE_REGISTER_ACCESSORS(dr7) static inline uint64_t -readcr3(void) +readflags(void) { uint64_t v; - __asm__ ("mov %%cr3, %0\n\t" : "=a"(v)); + __asm__ ("pushf\n\tpop %0\n\t" : "=a"(v)); return v; } -static inline uint64_t -readcr4(void) -{ - uint64_t v; - __asm__ ("mov %%cr4, %0\n\t" : "=a"(v)); - return v; -} - -static inline void -writecr4(uint64_t v) -{ - __asm__ ("mov %0, %%cr4\n\t" :: "a"(v)); -} - #endif diff --git a/include/x86/msr.h b/include/x86/msr.h index a889613..b9f30d3 100644 --- a/include/x86/msr.h +++ b/include/x86/msr.h @@ -3,7 +3,9 @@ #include -#define IA32_FEATURE_CONTROL 0x3A +#define IA32_FEATURE_CONTROL 0x03A +#define IA32_DEBUGCTL 0x1D9 +#define IA32_PAT 0x277 #define IA32_VMX_BASIC 0x480 #define IA32_VMX_PINBASED_CTLS 0x481 @@ -17,8 +19,12 @@ #define IA32_VMX_CR4_FIXED1 0x489 #define IA32_VMX_VMCS_ENUM 0x48A +#define IA32_EFER 0xC0000080 +#define IA32_FS_BASE 0xC0000100 +#define IA32_GS_BASE 0xC0000101 + static inline uint32_t -rdmsr32(uint32_t msr) +readmsr32(uint32_t msr) { uint32_t value; __asm__ ("rdmsr\n\t" : "=a"(value) : "c"(msr) : "edx"); @@ -26,7 +32,7 @@ rdmsr32(uint32_t msr) } static inline uint64_t -rdmsr64(uint32_t msr) +readmsr64(uint32_t msr) { uint64_t value; __asm__ ("rdmsr\n\t" : "=A"(value) : "c"(msr)); @@ -34,14 +40,14 @@ rdmsr64(uint32_t msr) } static inline void -wrmsr32(uint32_t msr, uint32_t value) +writemsr32(uint32_t msr, uint32_t value) { uint32_t high = 0; __asm__ ("wrmsr\n\t" :: "c"(msr), "a"(value), "d"(high)); } static inline void -wrmsr64(uint32_t msr, uint64_t value) +writemsr64(uint32_t msr, uint64_t value) { __asm__ ("wrmsr\n\t" :: "c"(msr), "A"(value)); } diff --git a/include/x86/vmx.h b/include/x86/vmx.h index 729f746..114fd57 100644 --- a/include/x86/vmx.h +++ b/include/x86/vmx.h @@ -89,9 +89,9 @@ vmread() } static inline void -vmwrite() +vmwrite(uint64_t field, uint64_t value) { - __asm__ volatile ("vmwrite\n\t" ::); + __asm__ volatile ("vmwrite %1, %0\n\t" :: "r"(field), "rm"(value)); } static inline void diff --git a/src/vintel.c b/src/vintel.c index c52bc71..e6f5f92 100644 --- a/src/vintel.c +++ b/src/vintel.c @@ -16,7 +16,7 @@ static struct VMCS *vmcs_region; static bool vintel_has_bios_support(void) { - uint64_t value = rdmsr64(IA32_FEATURE_CONTROL); + uint64_t value = readmsr64(IA32_FEATURE_CONTROL); return (value & 0x5) == 0x5; } @@ -44,6 +44,105 @@ vintel_has_support(char *err, size_t errmax) return true; } +static void +vintel_fix_cr_bits(void) +{ + uint64_t cr0_fixed0 = readmsr64(IA32_VMX_CR0_FIXED0); + uint64_t cr0_fixed1 = readmsr64(IA32_VMX_CR0_FIXED1); + uint64_t cr4_fixed0 = readmsr64(IA32_VMX_CR4_FIXED0); + uint64_t cr4_fixed1 = readmsr64(IA32_VMX_CR4_FIXED1); + + writecr0((readcr0() | cr0_fixed0) & cr0_fixed1); + writecr4((readcr4() | cr4_fixed0) & cr4_fixed1); +} + +#define GUEST_CR0 0x6800 +#define GUEST_CR3 0x6802 +#define GUEST_CR4 0x6804 +#define GUEST_DR7 0x681A +#define GUEST_RSP 0x681C +#define GUEST_RIP 0x681E +#define GUEST_RFLAGS 0x6820 +#define VMCS_LINK_POINTER 0x2800 +#define GUEST_IA32_DEBUGCTL 0x2802 +#define GUEST_IA32_PAT 0x2804 +#define GUEST_IA32_EFER 0x2806 +#define GUEST_FS_BASE 0x680E +#define GUEST_GS_BASE 0x6810 +#define GUEST_SYSENTER_CS 0x482A +#define GUEST_SYSENTER_ESP 0x6824 +#define GUEST_SYSENTER_EIP 0x6826 + +static void +vintel_init_guest(void) +{ + uint64_t guestSP = 0x0; + uint64_t guestIP = 0x0; + + vmwrite(GUEST_CR0, readcr0()); + vmwrite(GUEST_CR3, readcr3()); + vmwrite(GUEST_CR4, readcr4()); + vmwrite(GUEST_DR7, readdr7()); + vmwrite(GUEST_RFLAGS, readflags()); + vmwrite(GUEST_RSP, guestSP); + vmwrite(GUEST_RIP, guestIP); + vmwrite(VMCS_LINK_POINTER, -1LL); + vmwrite(GUEST_IA32_DEBUGCTL, readmsr64(IA32_DEBUGCTL)); + vmwrite(GUEST_IA32_PAT, readmsr64(IA32_PAT)); + vmwrite(GUEST_IA32_EFER, readmsr64(IA32_EFER)); + vmwrite(GUEST_FS_BASE, readmsr64(IA32_FS_BASE)); + vmwrite(GUEST_GS_BASE, readmsr64(IA32_GS_BASE)); + vmwrite(GUEST_SYSENTER_CS, readmsr64(0x174)); + vmwrite(GUEST_SYSENTER_ESP, readmsr64(0x175)); + vmwrite(GUEST_SYSENTER_EIP, readmsr64(0x176)); +} + +#if 0 +static void +vintel_init_host(void) +{ + // Read TR + trBase.LowPart = ((trItem[0] >> 16) & 0xFFFF) | ((trItem[1] & 0xFF) << 16) | ((trItem[1] & 0xFF000000) >> 8); + trBase.HighPart = trItem[2]; + + // Set TR + vmwrite(HOST_TR_BASE, trBase.QuadPart); + vmwrite(HOST_TR_SELECTOR, trSelector); + + // Set segment selectors + vmwrite(HOST_ES_SELECTOR, AsmReadES() & 0xfff8); + vmwrite(HOST_CS_SELECTOR, AsmReadCS() & 0xfff8); + vmwrite(HOST_SS_SELECTOR, AsmReadSS() & 0xfff8); + vmwrite(HOST_DS_SELECTOR, AsmReadDS() & 0xfff8); + vmwrite(HOST_FS_SELECTOR, AsmReadFS() & 0xfff8); + vmwrite(HOST_GS_SELECTOR, AsmReadGS() & 0xfff8); + + // Set control registers + vmwrite(HOST_CR0, readcr0()); + vmwrite(HOST_CR3, readcr3()); + vmwrite(HOST_CR4, readcr4()); + + // Set RSP and RIP + vmwrite(HOST_RSP, (ULONG64)pVcpu->VmxHostStackBase); + vmwrite(HOST_RIP, HostEip); + + // Set MSRs + vmwrite(HOST_IA32_PAT, __readmsr(IA32_MSR_PAT)); + vmwrite(HOST_IA32_EFER, __readmsr(IA32_MSR_EFER)); + vmwrite(HOST_FS_BASE, __readmsr(IA32_FS_BASE)); + vmwrite(HOST_GS_BASE, __readmsr(IA32_GS_KERNEL_BASE)); + vmwrite(HOST_IA32_SYSENTER_CS, __readmsr(0x174)); + vmwrite(HOST_IA32_SYSENTER_ESP, __readmsr(0x175)); + vmwrite(HOST_IA32_SYSENTER_EIP, __readmsr(0x176)); + + // Set GDT and IDT + GdtTable idtTable; + __sidt(&idtTable); + vmwrite(HOST_GDTR_BASE, gdtTable.Base); + vmwrite(HOST_IDTR_BASE, idtTable.Base); +} +#endif + void vintel_enable(void) { @@ -57,11 +156,13 @@ vintel_enable(void) wrmsr64(IA32_FEATURE_CONTROL, fctl); #endif + vintel_fix_cr_bits(); + Print(L"Allocating VMXON Page\n"); uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmxon_region); Print(L"VMXON: %p\n", vmxon_region); - vmxon_region->revisionID = rdmsr32(IA32_VMX_BASIC); + vmxon_region->revisionID = readmsr32(IA32_VMX_BASIC); uint64_t status = vmxon(vmxon_region); Print(L"VMXON Status: %p\n", (void *)status); @@ -72,18 +173,19 @@ vintel_enable(void) Print(L"Extended VMX Error\n"); } - Print(L"Allocating VMCS Page\n"); uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmcs_region); Print(L"VMCS: %p\n", vmcs_region); - vmcs_region->revisionID = rdmsr32(IA32_VMX_BASIC); + vmcs_region->revisionID = readmsr32(IA32_VMX_BASIC); status = vmclear(vmcs_region); Print(L"VMCLEAR Status: %p\n", (void *)status); status = vmptrld(vmcs_region); Print(L"VMPTRLD Status: %p\n", (void *)status); + + vintel_init_guest(); } struct virt_vtable virt_vtable_intel = {