1
0
mirror of https://github.com/momo5502/hypervisor.git synced 2025-06-06 19:37:42 +00:00

More cleanup

This commit is contained in:
momo5502 2022-04-03 08:20:36 +02:00
parent 386015f94b
commit e9f0a14fff
4 changed files with 65 additions and 94 deletions

View File

@ -37,21 +37,23 @@ public:
} }
private: private:
bool hypervisor_was_enabled_{false};
hypervisor hypervisor_{};
sleep_callback sleep_callback_{}; sleep_callback sleep_callback_{};
irp irp_{}; irp irp_{};
hypervisor hypervisor_{};
void sleep_notification(const sleep_callback::type type) void sleep_notification(const sleep_callback::type type)
{ {
if (type == sleep_callback::type::sleep) if (type == sleep_callback::type::sleep)
{ {
debug_log("Going to sleep!"); debug_log("Going to sleep...\n");
this->hypervisor_was_enabled_ = this->hypervisor_.is_enabled();
this->hypervisor_.disable(); this->hypervisor_.disable();
} }
if (type == sleep_callback::type::wakeup) if (type == sleep_callback::type::wakeup && this->hypervisor_was_enabled_)
{ {
debug_log("Waking up!"); debug_log("Waking up...\n");
this->hypervisor_.enable(); this->hypervisor_.enable();
} }
} }

View File

