You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.5 KiB
138 lines
4.5 KiB
#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;
|
|
}
|
|
} |