2025-03-10 20:24:32 +01:00
|
|
|
#include <efi.h>
|
|
|
|
|
#include <efilib.h>
|
|
|
|
|
#include <efiapi.h>
|
|
|
|
|
|
2025-03-10 19:19:53 +01:00
|
|
|
#include <cpuid.h>
|
|
|
|
|
#include <x86/msr.h>
|
|
|
|
|
#include <x86/cr.h>
|
2025-03-11 02:06:12 +01:00
|
|
|
#include <x86/idt.h>
|
|
|
|
|
#include <x86/gdt.h>
|
2025-03-10 20:24:32 +01:00
|
|
|
#include <x86/vmx.h>
|
2025-03-10 19:19:53 +01:00
|
|
|
|
|
|
|
|
#include "virt.h"
|
|
|
|
|
#include "std.h"
|
|
|
|
|
|
2025-03-10 20:24:32 +01:00
|
|
|
static struct VMXON *vmxon_region;
|
2025-03-10 20:41:09 +01:00
|
|
|
static struct VMCS *vmcs_region;
|
2025-03-10 20:24:32 +01:00
|
|
|
|
2025-03-10 19:19:53 +01:00
|
|
|
static bool
|
|
|
|
|
vintel_has_bios_support(void)
|
|
|
|
|
{
|
2025-03-11 01:40:28 +01:00
|
|
|
uint64_t value = readmsr64(IA32_FEATURE_CONTROL);
|
2025-03-10 19:19:53 +01:00
|
|
|
return (value & 0x5) == 0x5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
vintel_has_cpu_support(void)
|
|
|
|
|
{
|
|
|
|
|
unsigned info[4];
|
|
|
|
|
__get_cpuid(0x1, &info[0], &info[1], &info[2], &info[3]);
|
|
|
|
|
return (info[2] & (1 << 5)) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
vintel_has_support(char *err, size_t errmax)
|
|
|
|
|
{
|
|
|
|
|
if (!vintel_has_cpu_support()) {
|
|
|
|
|
strlcpy(err, "CPU does not support VT-x.", errmax);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!vintel_has_bios_support()) {
|
|
|
|
|
strlcpy(err, "VT-x support is not enabled in BIOS.", errmax);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-11 01:40:28 +01:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-11 02:06:12 +01:00
|
|
|
#define HOST_ES_SELECTOR 0xC00
|
|
|
|
|
#define HOST_CS_SELECTOR 0xC02
|
|
|
|
|
#define HOST_SS_SELECTOR 0xC04
|
|
|
|
|
#define HOST_DS_SELECTOR 0xC06
|
|
|
|
|
#define HOST_FS_SELECTOR 0xC08
|
|
|
|
|
#define HOST_GS_SELECTOR 0xC0A
|
|
|
|
|
#define HOST_TR_SELECTOR 0xC0C
|
|
|
|
|
|
|
|
|
|
#define HOST_CR0 0x6C00
|
|
|
|
|
#define HOST_CR3 0x6C02
|
|
|
|
|
#define HOST_CR4 0x6C04
|
|
|
|
|
|
|
|
|
|
#define HOST_RSP 0x6C14
|
|
|
|
|
#define HOST_RIP 0x6C16
|
|
|
|
|
|
|
|
|
|
#define HOST_IA32_PAT 0x2C00
|
|
|
|
|
#define HOST_IA32_EFER 0x2C02
|
|
|
|
|
|
|
|
|
|
#define HOST_FS_BASE 0x6C06
|
|
|
|
|
#define HOST_GS_BASE 0x6C08
|
|
|
|
|
#define HOST_TR_BASE 0x6C0A
|
|
|
|
|
|
|
|
|
|
#define HOST_SYSENTER_CS 0x4C00
|
|
|
|
|
#define HOST_SYSENTER_ESP 0x6C10
|
|
|
|
|
#define HOST_SYSENTER_EIP 0x6C12
|
|
|
|
|
|
|
|
|
|
#define HOST_GDTR_BASE 0x6C0C
|
|
|
|
|
#define HOST_IDTR_BASE 0x6C0E
|
|
|
|
|
|
|
|
|
|
#if 1
|
2025-03-11 01:40:28 +01:00
|
|
|
static void
|
|
|
|
|
vintel_init_host(void)
|
|
|
|
|
{
|
2025-03-11 02:06:12 +01:00
|
|
|
#if 0
|
2025-03-11 01:40:28 +01:00
|
|
|
// Read TR
|
|
|
|
|
trBase.LowPart = ((trItem[0] >> 16) & 0xFFFF) | ((trItem[1] & 0xFF) << 16) | ((trItem[1] & 0xFF000000) >> 8);
|
|
|
|
|
trBase.HighPart = trItem[2];
|
2025-03-11 02:06:12 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uint64_t trBase = 0x0;
|
|
|
|
|
uint64_t trSelector = 0x0;
|
|
|
|
|
uint64_t hostSP = 0x0;
|
|
|
|
|
uint64_t hostIP = 0x0;
|
2025-03-11 01:40:28 +01:00
|
|
|
|
|
|
|
|
// Set TR
|
2025-03-11 02:06:12 +01:00
|
|
|
vmwrite(HOST_TR_BASE, trBase);
|
2025-03-11 01:40:28 +01:00
|
|
|
vmwrite(HOST_TR_SELECTOR, trSelector);
|
|
|
|
|
|
|
|
|
|
// Set segment selectors
|
2025-03-11 02:06:12 +01:00
|
|
|
vmwrite(HOST_ES_SELECTOR, reades() & 0xfff8);
|
|
|
|
|
vmwrite(HOST_CS_SELECTOR, readcs() & 0xfff8);
|
|
|
|
|
vmwrite(HOST_SS_SELECTOR, readss() & 0xfff8);
|
|
|
|
|
vmwrite(HOST_DS_SELECTOR, readds() & 0xfff8);
|
|
|
|
|
vmwrite(HOST_FS_SELECTOR, readfs() & 0xfff8);
|
|
|
|
|
vmwrite(HOST_GS_SELECTOR, readgs() & 0xfff8);
|
2025-03-11 01:40:28 +01:00
|
|
|
|
|
|
|
|
// Set control registers
|
|
|
|
|
vmwrite(HOST_CR0, readcr0());
|
|
|
|
|
vmwrite(HOST_CR3, readcr3());
|
|
|
|
|
vmwrite(HOST_CR4, readcr4());
|
|
|
|
|
|
|
|
|
|
// Set RSP and RIP
|
2025-03-11 02:06:12 +01:00
|
|
|
vmwrite(HOST_RSP, hostSP);
|
|
|
|
|
vmwrite(HOST_RIP, hostIP);
|
2025-03-11 01:40:28 +01:00
|
|
|
|
|
|
|
|
// Set MSRs
|
2025-03-11 02:06:12 +01:00
|
|
|
vmwrite(HOST_IA32_PAT, readmsr64(IA32_PAT));
|
|
|
|
|
vmwrite(HOST_IA32_EFER, readmsr64(IA32_EFER));
|
|
|
|
|
vmwrite(HOST_FS_BASE, readmsr64(IA32_FS_BASE));
|
|
|
|
|
vmwrite(HOST_GS_BASE, readmsr64(IA32_KERNEL_GS_BASE));
|
|
|
|
|
vmwrite(HOST_SYSENTER_CS, readmsr64(0x174));
|
|
|
|
|
vmwrite(HOST_SYSENTER_ESP, readmsr64(0x175));
|
|
|
|
|
vmwrite(HOST_SYSENTER_EIP, readmsr64(0x176));
|
2025-03-11 01:40:28 +01:00
|
|
|
|
|
|
|
|
// Set GDT and IDT
|
2025-03-11 02:06:12 +01:00
|
|
|
struct GDTR gdtr = storegdt();
|
|
|
|
|
struct IDTR idtr = storeidt();
|
|
|
|
|
vmwrite(HOST_GDTR_BASE, gdtr.base);
|
|
|
|
|
vmwrite(HOST_IDTR_BASE, idtr.base);
|
2025-03-11 01:40:28 +01:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-10 20:24:32 +01:00
|
|
|
void
|
|
|
|
|
vintel_enable(void)
|
|
|
|
|
{
|
|
|
|
|
Print(L"Set CR4 Bit\n");
|
|
|
|
|
writecr4(readcr4() | CR4_VMXE);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
Print(L"Enable in Feature Control\n");
|
|
|
|
|
uint64_t fctl = rdmsr64(IA32_FEATURE_CONTROL);
|
|
|
|
|
fctl |= (1 << 0);
|
|
|
|
|
wrmsr64(IA32_FEATURE_CONTROL, fctl);
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-11 01:40:28 +01:00
|
|
|
vintel_fix_cr_bits();
|
|
|
|
|
|
2025-03-10 20:24:32 +01:00
|
|
|
Print(L"Allocating VMXON Page\n");
|
|
|
|
|
uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmxon_region);
|
|
|
|
|
|
2025-03-10 20:41:09 +01:00
|
|
|
Print(L"VMXON: %p\n", vmxon_region);
|
2025-03-11 01:40:28 +01:00
|
|
|
vmxon_region->revisionID = readmsr32(IA32_VMX_BASIC);
|
2025-03-10 20:24:32 +01:00
|
|
|
|
|
|
|
|
uint64_t status = vmxon(vmxon_region);
|
|
|
|
|
Print(L"VMXON Status: %p\n", (void *)status);
|
|
|
|
|
if (status & (1 << 0)) {
|
|
|
|
|
Print(L"Invalid VMCS Pointer\n");
|
|
|
|
|
}
|
|
|
|
|
if (status & (1 << 6)) {
|
|
|
|
|
Print(L"Extended VMX Error\n");
|
|
|
|
|
}
|
2025-03-10 20:41:09 +01:00
|
|
|
|
|
|
|
|
Print(L"Allocating VMCS Page\n");
|
|
|
|
|
uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmcs_region);
|
|
|
|
|
|
|
|
|
|
Print(L"VMCS: %p\n", vmcs_region);
|
2025-03-11 01:40:28 +01:00
|
|
|
vmcs_region->revisionID = readmsr32(IA32_VMX_BASIC);
|
2025-03-10 20:41:09 +01:00
|
|
|
|
|
|
|
|
status = vmclear(vmcs_region);
|
|
|
|
|
Print(L"VMCLEAR Status: %p\n", (void *)status);
|
|
|
|
|
|
|
|
|
|
status = vmptrld(vmcs_region);
|
|
|
|
|
Print(L"VMPTRLD Status: %p\n", (void *)status);
|
2025-03-11 01:40:28 +01:00
|
|
|
|
|
|
|
|
vintel_init_guest();
|
2025-03-11 02:06:12 +01:00
|
|
|
vintel_init_host();
|
2025-03-10 20:24:32 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-10 19:19:53 +01:00
|
|
|
struct virt_vtable virt_vtable_intel = {
|
|
|
|
|
.has_support = vintel_has_support,
|
2025-03-10 20:24:32 +01:00
|
|
|
.enable = vintel_enable,
|
2025-03-10 19:19:53 +01:00
|
|
|
};
|