diff --git a/bluepill.vcxproj b/bluepill.vcxproj
index 9c72598..6b4936c 100644
--- a/bluepill.vcxproj
+++ b/bluepill.vcxproj
@@ -85,8 +85,10 @@
+
+
@@ -96,11 +98,12 @@
+
+
-
@@ -111,7 +114,6 @@
-
diff --git a/bluepill.vcxproj.filters b/bluepill.vcxproj.filters
index a1d371b..84c04e5 100644
--- a/bluepill.vcxproj.filters
+++ b/bluepill.vcxproj.filters
@@ -38,6 +38,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -67,15 +73,18 @@
Header Files
-
- Header Files
-
Header Files
Header Files
+
+ Header Files
+
+
+ Header Files
+
@@ -84,9 +93,6 @@
Source Files
-
- Source Files
-
Source Files
diff --git a/command.cpp b/command.cpp
new file mode 100644
index 0000000..22ce2d9
--- /dev/null
+++ b/command.cpp
@@ -0,0 +1,26 @@
+#include "command.hpp"
+
+namespace command
+{
+ auto get(u64 dirbase, u64 command_ptr) -> vmcall_command_t
+ {
+ const auto virt_map =
+ mm::map_virt(dirbase, command_ptr);
+
+ if (!virt_map)
+ return {};
+
+ return *reinterpret_cast(virt_map);
+ }
+
+ auto set(u64 dirbase, u64 command_ptr, const vmcall_command_t& vmcall_command) -> void
+ {
+ const auto virt_map =
+ mm::map_virt(dirbase, command_ptr);
+
+ if (!virt_map)
+ return;
+
+ *reinterpret_cast(virt_map) = vmcall_command;
+ }
+}
\ No newline at end of file
diff --git a/command.hpp b/command.hpp
new file mode 100644
index 0000000..8451d91
--- /dev/null
+++ b/command.hpp
@@ -0,0 +1,62 @@
+#pragma once
+#include "mm.hpp"
+
+namespace command
+{
+ enum class vmcall_option
+ {
+ translate,
+ copy_virt,
+ write_phys,
+ read_phys,
+ dirbase
+ };
+
+ typedef struct _vmcall_command_t
+ {
+ bool present;
+ bool result;
+ vmcall_option option;
+
+ union
+ {
+ struct
+ {
+ u64 dirbase;
+ u64 virt_addr;
+ u64 phys_addr;
+ } translate;
+
+ struct
+ {
+ u64 virt_src;
+ u64 dirbase_src;
+ u64 virt_dest;
+ u64 dirbase_dest;
+ u64 size;
+ } copy_virt;
+
+ struct
+ {
+ u64 virt_src;
+ u64 dirbase_src;
+ u64 phys_dest;
+ u64 size;
+ } write_phys;
+
+ struct
+ {
+ u64 phys_src;
+ u64 dirbase_dest;
+ u64 virt_dest;
+ u64 size;
+ } read_phys;
+
+ u64 dirbase;
+ };
+
+ } vmcall_command_t, * pvmcall_command_t;
+
+ auto get(u64 dirbase, u64 command_ptr)->vmcall_command_t;
+ auto set(u64 dirbase, u64 command_ptr, const vmcall_command_t& vmcall_command) -> void;
+}
\ No newline at end of file
diff --git a/exception.cpp b/exception.cpp
new file mode 100644
index 0000000..b9abee5
--- /dev/null
+++ b/exception.cpp
@@ -0,0 +1,48 @@
+#include "exception.hpp"
+
+namespace exception
+{
+ auto handle_debug() -> void
+ {
+ rflags g_rflags;
+ ia32_debugctl_register debugctl;
+
+ __vmx_vmread(VMCS_GUEST_RFLAGS, &g_rflags.flags);
+ __vmx_vmread(VMCS_GUEST_DEBUGCTL, &debugctl.flags);
+
+ // should also check: if ((g_rflags.trap_flag && (debugctl.btf && instruction.type == branching))
+ if (g_rflags.trap_flag && !debugctl.btf)
+ {
+ vmx_exit_qualification_debug_exception pending_db;
+ __vmx_vmread(VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &pending_db.flags);
+ pending_db.single_instruction = true;
+ __vmx_vmwrite(VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, pending_db.flags);
+ }
+
+ vmx_interruptibility_state interrupt_state;
+ __vmx_vmread(VMCS_GUEST_INTERRUPTIBILITY_STATE,
+ reinterpret_cast(&interrupt_state.flags));
+
+ // not going to clear blocked by NMI or
+ // SMI stuff as IRETQ should unblock that...
+ // im not emulating IRETQ instruction either...
+ interrupt_state.blocking_by_mov_ss = false;
+ interrupt_state.blocking_by_sti = false;
+ __vmx_vmwrite(VMCS_GUEST_INTERRUPTIBILITY_STATE, interrupt_state.flags);
+ }
+
+ auto injection(interruption_type type, u8 vector, ecode_t error_code) -> void
+ {
+ vmentry_interrupt_information interrupt{};
+ interrupt.interruption_type = type;
+ interrupt.vector = vector;
+ interrupt.valid = true;
+
+ if (error_code.valid)
+ {
+ interrupt.deliver_error_code = error_code.valid;
+ __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, error_code.valid);
+ }
+ __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
+ }
+}
\ No newline at end of file
diff --git a/exception.hpp b/exception.hpp
new file mode 100644
index 0000000..10ddc40
--- /dev/null
+++ b/exception.hpp
@@ -0,0 +1,11 @@
+#pragma once
+#include "hv_types.hpp"
+
+namespace exception
+{
+ using ecode_t = struct { bool valid; u64 value; };
+ auto injection(interruption_type type, u8 vector, ecode_t error_code = {}) -> void;
+
+ // https://howtohypervise.blogspot.com/2019/01/a-common-missight-in-most-hypervisors.html
+ auto handle_debug() -> void;
+}
\ No newline at end of file
diff --git a/exit_handler.cpp b/exit_handler.cpp
index ea3fe7d..ff1014c 100644
--- a/exit_handler.cpp
+++ b/exit_handler.cpp
@@ -1,32 +1,10 @@
#include "vmxexit_handler.h"
-auto get_command(u64 dirbase, u64 command_ptr) -> vmcall_command_t
-{
- const auto virt_map =
- mm::map_virt(dirbase, command_ptr);
-
- if (!virt_map)
- return {};
-
- return *reinterpret_cast(virt_map);
-}
-
-auto set_command(u64 dirbase, u64 command_ptr, const vmcall_command_t& vmcall_command) -> void
-{
- const auto virt_map =
- mm::map_virt(dirbase, command_ptr);
-
- if (!virt_map)
- return;
-
- *reinterpret_cast(virt_map) = vmcall_command;
-}
-
auto vmresume_failure() -> void
{
size_t value;
__vmx_vmread(VMCS_VM_INSTRUCTION_ERROR, &value);
- __debugbreak();
+ dbg::print("> vmresume error... reason = 0x%x\n", value);
}
auto exit_handler(hv::pguest_registers regs) -> void
@@ -44,19 +22,13 @@ auto exit_handler(hv::pguest_registers regs) -> void
regs->rbx = result[1];
regs->rcx = result[2];
regs->rdx = result[3];
- break;
+ goto advance_rip;
}
// shouldnt get an exit when the LP is already executing an NMI...
// so it should be safe to inject an NMI here...
case VMX_EXIT_REASON_NMI_WINDOW:
{
- vmentry_interrupt_information interrupt{};
- interrupt.interruption_type = interruption_type::non_maskable_interrupt;
- interrupt.vector = EXCEPTION_NMI;
- interrupt.valid = true;
-
- __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
- __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, NULL);
+ exception::injection(interruption_type::non_maskable_interrupt, EXCEPTION_NMI);
// turn off NMI window exiting since we handled the NMI...
ia32_vmx_procbased_ctls_register procbased_ctls;
@@ -64,16 +36,7 @@ auto exit_handler(hv::pguest_registers regs) -> void
procbased_ctls.nmi_window_exiting = false;
__vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, procbased_ctls.flags);
- return; // dont advance rip...
- }
- case VMX_EXIT_REASON_EXCEPTION_OR_NMI:
- {
- ia32_vmx_procbased_ctls_register procbased_ctls;
- __vmx_vmread(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, &procbased_ctls.flags);
-
- procbased_ctls.nmi_window_exiting = true;
- __vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, procbased_ctls.flags);
- return; // dont advance rip...
+ goto dont_advance;
}
case VMX_EXIT_REASON_EXECUTE_XSETBV:
{
@@ -96,21 +59,14 @@ auto exit_handler(hv::pguest_registers regs) -> void
If the LOCK prefix is used.
*/
_xsetbv(regs->rcx, value.value);
- break;
+ goto advance_rip;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- vmentry_interrupt_information interrupt{};
- interrupt.interruption_type = interruption_type::hardware_exception;
- interrupt.vector = EXCEPTION_GP_FAULT;
-
- interrupt.valid = true;
- interrupt.deliver_error_code = true;
-
- __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
- __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu.error_code);
+ exception::injection(interruption_type::hardware_exception,
+ EXCEPTION_GP_FAULT, { true, g_vcpu.error_code });
+ goto dont_advance;
}
- return; // dont advance rip...
}
case VMX_EXIT_REASON_EXECUTE_RDMSR:
{
@@ -127,21 +83,14 @@ auto exit_handler(hv::pguest_registers regs) -> void
regs->rdx = result.high;
regs->rax = result.low;
- break;
+ goto advance_rip;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- vmentry_interrupt_information interrupt{};
- interrupt.interruption_type = interruption_type::hardware_exception;
- interrupt.vector = EXCEPTION_GP_FAULT;
-
- interrupt.valid = true;
- interrupt.deliver_error_code = true;
-
- __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
- __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu.error_code);
+ exception::injection(interruption_type::hardware_exception,
+ EXCEPTION_GP_FAULT, { true, g_vcpu.error_code });
+ goto dont_advance;
}
- return; // dont advance rip...
}
case VMX_EXIT_REASON_EXECUTE_WRMSR:
{
@@ -158,28 +107,19 @@ auto exit_handler(hv::pguest_registers regs) -> void
#UD If the LOCK prefix is used.
*/
__writemsr(regs->rcx, value.value);
- break;
+ goto advance_rip;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- vmentry_interrupt_information interrupt{};
- interrupt.interruption_type = interruption_type::hardware_exception;
- interrupt.vector = EXCEPTION_GP_FAULT;
-
- interrupt.valid = true;
- interrupt.deliver_error_code = true;
-
- __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
- __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu.error_code);
+ exception::injection(interruption_type::hardware_exception,
+ EXCEPTION_GP_FAULT, { true, g_vcpu.error_code });
+ goto dont_advance;
}
- return; // dont advance rip...
}
case VMX_EXIT_REASON_EXECUTE_INVD:
{
- // couldnt find the intrin for this so i just made one...
- // probably could have used __wbinvd?
- __invd();
- break;
+ __wbinvd();
+ goto advance_rip;
}
case VMX_EXIT_REASON_EXECUTE_VMCALL:
{
@@ -188,82 +128,78 @@ auto exit_handler(hv::pguest_registers regs) -> void
cr3 dirbase;
__vmx_vmread(VMCS_GUEST_CR3, &dirbase.flags);
- auto command = get_command(
+ auto command = command::get(
dirbase.pml4_pfn << 12, regs->rdx);
- if (command.present)
+ if (!command.present)
{
- switch (command.option)
- {
- case vmcall_option::copy_virt:
- {
- command.result =
- mm::copy_virt(
- command.copy_virt.dirbase_src,
- command.copy_virt.virt_src,
- command.copy_virt.dirbase_dest,
- command.copy_virt.virt_dest,
- command.copy_virt.size);
- break;
- }
- case vmcall_option::translate:
- {
- command.translate.phys_addr =
- mm::translate(mm::virt_addr_t{
- command.translate.virt_addr },
- command.translate.dirbase);
-
- // true if address is not null...
- command.result = command.translate.phys_addr;
- break;
- }
- case vmcall_option::read_phys:
- {
- command.result =
- mm::read_phys(
- command.read_phys.dirbase_dest,
- command.read_phys.phys_src,
- command.read_phys.virt_dest,
- command.read_phys.size);
- break;
- }
- case vmcall_option::write_phys:
- {
- command.result =
- mm::write_phys(
- command.write_phys.dirbase_src,
- command.write_phys.phys_dest,
- command.write_phys.virt_src,
- command.write_phys.size);
- break;
- }
- case vmcall_option::dirbase:
- {
- command.result = true;
- command.dirbase = dirbase.pml4_pfn << 12;
- break;
- }
- default:
- // check to see why the option was invalid...
- __debugbreak();
- break;
- }
+ exception::injection(interruption_type::hardware_exception, EXCEPTION_INVALID_OPCODE);
+ goto dont_advance;
+ }
- set_command(dirbase.pml4_pfn << 12, regs->rdx, command);
+ switch (command.option)
+ {
+ case command::vmcall_option::copy_virt:
+ {
+ command.result =
+ mm::copy_virt(
+ command.copy_virt.dirbase_src,
+ command.copy_virt.virt_src,
+ command.copy_virt.dirbase_dest,
+ command.copy_virt.virt_dest,
+ command.copy_virt.size);
+ break;
}
+ case command::vmcall_option::translate:
+ {
+ command.translate.phys_addr =
+ mm::translate(mm::virt_addr_t{
+ command.translate.virt_addr },
+ command.translate.dirbase);
+
+ // true if address is not null...
+ command.result = command.translate.phys_addr;
+ break;
+ }
+ case command::vmcall_option::read_phys:
+ {
+ command.result =
+ mm::read_phys(
+ command.read_phys.dirbase_dest,
+ command.read_phys.phys_src,
+ command.read_phys.virt_dest,
+ command.read_phys.size);
+ break;
+ }
+ case command::vmcall_option::write_phys:
+ {
+ command.result =
+ mm::write_phys(
+ command.write_phys.dirbase_src,
+ command.write_phys.phys_dest,
+ command.write_phys.virt_src,
+ command.write_phys.size);
+ break;
+ }
+ case command::vmcall_option::dirbase:
+ {
+ command.result = true;
+ command.dirbase = dirbase.pml4_pfn << 12;
+ break;
+ }
+ default:
+ // check to see why the option was invalid...
+ __debugbreak();
+ }
+
+ command::set(dirbase.pml4_pfn << 12, regs->rdx, command);
+ goto advance_rip;
}
else
{
- vmentry_interrupt_information interrupt{};
- interrupt.interruption_type = interruption_type::hardware_exception;
- interrupt.vector = EXCEPTION_INVALID_OPCODE;
- interrupt.valid = true;
-
- __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
- __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, NULL);
- return; // dont advance rip...
+ exception::injection(interruption_type::hardware_exception, EXCEPTION_INVALID_OPCODE);
+ goto dont_advance;
}
- break;
}
case VMX_EXIT_REASON_EXECUTE_VMWRITE:
case VMX_EXIT_REASON_EXECUTE_VMREAD:
@@ -272,24 +208,27 @@ auto exit_handler(hv::pguest_registers regs) -> void
case VMX_EXIT_REASON_EXECUTE_VMCLEAR:
case VMX_EXIT_REASON_EXECUTE_VMXOFF:
case VMX_EXIT_REASON_EXECUTE_VMXON:
+ case VMX_EXIT_REASON_EXECUTE_VMFUNC:
{
- vmentry_interrupt_information interrupt{};
- interrupt.interruption_type = interruption_type::hardware_exception;
- interrupt.vector = EXCEPTION_INVALID_OPCODE;
- interrupt.valid = true;
-
- __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
- __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, NULL);
- return; // dont advance rip...
+ exception::injection(interruption_type::hardware_exception, EXCEPTION_INVALID_OPCODE);
+ goto dont_advance;
}
default:
// TODO: check out the vmexit reason and add support for it...
__debugbreak();
- break;
}
-
+
+advance_rip:
size_t rip, exec_len;
__vmx_vmread(VMCS_GUEST_RIP, &rip);
__vmx_vmread(VMCS_VMEXIT_INSTRUCTION_LENGTH, &exec_len);
__vmx_vmwrite(VMCS_GUEST_RIP, rip + exec_len);
+
+ // since we are advancing RIP, also check if TF = 1, if so, set pending #DB...
+ // otherwise this #DB will fire on the wrong instruction... please refer to:
+ // https://howtohypervise.blogspot.com/2019/01/a-common-missight-in-most-hypervisors.html
+ exception::handle_debug();
+
+dont_advance:
+ return;
}
\ No newline at end of file
diff --git a/ia32.hpp b/ia32.hpp
index e710e4c..2510e6c 100644
--- a/ia32.hpp
+++ b/ia32.hpp
@@ -16605,6 +16605,7 @@ typedef struct
*/
typedef union
{
+ uint64_t flags;
struct
{
/**
@@ -16644,8 +16645,6 @@ typedef union
#define VMX_EXIT_QUALIFICATION_DEBUG_EXCEPTION_SINGLE_INSTRUCTION(_) (((_) >> 14) & 0x01)
uint64_t reserved2 : 49;
};
-
- uint64_t flags;
} vmx_exit_qualification_debug_exception;
/**
diff --git a/invd.asm b/invd.asm
deleted file mode 100644
index 6075711..0000000
--- a/invd.asm
+++ /dev/null
@@ -1,6 +0,0 @@
-.code
-__invd proc
- invd
- ret
-__invd endp
-end
\ No newline at end of file
diff --git a/invd.hpp b/invd.hpp
deleted file mode 100644
index fd580a1..0000000
--- a/invd.hpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#pragma once
-extern "C" void __invd(void);
\ No newline at end of file
diff --git a/mm.cpp b/mm.cpp
index c91dfd3..a432f34 100644
--- a/mm.cpp
+++ b/mm.cpp
@@ -145,14 +145,8 @@ namespace mm
if (!mapped_src)
return false;
- __try
- {
- memcpy(mapped_dest, mapped_src, current_size);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return false;
- }
+ __try { memcpy(mapped_dest, mapped_src, current_size); }
+ __except (EXCEPTION_EXECUTE_HANDLER) { return false; }
guest_phys += current_size;
guest_virt += current_size;
@@ -196,14 +190,8 @@ namespace mm
if (!mapped_src)
return false;
- __try
- {
- memcpy(mapped_dest, mapped_src, current_size);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return false;
- }
+ __try { memcpy(mapped_dest, mapped_src, current_size); }
+ __except (EXCEPTION_EXECUTE_HANDLER){ return false; }
guest_phys += current_size;
guest_virt += current_size;
@@ -242,14 +230,8 @@ namespace mm
// copy directly between the two pages...
auto current_size = min(dest_size, src_size);
- __try
- {
- memcpy(mapped_dest, mapped_src, current_size);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return false;
- }
+ __try{ memcpy(mapped_dest, mapped_src, current_size); }
+ __except (EXCEPTION_EXECUTE_HANDLER){ return false; }
virt_src += current_size;
virt_dest += current_size;
diff --git a/vmcs.cpp b/vmcs.cpp
index fb59354..b9d1941 100644
--- a/vmcs.cpp
+++ b/vmcs.cpp
@@ -152,9 +152,7 @@ namespace vmcs
ia32_vmx_exit_ctls_register exit_ctls{};
ia32_vmx_basic_register vmx_basic{ __readmsr(IA32_VMX_BASIC) };
- pinbased_ctls.nmi_exiting = true;
pinbased_ctls.virtual_nmi = true;
-
procbased_ctls.activate_secondary_controls = true;
exit_ctls.host_address_space_size = true;
@@ -164,7 +162,6 @@ namespace vmcs
procbased_ctls2.enable_rdtscp = true;
procbased_ctls2.enable_xsaves = true;
procbased_ctls2.conceal_vmx_from_pt = true;
- //procbased_ctls2.enable_ept = true;
if (vmx_basic.vmx_controls)
{
@@ -211,13 +208,6 @@ namespace vmcs
__vmx_vmwrite(VMCS_CTRL_VMEXIT_CONTROLS, exit_ctls.flags);
}
- /*ept_pointer eptp{};
- eptp.memory_type = MEMORY_TYPE_WRITE_BACK;
- eptp.enable_access_and_dirty_flags = true;
- eptp.page_walk_length = EPT_PAGE_WALK_LENGTH_4;
- eptp.page_frame_number = reinterpret_cast(&mm::epml4) >> 12;
- __vmx_vmwrite(VMCS_CTRL_EPT_POINTER, eptp.flags);*/
-
msr_fix_value.flags = __readmsr(IA32_VMX_PROCBASED_CTLS2);
procbased_ctls2.flags &= msr_fix_value.allowed_1_settings;
procbased_ctls2.flags |= msr_fix_value.allowed_0_settings;
diff --git a/vmxexit_handler.asm b/vmxexit_handler.asm
index 1ab295e..d537844 100644
--- a/vmxexit_handler.asm
+++ b/vmxexit_handler.asm
@@ -101,6 +101,6 @@ vmxexit_handler proc
vmresume
call vmresume_failure
- hlt
+ int 3
vmxexit_handler endp
end
\ No newline at end of file
diff --git a/vmxexit_handler.h b/vmxexit_handler.h
index b404baa..aae3d5a 100644
--- a/vmxexit_handler.h
+++ b/vmxexit_handler.h
@@ -1,67 +1,11 @@
#pragma once
#include "hv_types.hpp"
#include "debug.hpp"
-#include "invd.hpp"
#include "mm.hpp"
#include "vmxon.hpp"
-
-enum class vmcall_option
-{
- translate,
- copy_virt,
- write_phys,
- read_phys,
- dirbase
-};
-
-typedef struct _vmcall_command_t
-{
- bool present;
- bool result;
- vmcall_option option;
-
- union
- {
- struct
- {
- u64 dirbase;
- u64 virt_addr;
- u64 phys_addr;
- } translate;
-
- struct
- {
- u64 virt_src;
- u64 dirbase_src;
- u64 virt_dest;
- u64 dirbase_dest;
- u64 size;
- } copy_virt;
-
- struct
- {
- u64 virt_src;
- u64 dirbase_src;
- u64 phys_dest;
- u64 size;
- } write_phys;
-
- struct
- {
- u64 phys_src;
- u64 dirbase_dest;
- u64 virt_dest;
- u64 size;
- } read_phys;
-
- u64 dirbase;
- };
-
-} vmcall_command_t, * pvmcall_command_t;
+#include "command.hpp"
+#include "exception.hpp"
extern "C" auto vmxexit_handler() -> void;
extern "C" auto vmresume_failure() -> void;
-extern "C" auto exit_handler(hv::pguest_registers regs) -> void;
-
-auto get_command(u64 dirbase, u64 command_ptr) -> vmcall_command_t;
-auto set_command(u64 dirbase, u64 command_ptr, const vmcall_command_t& vmcall_command) -> void;
\ No newline at end of file
+extern "C" auto exit_handler(hv::pguest_registers regs) -> void;
\ No newline at end of file