parent
d3f4b34dbe
commit
ebe2e90af9
@ -1,7 +1,7 @@
|
||||
_text segment
|
||||
hyperv proc
|
||||
hypercall proc
|
||||
cpuid
|
||||
ret
|
||||
hyperv endp
|
||||
hypercall endp
|
||||
_text ends
|
||||
end
|
@ -1,3 +1,9 @@
|
||||
#pragma once
|
||||
#define VMEXIT_KEY 0xDEADBEEFDEADBEEF
|
||||
extern "C" size_t hyperv(size_t key);
|
||||
enum class vmexit_command_t
|
||||
{
|
||||
init_paging_tables = 0x111
|
||||
// add your commands here...
|
||||
};
|
||||
|
||||
extern "C" size_t hypercall(size_t key, vmexit_command_t command);
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,138 @@
|
||||
#include "pg_table.h"
|
||||
|
||||
namespace pg_table
|
||||
{
|
||||
void* translate(void* virtual_address, const ptable_entries entries)
|
||||
{
|
||||
virt_addr_t virt_addr{ virtual_address };
|
||||
virt_addr_t cursor{ hyperv_pml4 };
|
||||
|
||||
if (entries) entries->pml4e = reinterpret_cast<ppml4e>(cursor.value)[virt_addr.pml4_index];
|
||||
if (!reinterpret_cast<ppml4e>(cursor.value)[virt_addr.pml4_index].present)
|
||||
return nullptr;
|
||||
|
||||
// set the cursor to self reference so that when we read
|
||||
// the addresses pointed to by cursor its going to be a pdpt...
|
||||
cursor.pdpt_index = virt_addr_t{ hyperv_pml4 }.pml4_index;
|
||||
cursor.pd_index = virt_addr_t{ hyperv_pml4 }.pml4_index;
|
||||
cursor.pt_index = virt_addr.pml4_index;
|
||||
if (entries) entries->pdpte = reinterpret_cast<ppdpte>(cursor.value)[virt_addr.pdpt_index];
|
||||
|
||||
if (!reinterpret_cast<ppdpte>(cursor.value)[virt_addr.pdpt_index].present)
|
||||
return nullptr;
|
||||
|
||||
// set the cursor to self reference so that when we read
|
||||
// the addresses pointed to by cursor its going to be a pd...
|
||||
cursor.pdpt_index = virt_addr_t{ hyperv_pml4 }.pml4_index;
|
||||
cursor.pd_index = virt_addr.pml4_index;
|
||||
cursor.pt_index = virt_addr.pdpt_index;
|
||||
if (entries) entries->pde = reinterpret_cast<ppde>(cursor.value)[virt_addr.pd_index];
|
||||
|
||||
if (!reinterpret_cast<ppde>(cursor.value)[virt_addr.pd_index].present)
|
||||
return nullptr;
|
||||
|
||||
// set the cursor to self reference so that when we read
|
||||
// the addresses pointed to by cursor its going to be a pt...
|
||||
cursor.pdpt_index = virt_addr.pml4_index;
|
||||
cursor.pd_index = virt_addr.pdpt_index;
|
||||
cursor.pt_index = virt_addr.pd_index;
|
||||
if (entries) entries->pte = reinterpret_cast<ppte>(cursor.value)[virt_addr.pt_index];
|
||||
|
||||
if (!reinterpret_cast<ppte>(cursor.value)[virt_addr.pt_index].present)
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<void*>(
|
||||
reinterpret_cast<ppte>(cursor.value)[virt_addr.pt_index].pfn << 12);
|
||||
}
|
||||
|
||||
void* translate(void* virtual_address, u32 pml4_pfn, const ptable_entries entries)
|
||||
{
|
||||
virt_addr_t virt_addr{ virtual_address };
|
||||
const auto cursor = get_cursor_page();
|
||||
|
||||
set_cursor_page(pml4_pfn);
|
||||
if (!reinterpret_cast<ppml4e>(cursor)[virt_addr.pml4_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pml4e = reinterpret_cast<ppml4e>(cursor)[virt_addr.pml4_index];
|
||||
set_cursor_page(reinterpret_cast<ppml4e>(cursor)[virt_addr.pml4_index].pfn);
|
||||
if (!reinterpret_cast<ppdpte>(cursor)[virt_addr.pdpt_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pdpte = reinterpret_cast<ppdpte>(cursor)[virt_addr.pdpt_index];
|
||||
set_cursor_page(reinterpret_cast<ppdpte>(cursor)[virt_addr.pdpt_index].pfn);
|
||||
if (!reinterpret_cast<ppde>(cursor)[virt_addr.pd_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pde = reinterpret_cast<ppde>(cursor)[virt_addr.pd_index];
|
||||
set_cursor_page(reinterpret_cast<ppde>(cursor)[virt_addr.pd_index].pfn);
|
||||
if (!reinterpret_cast<ppte>(cursor)[virt_addr.pt_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pte = reinterpret_cast<ppte>(cursor)[virt_addr.pt_index];
|
||||
return reinterpret_cast<void*>(
|
||||
reinterpret_cast<ppte>(cursor)[virt_addr.pt_index].pfn << 12);
|
||||
}
|
||||
|
||||
void set_cursor_page(u32 phys_pfn)
|
||||
{
|
||||
cpuid_eax_01 cpuid_value;
|
||||
__cpuid((int*)&cpuid_value, 1);
|
||||
pg_table::pt[cpuid_value
|
||||
.cpuid_additional_information
|
||||
.initial_apic_id].pfn = phys_pfn;
|
||||
|
||||
// flush tlb for this page and then ensure the instruction stream
|
||||
// is seralized as to not execute instructions out of order and access the page
|
||||
// before the TLB is flushed...
|
||||
__invlpg(get_cursor_page());
|
||||
_mm_lfence();
|
||||
}
|
||||
|
||||
void* get_cursor_page()
|
||||
{
|
||||
cpuid_eax_01 cpuid_value;
|
||||
__cpuid((int*)&cpuid_value, 1);
|
||||
constexpr auto cursor_page = 0x00007F7FFFE00000;
|
||||
|
||||
virt_addr_t virt_addr{ reinterpret_cast<void*>(cursor_page) };
|
||||
virt_addr.pt_index = cpuid_value
|
||||
.cpuid_additional_information
|
||||
.initial_apic_id;
|
||||
|
||||
return virt_addr.value;
|
||||
}
|
||||
|
||||
bool init_pg_tables()
|
||||
{
|
||||
auto pdpt_phys = reinterpret_cast<u64>(translate(pdpt));
|
||||
auto pd_phys = reinterpret_cast<u64>(translate(pd));
|
||||
auto pt_phys = reinterpret_cast<u64>(translate(pt));
|
||||
|
||||
if (!pdpt_phys || !pd_phys || !pt_phys)
|
||||
return false;
|
||||
|
||||
hyperv_pml4[254].present = true;
|
||||
hyperv_pml4[254].pfn = pdpt_phys >> 12;
|
||||
hyperv_pml4[254].user_supervisor = false;
|
||||
hyperv_pml4[254].rw = true;
|
||||
|
||||
pdpt[511].present = true;
|
||||
pdpt[511].pfn = pd_phys >> 12;
|
||||
pdpt[511].user_supervisor = false;
|
||||
pdpt[511].rw = true;
|
||||
|
||||
pd[511].present = true;
|
||||
pd[511].pfn = pt_phys >> 12;
|
||||
pd[511].user_supervisor = false;
|
||||
pd[511].rw = true;
|
||||
|
||||
for (auto idx = 0u; idx < 512; ++idx)
|
||||
{
|
||||
pt[idx].present = true;
|
||||
pt[idx].user_supervisor = false;
|
||||
pt[idx].rw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
#include "pg_table.h"
|
||||
|
||||
namespace pg_table
|
||||
{
|
||||
void* translate(void* virtual_address, const ptable_entries entries)
|
||||
{
|
||||
virt_addr_t virt_addr{ virtual_address };
|
||||
virt_addr_t cursor{ hyperv_pml4 };
|
||||
|
||||
if (entries) entries->pml4e = reinterpret_cast<ppml4e>(cursor.value)[virt_addr.pml4_index];
|
||||
if (!reinterpret_cast<ppml4e>(cursor.value)[virt_addr.pml4_index].present)
|
||||
return nullptr;
|
||||
|
||||
// set the cursor to self reference so that when we read
|
||||
// the addresses pointed to by cursor its going to be a pdpt...
|
||||
cursor.pdpt_index = virt_addr_t{ hyperv_pml4 }.pml4_index;
|
||||
cursor.pd_index = virt_addr_t{ hyperv_pml4 }.pml4_index;
|
||||
cursor.pt_index = virt_addr.pml4_index;
|
||||
if (entries) entries->pdpte = reinterpret_cast<ppdpte>(cursor.value)[virt_addr.pdpt_index];
|
||||
|
||||
if (!reinterpret_cast<ppdpte>(cursor.value)[virt_addr.pdpt_index].present)
|
||||
return nullptr;
|
||||
|
||||
// set the cursor to self reference so that when we read
|
||||
// the addresses pointed to by cursor its going to be a pd...
|
||||
cursor.pdpt_index = virt_addr_t{ hyperv_pml4 }.pml4_index;
|
||||
cursor.pd_index = virt_addr.pml4_index;
|
||||
cursor.pt_index = virt_addr.pdpt_index;
|
||||
if (entries) entries->pde = reinterpret_cast<ppde>(cursor.value)[virt_addr.pd_index];
|
||||
|
||||
if (!reinterpret_cast<ppde>(cursor.value)[virt_addr.pd_index].present)
|
||||
return nullptr;
|
||||
|
||||
// set the cursor to self reference so that when we read
|
||||
// the addresses pointed to by cursor its going to be a pt...
|
||||
cursor.pdpt_index = virt_addr.pml4_index;
|
||||
cursor.pd_index = virt_addr.pdpt_index;
|
||||
cursor.pt_index = virt_addr.pd_index;
|
||||
if (entries) entries->pte = reinterpret_cast<ppte>(cursor.value)[virt_addr.pt_index];
|
||||
|
||||
if (!reinterpret_cast<ppte>(cursor.value)[virt_addr.pt_index].present)
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<void*>(
|
||||
reinterpret_cast<ppte>(cursor.value)[virt_addr.pt_index].pfn << 12);
|
||||
}
|
||||
|
||||
void* translate(void* virtual_address, u32 pml4_pfn, const ptable_entries entries)
|
||||
{
|
||||
virt_addr_t virt_addr{ virtual_address };
|
||||
const auto cursor = get_cursor_page();
|
||||
|
||||
set_cursor_page(pml4_pfn);
|
||||
if (!reinterpret_cast<ppml4e>(cursor)[virt_addr.pml4_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pml4e = reinterpret_cast<ppml4e>(cursor)[virt_addr.pml4_index];
|
||||
set_cursor_page(reinterpret_cast<ppml4e>(cursor)[virt_addr.pml4_index].pfn);
|
||||
if (!reinterpret_cast<ppdpte>(cursor)[virt_addr.pdpt_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pdpte = reinterpret_cast<ppdpte>(cursor)[virt_addr.pdpt_index];
|
||||
set_cursor_page(reinterpret_cast<ppdpte>(cursor)[virt_addr.pdpt_index].pfn);
|
||||
if (!reinterpret_cast<ppde>(cursor)[virt_addr.pd_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pde = reinterpret_cast<ppde>(cursor)[virt_addr.pd_index];
|
||||
set_cursor_page(reinterpret_cast<ppde>(cursor)[virt_addr.pd_index].pfn);
|
||||
if (!reinterpret_cast<ppte>(cursor)[virt_addr.pt_index].present)
|
||||
return nullptr;
|
||||
|
||||
if (entries) entries->pte = reinterpret_cast<ppte>(cursor)[virt_addr.pt_index];
|
||||
return reinterpret_cast<void*>(
|
||||
reinterpret_cast<ppte>(cursor)[virt_addr.pt_index].pfn << 12);
|
||||
}
|
||||
|
||||
void set_cursor_page(u32 phys_pfn)
|
||||
{
|
||||
cpuid_eax_01 cpuid_value;
|
||||
__cpuid((int*)&cpuid_value, 1);
|
||||
pg_table::pt[cpuid_value
|
||||
.cpuid_additional_information
|
||||
.initial_apic_id].pfn = phys_pfn;
|
||||
|
||||
// flush tlb for this page and then ensure the instruction stream
|
||||
// is seralized as to not execute instructions out of order and access the page
|
||||
// before the TLB is flushed...
|
||||
__invlpg(get_cursor_page());
|
||||
_mm_lfence();
|
||||
}
|
||||
|
||||
void* get_cursor_page()
|
||||
{
|
||||
cpuid_eax_01 cpuid_value;
|
||||
__cpuid((int*)&cpuid_value, 1);
|
||||
constexpr auto cursor_page = 0x00007F7FFFE00000;
|
||||
|
||||
virt_addr_t virt_addr{ reinterpret_cast<void*>(cursor_page) };
|
||||
virt_addr.pt_index = cpuid_value
|
||||
.cpuid_additional_information
|
||||
.initial_apic_id;
|
||||
|
||||
return virt_addr.value;
|
||||
}
|
||||
|
||||
bool init_pg_tables()
|
||||
{
|
||||
auto pdpt_phys = reinterpret_cast<u64>(translate(pdpt));
|
||||
auto pd_phys = reinterpret_cast<u64>(translate(pd));
|
||||
auto pt_phys = reinterpret_cast<u64>(translate(pt));
|
||||
|
||||
if (!pdpt_phys || !pd_phys || !pt_phys)
|
||||
return false;
|
||||
|
||||
hyperv_pml4[254].present = true;
|
||||
hyperv_pml4[254].pfn = pdpt_phys >> 12;
|
||||
hyperv_pml4[254].user_supervisor = false;
|
||||
hyperv_pml4[254].rw = true;
|
||||
|
||||
pdpt[511].present = true;
|
||||
pdpt[511].pfn = pd_phys >> 12;
|
||||
pdpt[511].user_supervisor = false;
|
||||
pdpt[511].rw = true;
|
||||
|
||||
pd[511].present = true;
|
||||
pd[511].pfn = pt_phys >> 12;
|
||||
pd[511].user_supervisor = false;
|
||||
pd[511].rw = true;
|
||||
|
||||
for (auto idx = 0u; idx < 512; ++idx)
|
||||
{
|
||||
pt[idx].present = true;
|
||||
pt[idx].user_supervisor = false;
|
||||
pt[idx].rw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
#include "Utils.h"
|
||||
|
||||
#define MAP_PHYSICAL_SIG "\xE8\x00\x00\x00\x00\x85\xC0\x0F\x88\x00\x00\x00\x00\x48\x8B\xBC\x24"
|
||||
#define MAP_PHYSICAL_MASK "x????xxxx????xxxx"
|
||||
static_assert(sizeof(MAP_PHYSICAL_SIG) == sizeof(MAP_PHYSICAL_MASK), "signature and mask do not patch sizes...\n");
|
||||
|
||||
typedef EFI_STATUS(EFIAPI* MAP_PHYSICAL)
|
||||
(
|
||||
VOID** VirtualAddress,
|
||||
VOID* PhysicalAddress,
|
||||
UINTN Size,
|
||||
VOID* Unknown,
|
||||
VOID* Unknown2
|
||||
);
|
||||
extern MAP_PHYSICAL MmMapPhysicalMemory;
|
||||
|
||||
typedef union _CR3
|
||||
{
|
||||
UINTN Value;
|
||||
struct
|
||||
{
|
||||
UINTN reserved1 : 3;
|
||||
UINTN PageLevelWriteThrough : 1;
|
||||
UINTN PageLevelCacheDisable : 1;
|
||||
UINTN reserved2 : 7;
|
||||
UINTN Pml4Pfn : 36;
|
||||
UINTN reserved3 : 16;
|
||||
};
|
||||
} CR3;
|
||||
|
||||
typedef union _VIRT_ADDR_T
|
||||
{
|
||||
void* Value;
|
||||
struct
|
||||
{
|
||||
UINT64 offset : 12;
|
||||
UINT64 PtIdx : 9;
|
||||
UINT64 PdIdx : 9;
|
||||
UINT64 PdptIdx : 9;
|
||||
UINT64 Pml4Idx : 9;
|
||||
UINT64 reserved : 16;
|
||||
};
|
||||
} VIRT_ADDR_T, *PVIRT_ADDR_T;
|
||||
|
||||
|
||||
typedef union _PML4E_T
|
||||
{
|
||||
UINT64 Value;
|
||||
struct
|
||||
{
|
||||
UINT64 Present : 1; // Must be 1, region invalid if 0.
|
||||
UINT64 ReadWrite : 1; // If 0, writes not allowed.
|
||||
UINT64 UserSuperVisor : 1; // If 0, user-mode accesses not allowed.
|
||||
UINT64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
||||
UINT64 page_cache : 1; // Determines the memory type used to access PDPT.
|
||||
UINT64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
UINT64 Ignored1 : 1;
|
||||
UINT64 LargePage : 1; // Must be 0 for PML4E.
|
||||
UINT64 Ignored2 : 4;
|
||||
UINT64 Pfn : 36; // The page frame number of the PDPT of this PML4E.
|
||||
UINT64 Reserved : 4;
|
||||
UINT64 Ignored3 : 11;
|
||||
UINT64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} PML4E_T, * PPML4E_T;
|
||||
|
||||
typedef union _PDPTE
|
||||
{
|
||||
UINT64 Value;
|
||||
struct
|
||||
{
|
||||
UINT64 Present : 1; // Must be 1, region invalid if 0.
|
||||
UINT64 ReadWrite : 1; // If 0, writes not allowed.
|
||||
UINT64 UserSuperVisor : 1; // If 0, user-mode accesses not allowed.
|
||||
UINT64 PageWriteThrough : 1; // Determines the memory type used to access PD.
|
||||
UINT64 page_cache : 1; // Determines the memory type used to access PD.
|
||||
UINT64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
UINT64 Ignored1 : 1;
|
||||
UINT64 LargePage : 1; // If 1, this entry maps a 1GB page.
|
||||
UINT64 Ignored2 : 4;
|
||||
UINT64 Pfn : 36; // The page frame number of the PD of this PDPTE.
|
||||
UINT64 Reserved : 4;
|
||||
UINT64 Ignored3 : 11;
|
||||
UINT64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} PDPTE_T, * PPDPTE_T;
|
||||
|
||||
typedef union _PDE
|
||||
{
|
||||
UINT64 Value;
|
||||
struct
|
||||
{
|
||||
UINT64 Present : 1; // Must be 1, region invalid if 0.
|
||||
UINT64 ReadWrite : 1; // If 0, writes not allowed.
|
||||
UINT64 UserSuperVisor : 1; // If 0, user-mode accesses not allowed.
|
||||
UINT64 PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||
UINT64 page_cache : 1; // Determines the memory type used to access PT.
|
||||
UINT64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
UINT64 Ignored1 : 1;
|
||||
UINT64 LargePage : 1; // If 1, this entry maps a 2MB page.
|
||||
UINT64 Ignored2 : 4;
|
||||
UINT64 Pfn : 36; // The page frame number of the PT of this PDE.
|
||||
UINT64 Reserved : 4;
|
||||
UINT64 Ignored3 : 11;
|
||||
UINT64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} PDE_T, * PPDE_T;
|
||||
|
||||
typedef union _PTE
|
||||
{
|
||||
UINT64 Value;
|
||||
struct
|
||||
{
|
||||
UINT64 Present : 1; // Must be 1, region invalid if 0.
|
||||
UINT64 ReadWrite : 1; // If 0, writes not allowed.
|
||||
UINT64 UserSuperVisor : 1; // If 0, user-mode accesses not allowed.
|
||||
UINT64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
||||
UINT64 page_cache : 1; // Determines the memory type used to access the memory.
|
||||
UINT64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
UINT64 Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||
UINT64 PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||
UINT64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||
UINT64 Ignored2 : 3;
|
||||
UINT64 Pfn : 36; // The page frame number of the backing physical page.
|
||||
UINT64 reserved : 4;
|
||||
UINT64 Ignored3 : 7;
|
||||
UINT64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||
UINT64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} PTE_T, *PPTE_T;
|
||||
|
||||
typedef struct _TABLE_ENTRIES
|
||||
{
|
||||
PML4E_T Pml4Entry;
|
||||
PDPTE_T PdptEntry;
|
||||
PDE_T PdEntry;
|
||||
PTE_T PtEntry;
|
||||
} TABLE_ENTRIES, *PTABLE_ENTRIES;
|
Loading…
Reference in new issue