diff --git a/include/x86/msr.h b/include/x86/msr.h index 2a7290e..15e96a5 100644 --- a/include/x86/msr.h +++ b/include/x86/msr.h @@ -19,8 +19,10 @@ #define IA32_VMX_CR4_FIXED1 0x489 #define IA32_VMX_TRUE_ENTRY_CTLS 0x490 #define IA32_VMX_VMCS_ENUM 0x48A +#define IA32_VMX_PROCBASED_CTLS2 0x48B #define IA32_VMX_TRUE_PINBASED_CTLS 0x48D #define IA32_VMX_TRUE_PROCBASED_CTLS 0x48E +#define IA32_VMX_TRUE_EXIT_CTLS 0x48F #define IA32_EFER 0xC0000080 #define IA32_FS_BASE 0xC0000100 diff --git a/include/x86/vmx.h b/include/x86/vmx.h index e296828..2b3c904 100644 --- a/include/x86/vmx.h +++ b/include/x86/vmx.h @@ -99,10 +99,16 @@ vmread(uint64_t field) return value; } -static inline void +static inline uint64_t vmwrite(uint64_t field, uint64_t value) { - __asm__ volatile ("vmwrite %0, %1\n\t" :: "rm"(value), "r"(field)); + uint64_t flags; + __asm__ volatile ( + "vmwrite %1, %2\n\t" + "pushf \n\t" + "pop %0 \n\t" + : "=r"(flags) : "rm"(value), "r"(field)); + return flags; } static inline void diff --git a/src/vintel.c b/src/vintel.c index e163656..de0769a 100644 --- a/src/vintel.c +++ b/src/vintel.c @@ -94,6 +94,19 @@ vintel_fix_cr_bits(void) #define CPU_BASED_VM_EXEC_CONTROL 0x4002 #define VM_ENTRY_MSR_LOAD_COUNT 0x4014 #define VM_ENTRY_INTR_INFO_FIELD 0x4016 +#define CPU_BASED_VM_EXEC_CONTROL2 0x401E + +static void +checked_vmwrite(uint64_t field, uint64_t value) +{ + uint64_t status = vmwrite(field, value); + if (status & (1 << 0)) { + AsciiPrint("vmwrite(%lx): Invalid VMCS Pointer\n", field); + } + if (status & (1 << 6)) { + AsciiPrint("vmwrite(%lx): %a\n", vmcs_describe_error()); + } +} static uint64_t vmx_adjust_controls(uint64_t value, uint32_t msr) @@ -109,12 +122,19 @@ vmx_init_execution_controls(void) uint64_t vmxBasic = readmsr64(IA32_VMX_BASIC); uint64_t pinBasedMsr = ((vmxBasic >> 55) & 1) ? IA32_VMX_TRUE_PINBASED_CTLS : IA32_VMX_PINBASED_CTLS; uint64_t procBasedMsr = ((vmxBasic >> 55) & 1) ? IA32_VMX_TRUE_PROCBASED_CTLS : IA32_VMX_PROCBASED_CTLS; + uint64_t procBasedMsr2 = IA32_VMX_PROCBASED_CTLS2; uint64_t pinBasedControls = vmx_adjust_controls(0, pinBasedMsr); uint64_t procBasedControls = vmx_adjust_controls(0, procBasedMsr); + uint64_t procBasedControls2 = vmx_adjust_controls(0, procBasedMsr2); - vmwrite(PIN_BASED_VM_EXEC_CONTROL, pinBasedControls); - vmwrite(CPU_BASED_VM_EXEC_CONTROL, procBasedControls); + checked_vmwrite(PIN_BASED_VM_EXEC_CONTROL, pinBasedControls); + checked_vmwrite(CPU_BASED_VM_EXEC_CONTROL, procBasedControls); + checked_vmwrite(CPU_BASED_VM_EXEC_CONTROL2, procBasedControls2); + + AsciiPrint("PIN_BASED_VM_EXEC_CONTROL: %lx\n", pinBasedControls); + AsciiPrint("CPU_BASED_VM_EXEC_CONTROL: %lx\n", procBasedControls); + AsciiPrint("CPU_BASED_VM_EXEC_CONTROL2: %lx\n", procBasedControls2); } // HACK @@ -133,10 +153,10 @@ vintel_write_guest_segment(struct GDTR gdtr, int reg, int ss, uint32_t hibase) { struct segdescr *descr = &gdtr.base[ss >> 3]; - vmwrite(GUEST_ES_SELECTOR + 2 * reg, ss & 0xfff8); - vmwrite(GUEST_ES_BASE + 2 * reg, getsegbase(descr) | ((uint64_t)hibase << 32)); - vmwrite(GUEST_ES_LIMIT + 2 * reg, getseglimit(descr)); - vmwrite(GUEST_ES_ACCESS + 2 * reg, getsegaccess(descr, false)); + checked_vmwrite(GUEST_ES_SELECTOR + 2 * reg, ss & 0xfff8); + checked_vmwrite(GUEST_ES_BASE + 2 * reg, getsegbase(descr) | ((uint64_t)hibase << 32)); + checked_vmwrite(GUEST_ES_LIMIT + 2 * reg, getseglimit(descr)); + checked_vmwrite(GUEST_ES_ACCESS + 2 * reg, getsegaccess(descr, false)); } static void @@ -162,33 +182,33 @@ vintel_init_guest(void) * Then later reload the GDT to make the shadow registers consistent again. * Sigh. */ - vmwrite(GUEST_ES_SELECTOR + 2 * 7, readtr() & 0xfff8); - vmwrite(GUEST_ES_BASE + 2 * 7, (uintptr_t)myprocvisor()->host_tss); // just abuse the host's TSS for this - vmwrite(GUEST_ES_LIMIT + 2 * 7, sizeof (struct TSS) - 1); - vmwrite(GUEST_ES_ACCESS + 2 * 7, 0x00000089); + checked_vmwrite(GUEST_ES_SELECTOR + 2 * 7, readtr() & 0xfff8); + checked_vmwrite(GUEST_ES_BASE + 2 * 7, (uintptr_t)myprocvisor()->host_tss); // just abuse the host's TSS for this + checked_vmwrite(GUEST_ES_LIMIT + 2 * 7, sizeof (struct TSS) - 1); + checked_vmwrite(GUEST_ES_ACCESS + 2 * 7, 0x00000089); // Set control registers - vmwrite(GUEST_CR0, readcr0()); - vmwrite(GUEST_CR3, readcr3()); - vmwrite(GUEST_CR4, readcr4()); + checked_vmwrite(GUEST_CR0, readcr0()); + checked_vmwrite(GUEST_CR3, readcr3()); + checked_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)); + checked_vmwrite(GUEST_DR7, readdr7()); + checked_vmwrite(GUEST_RFLAGS, readflags()); + checked_vmwrite(GUEST_RSP, guestSP); + checked_vmwrite(GUEST_RIP, guestIP); + checked_vmwrite(VMCS_LINK_POINTER, -1LL); + checked_vmwrite(GUEST_IA32_DEBUGCTL, readmsr64(IA32_DEBUGCTL)); + checked_vmwrite(GUEST_IA32_PAT, readmsr64(IA32_PAT)); + checked_vmwrite(GUEST_IA32_EFER, readmsr64(IA32_EFER)); + checked_vmwrite(GUEST_FS_BASE, readmsr64(IA32_FS_BASE)); + checked_vmwrite(GUEST_GS_BASE, readmsr64(IA32_GS_BASE)); + checked_vmwrite(GUEST_SYSENTER_CS, readmsr64(0x174)); + checked_vmwrite(GUEST_SYSENTER_ESP, readmsr64(0x175)); + checked_vmwrite(GUEST_SYSENTER_EIP, readmsr64(0x176)); // Set GDT and IDT - vmwrite(GUEST_GDTR_BASE, (uintptr_t)gdtr.base); - vmwrite(GUEST_IDTR_BASE, (uintptr_t)idtr.base); + checked_vmwrite(GUEST_GDTR_BASE, (uintptr_t)gdtr.base); + checked_vmwrite(GUEST_IDTR_BASE, (uintptr_t)idtr.base); } #define HOST_ES_SELECTOR 0xC00 @@ -220,6 +240,11 @@ vintel_init_guest(void) #define HOST_GDTR_BASE 0x6C0C #define HOST_IDTR_BASE 0x6C0E +#define CR3_TARGET_COUNT 0x400A +#define VM_EXIT_CONTROLS 0x400C + +#define EXCEPTION_BITMAP 0x4004 + static void vintel_init_host(void) { @@ -229,30 +254,30 @@ vintel_init_host(void) uint64_t hostIP = 0x0; // Set segment selectors - vmwrite(HOST_ES_SELECTOR, 0x10); - vmwrite(HOST_CS_SELECTOR, 0x08); - vmwrite(HOST_SS_SELECTOR, 0x10); - vmwrite(HOST_DS_SELECTOR, 0x10); - vmwrite(HOST_FS_SELECTOR, 0x00); - vmwrite(HOST_GS_SELECTOR, 0x00); - vmwrite(HOST_TR_SELECTOR, 0x18); + checked_vmwrite(HOST_ES_SELECTOR, 0x10); + checked_vmwrite(HOST_CS_SELECTOR, 0x08); + checked_vmwrite(HOST_SS_SELECTOR, 0x10); + checked_vmwrite(HOST_DS_SELECTOR, 0x10); + checked_vmwrite(HOST_FS_SELECTOR, 0x00); + checked_vmwrite(HOST_GS_SELECTOR, 0x00); + checked_vmwrite(HOST_TR_SELECTOR, 0x18); // Set control registers - vmwrite(HOST_CR0, readcr0()); - vmwrite(HOST_CR3, readcr3()); - vmwrite(HOST_CR4, readcr4()); + checked_vmwrite(HOST_CR0, readcr0()); + checked_vmwrite(HOST_CR3, readcr3()); + checked_vmwrite(HOST_CR4, readcr4()); // Set RSP and RIP - vmwrite(HOST_RSP, hostSP); - vmwrite(HOST_RIP, hostIP); + checked_vmwrite(HOST_RSP, hostSP); + checked_vmwrite(HOST_RIP, hostIP); // Set MSRs - vmwrite(HOST_IA32_PAT, readmsr64(IA32_PAT)); - vmwrite(HOST_IA32_EFER, readmsr64(IA32_EFER)); + checked_vmwrite(HOST_IA32_PAT, readmsr64(IA32_PAT)); + checked_vmwrite(HOST_IA32_EFER, readmsr64(IA32_EFER)); // Set GDT and IDT - vmwrite(HOST_GDTR_BASE, (uintptr_t)pv->host_gdtr.base); - vmwrite(HOST_IDTR_BASE, (uintptr_t)pv->host_idtr.base); + checked_vmwrite(HOST_GDTR_BASE, (uintptr_t)pv->host_gdtr.base); + checked_vmwrite(HOST_IDTR_BASE, (uintptr_t)pv->host_idtr.base); } void @@ -309,10 +334,19 @@ vintel_enable(void) uint64_t vmxBasic = readmsr64(IA32_VMX_BASIC); uint32_t msr = ((vmxBasic >> 55) & 1) ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS; uint64_t entryControls = vmx_adjust_controls(0x200, msr); // 0x200 enables IA-32e mode - vmwrite(VM_ENTRY_CONTROLS, entryControls); + checked_vmwrite(VM_ENTRY_CONTROLS, entryControls); + AsciiPrint("VM_ENTRY_CONTROLS: %lx\n", entryControls); - vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); - vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); + uint32_t exitMsr = ((vmxBasic >> 55) & 1) ? IA32_VMX_TRUE_EXIT_CTLS : IA32_VMX_EXIT_CTLS; + uint64_t exitControls = vmx_adjust_controls(0x0, exitMsr); + checked_vmwrite(VM_EXIT_CONTROLS, exitControls); + AsciiPrint("VM_EXIT_CONTROLS: %lx\n", exitControls); + + checked_vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); + checked_vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); + checked_vmwrite(CR3_TARGET_COUNT, 0); + + checked_vmwrite(EXCEPTION_BITMAP, 0); } status = vmlaunch();