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;
|
||||
}
|
||||
}
|
@ -1,113 +1,167 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "ia32.hpp"
|
||||
|
||||
#pragma section(".pdpt", read, write)
|
||||
#pragma section(".pd", read, write)
|
||||
#pragma section(".pt", read, write)
|
||||
|
||||
typedef union _virt_addr_t
|
||||
namespace pg_table
|
||||
{
|
||||
void* value;
|
||||
struct
|
||||
typedef union _virt_addr_t
|
||||
{
|
||||
u64 offset : 12;
|
||||
u64 pt_index : 9;
|
||||
u64 pd_index : 9;
|
||||
u64 pdpt_index : 9;
|
||||
u64 pml4_index : 9;
|
||||
u64 reserved : 16;
|
||||
};
|
||||
} virt_addr_t, * pvirt_addr_t;
|
||||
void* value;
|
||||
struct
|
||||
{
|
||||
u64 offset : 12;
|
||||
u64 pt_index : 9;
|
||||
u64 pd_index : 9;
|
||||
u64 pdpt_index : 9;
|
||||
u64 pml4_index : 9;
|
||||
u64 reserved : 16;
|
||||
};
|
||||
} virt_addr_t, * pvirt_addr_t;
|
||||
|
||||
typedef union _pml4e
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pml4e
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 ReadWrite : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PDPT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // Must be 0 for PML4E.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PDPT of this PML4E.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pml4e, * ppml4e;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PDPT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // Must be 0 for PML4E.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PDPT of this PML4E.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pml4e, * ppml4e;
|
||||
|
||||
typedef union _pdpte
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pdpte
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PD.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PD.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 1GB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PD of this PDPTE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pdpte, * ppdpte;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PD.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PD.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 1GB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PD of this PDPTE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pdpte, * ppdpte;
|
||||
|
||||
typedef union _pde
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pde
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 2MB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PT of this PDE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pde, * ppde;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 2MB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PT of this PDE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pde, * ppde;
|
||||
|
||||
typedef union _pte
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pte
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
||||
u64 page_cache : 1; // Determines the memory type used to access the memory.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||
u64 PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||
u64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||
u64 Ignored2 : 3;
|
||||
u64 pfn : 36; // The page frame number of the backing physical page.
|
||||
u64 reserved : 4;
|
||||
u64 Ignored3 : 7;
|
||||
u64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pte, * ppte;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
||||
u64 page_cache : 1; // Determines the memory type used to access the memory.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||
u64 PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||
u64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||
u64 Ignored2 : 3;
|
||||
u64 pfn : 36; // The page frame number of the backing physical page.
|
||||
u64 reserved : 4;
|
||||
u64 Ignored3 : 7;
|
||||
u64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pte, * ppte;
|
||||
|
||||
namespace pg_table
|
||||
{
|
||||
__declspec(allocate(".pdpt")) inline pdpte pdpt[512];
|
||||
__declspec(allocate(".pd")) inline pde pd[512];
|
||||
__declspec(allocate(".pt")) inline pte pt[512];
|
||||
typedef struct _table_entries
|
||||
{
|
||||
pg_table::pml4e pml4e;
|
||||
pg_table::pdpte pdpte;
|
||||
pg_table::pde pde;
|
||||
pg_table::pte pte;
|
||||
} table_entries, *ptable_entries;
|
||||
|
||||
/// <summary>
|
||||
/// payload paging tables...
|
||||
/// </summary>
|
||||
__declspec(allocate(".pdpt")) inline pdpte pdpt[512];
|
||||
__declspec(allocate(".pd")) inline pde pd[512];
|
||||
__declspec(allocate(".pt")) inline pte pt[512];
|
||||
|
||||
/// <summary>
|
||||
/// self referencing pml4e is at 255...
|
||||
/// </summary>
|
||||
inline const ppml4e hyperv_pml4{ reinterpret_cast<ppml4e>(0x00007FBFDFEFF000) };
|
||||
|
||||
/// <summary>
|
||||
/// only does address translation for hyper-v's context
|
||||
/// </summary>
|
||||
/// <param name="virtual_address">virtual address to be translated...</param>
|
||||
/// <param name="entries">optional </param>
|
||||
/// <returns>returns a physical address...</returns>
|
||||
void* translate(void* virt_addr, const ptable_entries entries = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// translates linear virtual addresses to linear physical addresses...
|
||||
/// </summary>
|
||||
/// <param name="virtual_address">virtual address to translate...</param>
|
||||
/// <param name="pml4_pfn">page map level four page frame number...</param>
|
||||
/// <param name="entries">(optional) pointer to a table_entries structure...</param>
|
||||
/// <returns>linear physical address...</returns>
|
||||
void* translate(void* virtual_address, u32 pml4_pfn, const ptable_entries entries = nullptr);
|
||||
|
||||
/// <summary>
|
||||
// changes the cursor address to the specified physical address...
|
||||
// after doing so, the TLB entry for that address is going to be flushed...
|
||||
// a memory fence is applied to prevent out of order execution...
|
||||
/// </summary>
|
||||
/// <param name="phys_pfn">pfn of the physical page to change the cursor too...</param>
|
||||
void set_cursor_page(u32 phys_pfn);
|
||||
|
||||
/// <summary>
|
||||
/// get the cursor page... each core has its own cursor page...
|
||||
/// </summary>
|
||||
/// <returns>cursor page for the current core...</returns>
|
||||
void* get_cursor_page();
|
||||
|
||||
/// <summary>
|
||||
/// initalizes paging tables (connects pdpt->pd->pt)
|
||||
/// </summary>
|
||||
/// <returns>was the setup successful?</returns>
|
||||
bool init_pg_tables();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,113 +1,167 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "ia32.hpp"
|
||||
|
||||
#pragma section(".pdpt", read, write)
|
||||
#pragma section(".pd", read, write)
|
||||
#pragma section(".pt", read, write)
|
||||
|
||||
typedef union _virt_addr_t
|
||||
namespace pg_table
|
||||
{
|
||||
void* value;
|
||||
struct
|
||||
typedef union _virt_addr_t
|
||||
{
|
||||
u64 offset : 12;
|
||||
u64 pt_index : 9;
|
||||
u64 pd_index : 9;
|
||||
u64 pdpt_index : 9;
|
||||
u64 pml4_index : 9;
|
||||
u64 reserved : 16;
|
||||
};
|
||||
} virt_addr_t, * pvirt_addr_t;
|
||||
void* value;
|
||||
struct
|
||||
{
|
||||
u64 offset : 12;
|
||||
u64 pt_index : 9;
|
||||
u64 pd_index : 9;
|
||||
u64 pdpt_index : 9;
|
||||
u64 pml4_index : 9;
|
||||
u64 reserved : 16;
|
||||
};
|
||||
} virt_addr_t, * pvirt_addr_t;
|
||||
|
||||
typedef union _pml4e
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pml4e
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 ReadWrite : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PDPT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // Must be 0 for PML4E.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PDPT of this PML4E.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pml4e, * ppml4e;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PDPT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // Must be 0 for PML4E.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PDPT of this PML4E.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pml4e, * ppml4e;
|
||||
|
||||
typedef union _pdpte
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pdpte
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PD.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PD.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 1GB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PD of this PDPTE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pdpte, * ppdpte;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PD.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PD.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 1GB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PD of this PDPTE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pdpte, * ppdpte;
|
||||
|
||||
typedef union _pde
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pde
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 2MB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PT of this PDE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pde, * ppde;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||
u64 page_cache : 1; // Determines the memory type used to access PT.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Ignored1 : 1;
|
||||
u64 page_size : 1; // If 1, this entry maps a 2MB page.
|
||||
u64 Ignored2 : 4;
|
||||
u64 pfn : 36; // The page frame number of the PT of this PDE.
|
||||
u64 Reserved : 4;
|
||||
u64 Ignored3 : 11;
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pde, * ppde;
|
||||
|
||||
typedef union _pte
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
typedef union _pte
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
||||
u64 page_cache : 1; // Determines the memory type used to access the memory.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||
u64 PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||
u64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||
u64 Ignored2 : 3;
|
||||
u64 pfn : 36; // The page frame number of the backing physical page.
|
||||
u64 reserved : 4;
|
||||
u64 Ignored3 : 7;
|
||||
u64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pte, * ppte;
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u64 present : 1; // Must be 1, region invalid if 0.
|
||||
u64 rw : 1; // If 0, writes not allowed.
|
||||
u64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||
u64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
||||
u64 page_cache : 1; // Determines the memory type used to access the memory.
|
||||
u64 accessed : 1; // If 0, this entry has not been used for translation.
|
||||
u64 Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||
u64 PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||
u64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||
u64 Ignored2 : 3;
|
||||
u64 pfn : 36; // The page frame number of the backing physical page.
|
||||
u64 reserved : 4;
|
||||
u64 Ignored3 : 7;
|
||||
u64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||
u64 nx : 1; // If 1, instruction fetches not allowed.
|
||||
};
|
||||
} pte, * ppte;
|
||||
|
||||
namespace pg_table
|
||||
{
|
||||
__declspec(allocate(".pdpt")) inline pdpte pdpt[512];
|
||||
__declspec(allocate(".pd")) inline pde pd[512];
|
||||
__declspec(allocate(".pt")) inline pte pt[512];
|
||||
typedef struct _table_entries
|
||||
{
|
||||
pg_table::pml4e pml4e;
|
||||
pg_table::pdpte pdpte;
|
||||
pg_table::pde pde;
|
||||
pg_table::pte pte;
|
||||
} table_entries, *ptable_entries;
|
||||
|
||||
/// <summary>
|
||||
/// payload paging tables...
|
||||
/// </summary>
|
||||
__declspec(allocate(".pdpt")) inline pdpte pdpt[512];
|
||||
__declspec(allocate(".pd")) inline pde pd[512];
|
||||
__declspec(allocate(".pt")) inline pte pt[512];
|
||||
|
||||
/// <summary>
|
||||
/// self referencing pml4e is at 255...
|
||||
/// </summary>
|
||||
inline const ppml4e hyperv_pml4{ reinterpret_cast<ppml4e>(0x00007FBFDFEFF000) };
|
||||
|
||||
/// <summary>
|
||||
/// only does address translation for hyper-v's context
|
||||
/// </summary>
|
||||
/// <param name="virtual_address">virtual address to be translated...</param>
|
||||
/// <param name="entries">optional </param>
|
||||
/// <returns>returns a physical address...</returns>
|
||||
void* translate(void* virt_addr, const ptable_entries entries = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// translates linear virtual addresses to linear physical addresses...
|
||||
/// </summary>
|
||||
/// <param name="virtual_address">virtual address to translate...</param>
|
||||
/// <param name="pml4_pfn">page map level four page frame number...</param>
|
||||
/// <param name="entries">(optional) pointer to a table_entries structure...</param>
|
||||
/// <returns>linear physical address...</returns>
|
||||
void* translate(void* virtual_address, u32 pml4_pfn, const ptable_entries entries = nullptr);
|
||||
|
||||
/// <summary>
|
||||
// changes the cursor address to the specified physical address...
|
||||
// after doing so, the TLB entry for that address is going to be flushed...
|
||||
// a memory fence is applied to prevent out of order execution...
|
||||
/// </summary>
|
||||
/// <param name="phys_pfn">pfn of the physical page to change the cursor too...</param>
|
||||
void set_cursor_page(u32 phys_pfn);
|
||||
|
||||
/// <summary>
|
||||
/// get the cursor page... each core has its own cursor page...
|
||||
/// </summary>
|
||||
/// <returns>cursor page for the current core...</returns>
|
||||
void* get_cursor_page();
|
||||
|
||||
/// <summary>
|
||||
/// initalizes paging tables (connects pdpt->pd->pt)
|
||||
/// </summary>
|
||||
/// <returns>was the setup successful?</returns>
|
||||
bool init_pg_tables();
|
||||
}
|
@ -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