parent
d3f4b34dbe
commit
ebe2e90af9
@ -1,7 +1,7 @@
|
|||||||
_text segment
|
_text segment
|
||||||
hyperv proc
|
hypercall proc
|
||||||
cpuid
|
cpuid
|
||||||
ret
|
ret
|
||||||
hyperv endp
|
hypercall endp
|
||||||
_text ends
|
_text ends
|
||||||
end
|
end
|
@ -1,3 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#define VMEXIT_KEY 0xDEADBEEFDEADBEEF
|
#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