@ -44,6 +44,38 @@ namespace
__cpuid(cpuid_data, HYPERV_CPUID_INTERFACE); __cpuid(cpuid_data, HYPERV_CPUID_INTERFACE);
return cpuid_data[0] == 'momo'; return cpuid_data[0] == 'momo';
} }
void cpature_special_registers(vmx::special_registers& special_registers)
{
special_registers.cr0 = __readcr0();
special_registers.cr3 = __readcr3();
special_registers.cr4 = __readcr4();
special_registers.debug_control = __readmsr(IA32_DEBUGCTL);
special_registers.msr_gs_base = __readmsr(IA32_GS_BASE);
special_registers.kernel_dr7 = __readdr(7);
_sgdt(&special_registers.gdtr.limit);
__sidt(&special_registers.idtr.limit);
_str(&special_registers.tr);
_sldt(&special_registers.ldtr);
}
void capture_cpu_context(vmx::vm_launch_context& launch_context)
{
cpature_special_registers(launch_context.special_registers);
RtlCaptureContext(&launch_context.context_frame);
}
void restore_descriptor_tables(vmx::vm_launch_context& launch_context)
{
__lgdt(&launch_context.special_registers.gdtr.limit);
__lidt(&launch_context.special_registers.idtr.limit);
}
[[ noreturn ]] void resume_vmx()
{
__vmx_vmresume();
}
} }
hypervisor::hypervisor() hypervisor::hypervisor()
@ -85,6 +117,13 @@ void hypervisor::disable()
{ {
this->disable_core(); this->disable_core();
}); });
debug_log("Hypervisor disabled on all cores\n");
}
bool hypervisor::is_enabled() const
{
return is_hypervisor_present();
} }
void hypervisor::enable() void hypervisor::enable()
@ -105,6 +144,8 @@ void hypervisor::enable()
this->disable(); this->disable();
throw std::runtime_error("Hypervisor initialization failed"); throw std::runtime_error("Hypervisor initialization failed");
} }
debug_log("Hypervisor enabled on %d cores\n", this->vm_state_count_);
} }
bool hypervisor::try_enable_core(const uint64_t system_directory_table_base) bool hypervisor::try_enable_core(const uint64_t system_directory_table_base)
@ -126,20 +167,6 @@ bool hypervisor::try_enable_core(const uint64_t system_directory_table_base)
} }
} }
void ShvCaptureSpecialRegisters(vmx::special_registers* special_registers)
{
special_registers->cr0 = __readcr0();
special_registers->cr3 = __readcr3();
special_registers->cr4 = __readcr4();
special_registers->debug_control = __readmsr(IA32_DEBUGCTL);
special_registers->msr_gs_base = __readmsr(IA32_GS_BASE);
special_registers->kernel_dr7 = __readdr(7);
_sgdt(&special_registers->gdtr.limit);
__sidt(&special_registers->idtr.limit);
_str(&special_registers->tr);
_sldt(&special_registers->ldtr);
}
uintptr_t uintptr_t
FORCEINLINE FORCEINLINE
ShvVmxRead( ShvVmxRead(
@ -566,15 +593,12 @@ VOID
ShvVpRestoreAfterLaunch( ShvVpRestoreAfterLaunch(
VOID) VOID)
{ {
debug_log("[%d] restore\n", thread::get_processor_index());
// //
// Get the per-processor data. This routine temporarily executes on the // Get the per-processor data. This routine temporarily executes on the
// same stack as the hypervisor (using no real stack space except the home // same stack as the hypervisor (using no real stack space except the home
// registers), so we can retrieve the VP the same way the hypervisor does. // registers), so we can retrieve the VP the same way the hypervisor does.
// //
auto* vpData = (vmx::vm_state*)((uintptr_t)_AddressOfReturnAddress() + auto* vpData = (vmx::vm_state*)((uintptr_t)_AddressOfReturnAddress() + sizeof(CONTEXT) - KERNEL_STACK_SIZE);
sizeof(CONTEXT) -
KERNEL_STACK_SIZE);
// //
// Record that VMX is now enabled by returning back to ShvVpInitialize with // Record that VMX is now enabled by returning back to ShvVpInitialize with
@ -750,37 +774,6 @@ ShvVmxHandleExit(
__vmx_vmwrite(VMCS_GUEST_RIP, VpState->GuestRip); __vmx_vmwrite(VMCS_GUEST_RIP, VpState->GuestRip);
} }
VOID
ShvOsUnprepareProcessor(
_In_ vmx::vm_state* VpData
)
{
//
// When running in VMX root mode, the processor will set limits of the
// GDT and IDT to 0xFFFF (notice that there are no Host VMCS fields to
// set these values). This causes problems with PatchGuard, which will
// believe that the GDTR and IDTR have been modified by malware, and
// eventually crash the system. Since we know what the original state
// of the GDTR and IDTR was, simply restore it now.
//
__lgdt(&VpData->launch_context.special_registers.gdtr.limit);
__lidt(&VpData->launch_context.special_registers.idtr.limit);
}
DECLSPEC_NORETURN
VOID
ShvVmxResume()
{
//
// Issue a VMXRESUME. The reason that we've defined an entire function for
// this sole instruction is both so that we can use it as the target of the
// VMCS when re-entering the VM After a VM-Exit, as well as so that we can
// decorate it with the DECLSPEC_NORETURN marker, which is not set on the
// intrinsic (as it can fail in case of an error).
//
__vmx_vmresume();
}
extern "C" DECLSPEC_NORETURN extern "C" DECLSPEC_NORETURN
VOID VOID
ShvVmxEntryHandler() ShvVmxEntryHandler()
@ -836,7 +829,7 @@ ShvVmxEntryHandler()
// //
// Perform any OS-specific CPU uninitialization work // Perform any OS-specific CPU uninitialization work
// //
ShvOsUnprepareProcessor(vpData); restore_descriptor_tables(vpData->launch_context);
// //
// Our callback routine may have interrupted an arbitrary user process, // Our callback routine may have interrupted an arbitrary user process,
@ -866,22 +859,13 @@ ShvVmxEntryHandler()
} }
else else
{ {
//
// Because we won't be returning back into assembly code, nothing will
// ever know about the "pop rcx" that must technically be done (or more
// accurately "add rsp, 4" as rcx will already be correct thanks to the
// fixup earlier. In order to keep the stack sane, do that adjustment
// here.
//
//Context->Rsp += sizeof(Context->Rcx);
// //
// Return into a VMXRESUME intrinsic, which we broke out as its own // Return into a VMXRESUME intrinsic, which we broke out as its own
// function, in order to allow this to work. No assembly code will be // function, in order to allow this to work. No assembly code will be
// needed as RtlRestoreContext will fix all the GPRs, and what we just // needed as RtlRestoreContext will fix all the GPRs, and what we just
// did to RSP will take care of the rest. // did to RSP will take care of the rest.
// //
Context->Rip = (UINT64)ShvVmxResume; Context->Rip = reinterpret_cast<uint64_t>(resume_vmx);
} }
// //
@ -1153,23 +1137,17 @@ INT32 ShvVmxLaunchOnVp(vmx::vm_state* VpData)
VpData->launch_context.msr_data[i].QuadPart = __readmsr(IA32_VMX_BASIC + i); VpData->launch_context.msr_data[i].QuadPart = __readmsr(IA32_VMX_BASIC + i);
} }
debug_log("[%d] mtrr init\n", thread::get_processor_index());
// //
// Initialize all the MTRR-related MSRs by reading their value and build // Initialize all the MTRR-related MSRs by reading their value and build
// range structures to describe their settings // range structures to describe their settings
// //
ShvVmxMtrrInitialize(VpData); ShvVmxMtrrInitialize(VpData);
debug_log("[%d] ept init\n", thread::get_processor_index());
// //
// Initialize the EPT structures // Initialize the EPT structures
// //
ShvVmxEptInitialize(VpData); ShvVmxEptInitialize(VpData);
debug_log("[%d] entering root mode\n", thread::get_processor_index());
// //
// Attempt to enter VMX root mode on this processor. // Attempt to enter VMX root mode on this processor.
// //
@ -1178,8 +1156,6 @@ INT32 ShvVmxLaunchOnVp(vmx::vm_state* VpData)
throw std::runtime_error("Not available"); throw std::runtime_error("Not available");
} }
debug_log("[%d] setting up vmcs\n", thread::get_processor_index());
// //
// Initialize the VMCS, both guest and host state. // Initialize the VMCS, both guest and host state.
// //
@ -1191,38 +1167,20 @@ INT32 ShvVmxLaunchOnVp(vmx::vm_state* VpData)
// processor to jump to ShvVpRestoreAfterLaunch on success, or return // processor to jump to ShvVpRestoreAfterLaunch on success, or return
// back to the caller on failure. // back to the caller on failure.
// //
debug_log("[%d] vmx launch\n", thread::get_processor_index());
return ShvVmxLaunch(); return ShvVmxLaunch();
} }
void hypervisor::enable_core(const uint64_t system_directory_table_base) void hypervisor::enable_core(const uint64_t system_directory_table_base)
{ {
debug_log("[%d] Enabling hypervisor on core %d\n", thread::get_processor_index(), thread::get_processor_index()); debug_log("Enabling hypervisor on core %d\n", thread::get_processor_index(), thread::get_processor_index());
auto* vm_state = this->get_current_vm_state(); auto* vm_state = this->get_current_vm_state();
vm_state->launch_context.system_directory_table_base = system_directory_table_base; vm_state->launch_context.system_directory_table_base = system_directory_table_base;
debug_log("[%d] Capturing registers\n", thread::get_processor_index()); capture_cpu_context(vm_state->launch_context);
ShvCaptureSpecialRegisters(&vm_state->launch_context.special_registers);
//
// Then, capture the entire register state. We will need this, as once we
// launch the VM, it will begin execution at the defined guest instruction
// pointer, which we set to ShvVpRestoreAfterLaunch, with the registers set
// to whatever value they were deep inside the VMCS/VMX initialization code.
// By using RtlRestoreContext, that function sets the AC flag in EFLAGS and
// returns here with our registers restored.
//
debug_log("[%d] Capturing context\n", thread::get_processor_index());
RtlCaptureContext(&vm_state->launch_context.context_frame);
if ((__readeflags() & EFLAGS_ALIGNMENT_CHECK_FLAG_FLAG) == 0) if ((__readeflags() & EFLAGS_ALIGNMENT_CHECK_FLAG_FLAG) == 0)
{ {
//
// If the AC bit is not set in EFLAGS, it means that we have not yet
// launched the VM. Attempt to initialize VMX on this processor.
//
debug_log("[%d] Launching\n", thread::get_processor_index());
ShvVmxLaunchOnVp(vm_state); ShvVmxLaunchOnVp(vm_state);
} }
@ -1234,8 +1192,16 @@ void hypervisor::enable_core(const uint64_t system_directory_table_base)
void hypervisor::disable_core() void hypervisor::disable_core()
{ {
debug_log("Disabling hypervisor on core %d\n", thread::get_processor_index());
int32_t cpu_info[4]{0}; int32_t cpu_info[4]{0};
__cpuidex(cpu_info, 0x41414141, 0x42424242); __cpuidex(cpu_info, 0x41414141, 0x42424242);
if (this->is_enabled())
{
debug_log("Shutdown for core %d failed. Issuing kernel panic!\n", thread::get_processor_index());
KeBugCheckEx(DRIVER_VIOLATION, 1, 0, 0, 0);
}
} }
void hypervisor::allocate_vm_states() void hypervisor::allocate_vm_states()
@ -1245,7 +1211,8 @@ void hypervisor::allocate_vm_states()
throw std::runtime_error("VM states are still in use"); throw std::runtime_error("VM states are still in use");
} }
// As Windows technically supports cpu hot-plugging, keep track of the allocation count // As Windows technically supports cpu hot-plugging, keep track of the allocation count.
// However virtualizing the hot-plugged cpu won't be supported here.
this->vm_state_count_ = thread::get_processor_count(); this->vm_state_count_ = thread::get_processor_count();
this->vm_states_ = new vmx::vm_state*[this->vm_state_count_]{}; this->vm_states_ = new vmx::vm_state*[this->vm_state_count_]{};

View File

@ -17,6 +17,8 @@ public:
void enable(); void enable();
void disable(); void disable();
bool is_enabled() const;
private: private:
uint32_t vm_state_count_{0}; uint32_t vm_state_count_{0};
vmx::vm_state** vm_states_{nullptr}; vmx::vm_state** vm_states_{nullptr};

View File

@ -41,7 +41,7 @@ namespace vmx
struct vm_launch_context struct vm_launch_context
{ {
struct special_registers special_registers; special_registers special_registers;
CONTEXT context_frame; CONTEXT context_frame;
uint64_t system_directory_table_base; uint64_t system_directory_table_base;
LARGE_INTEGER msr_data[17]; LARGE_INTEGER msr_data[17];