#pragma once #include #include #define VMEXIT_KEY 0xDEADBEEFDEADBEEF #define PAGE_4KB 0x1000 #define PAGE_2MB PAGE_4KB * 512 #define PAGE_1GB PAGE_2MB * 512 using u8 = unsigned char; using u16 = unsigned short; using u32 = unsigned int; using u64 = unsigned long long; namespace voyager { // code comments itself... using guest_virt_t = u64; using guest_phys_t = u64; using host_virt_t = u64; using host_phys_t = u64; enum class vmexit_command_t { init_page_tables, read_guest_phys, write_guest_phys, copy_guest_virt, get_dirbase, translate }; enum class vmxroot_error_t { error_success, pml4e_not_present, pdpte_not_present, pde_not_present, pte_not_present, vmxroot_translate_failure, invalid_self_ref_pml4e, invalid_mapping_pml4e, invalid_host_virtual, invalid_guest_physical, invalid_guest_virtual, page_table_init_failed }; typedef union _command_t { struct _copy_phys { host_phys_t phys_addr; guest_virt_t buffer; u64 size; } copy_phys; struct _copy_virt { guest_phys_t dirbase_src; guest_virt_t virt_src; guest_phys_t dirbase_dest; guest_virt_t virt_dest; u64 size; } copy_virt; struct _translate_virt { guest_virt_t virt_src; guest_phys_t phys_addr; } translate_virt; guest_phys_t dirbase; } command_t, * pcommand_t; /// /// this function is used to cause a vmexit as though its calling a function... /// extern "C" auto hypercall(u64 key, vmexit_command_t, pcommand_t command)->vmxroot_error_t; /// /// gets the current cores CR3 value (current address space pml4)... /// /// returns the guest cr3 value... auto current_dirbase()->guest_phys_t; /// /// initalizies page tables for all cores... /// /// status of the initalization... auto init()->vmxroot_error_t; /// /// translate a linear virtual address of the current address space /// to a linear physical address... /// /// virtual address in the vmexiting core's address space... /// guest physical address... auto translate(guest_virt_t virt_addr)->guest_phys_t; /// /// reads guest physical memory... /// /// physical address to read... /// buffer (guest virtual address) to read into... /// number of bytes to read (can only be 0x1000 or less)... /// STATUS_SUCCESS if the read was successful... auto read_phys(guest_phys_t phys_addr, guest_virt_t buffer, u64 size)->vmxroot_error_t; /// /// write guest physical memory... /// /// physical address to read /// guest virtual address to write from... /// number of bytes to write /// auto write_phys(guest_phys_t phys_addr, guest_virt_t buffer, u64 size)->vmxroot_error_t; /// /// copy guest virtual memory between virtual address spaces... /// /// dirbase of the source address space /// virtual address in the source address space /// dirbase of the destination address space /// virtual address of the destination address /// size to copy between address spaces /// returns error_success on successful copy and invalid_guest_virt when an address is invalid... auto copy_virt(guest_phys_t dirbase_src, guest_virt_t virt_src, guest_phys_t dirbase_dest, guest_virt_t virt_dest, u64 size)->vmxroot_error_t; template auto rpm(guest_phys_t dirbase, guest_virt_t virt_addr) -> T { T buffer; auto result = copy_virt(dirbase, virt_addr, current_dirbase(), (guest_virt_t)&buffer, sizeof T); if (result != vmxroot_error_t::error_success) return {}; return buffer; } template auto wpm(guest_phys_t dirbase, guest_virt_t virt_addr, const T& data) -> void { copy_virt(current_dirbase(), (guest_virt_t)&data, dirbase, virt_addr, sizeof T); } }