kernel/x86_64: LA57 aka 5-level paging

this enables the kernel to correctly take over when the bootloader prepares
the paging in 4-level or 5-level.

Change-Id: I0444486d8e17aade574e2afe255a3c2cfc49f21f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3551
Reviewed-by: Adrien Destugues <[email protected]>
Reviewed-by: Axel Dörfler <[email protected]>
This commit is contained in:
Jérôme Duval
2020-12-28 18:21:11 +00:00
parent cb8472235b
commit 58353b3809
8 changed files with 144 additions and 71 deletions
@@ -84,7 +84,11 @@ arch_vm_translation_map_init(kernel_args *args,
#endif
#ifdef __x86_64__
gX86PagingMethod = new(&sPagingMethodBuffer) X86PagingMethod64Bit;
bool la57Available = x86_check_feature(IA32_FEATURE_LA57, FEATURE_7_ECX);
bool enabled = la57Available && (x86_read_cr4() & IA32_CR4_LA57) != 0;
if (enabled)
dprintf("using LA57 paging\n");
gX86PagingMethod = new(&sPagingMethodBuffer) X86PagingMethod64Bit(enabled);
#elif B_HAIKU_PHYSICAL_BITS == 64
bool paeAvailable = x86_check_feature(IA32_FEATURE_PAE, FEATURE_COMMON);
bool paeNeeded = x86_check_feature(IA32_FEATURE_AMD_EXT_NX,
@@ -34,16 +34,20 @@
#endif
bool X86PagingMethod64Bit::la57 = false;
// #pragma mark - X86PagingMethod64Bit
X86PagingMethod64Bit::X86PagingMethod64Bit()
X86PagingMethod64Bit::X86PagingMethod64Bit(bool la57)
:
fKernelPhysicalPML4(0),
fKernelVirtualPML4(NULL),
fKernelPhysicalPMLTop(0),
fKernelVirtualPMLTop(NULL),
fPhysicalPageMapper(NULL),
fKernelPhysicalPageMapper(NULL)
{
X86PagingMethod64Bit::la57 = la57;
}
@@ -56,8 +60,8 @@ status_t
X86PagingMethod64Bit::Init(kernel_args* args,
VMPhysicalPageMapper** _physicalPageMapper)
{
fKernelPhysicalPML4 = args->arch_args.phys_pgdir;
fKernelVirtualPML4 = (uint64*)(addr_t)args->arch_args.vir_pgdir;
fKernelPhysicalPMLTop = args->arch_args.phys_pgdir;
fKernelVirtualPMLTop = (uint64*)(addr_t)args->arch_args.vir_pgdir;
// if available enable NX-bit (No eXecute)
if (x86_check_feature(IA32_FEATURE_AMD_EXT_NX, FEATURE_EXT_AMD))
@@ -65,7 +69,7 @@ X86PagingMethod64Bit::Init(kernel_args* args,
// Ensure that the user half of the address space is clear. This removes
// the temporary identity mapping made by the boot loader.
memset(fKernelVirtualPML4, 0, sizeof(uint64) * 256);
memset(fKernelVirtualPMLTop, 0, sizeof(uint64) * 256);
arch_cpu_global_TLB_invalidate();
// Create the physical page mapper.
@@ -88,8 +92,8 @@ X86PagingMethod64Bit::InitPostArea(kernel_args* args)
if (area < B_OK)
return area;
// Create an area to represent the kernel PML4.
area = create_area("kernel pml4", (void**)&fKernelVirtualPML4,
// Create an area to represent the kernel PMLTop.
area = create_area("kernel pmltop", (void**)&fKernelVirtualPMLTop,
B_EXACT_ADDRESS, B_PAGE_SIZE, B_ALREADY_WIRED,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (area < B_OK)
@@ -102,7 +106,7 @@ X86PagingMethod64Bit::InitPostArea(kernel_args* args)
status_t
X86PagingMethod64Bit::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
{
X86VMTranslationMap64Bit* map = new(std::nothrow) X86VMTranslationMap64Bit;
X86VMTranslationMap64Bit* map = new(std::nothrow) X86VMTranslationMap64Bit(la57);
if (map == NULL)
return B_NO_MEMORY;
@@ -125,8 +129,17 @@ X86PagingMethod64Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
TRACE("X86PagingMethod64Bit::MapEarly(%#" B_PRIxADDR ", %#" B_PRIxPHYSADDR
", %#" B_PRIx8 ")\n", virtualAddress, physicalAddress, attributes);
uint64* virtualPML4 = fKernelVirtualPMLTop;
if (la57) {
// Get the PML4. We should be mapping on an existing PML4 at this stage.
uint64* pml5e = &fKernelVirtualPMLTop[VADDR_TO_PML5E(virtualAddress)];
ASSERT((*pml5e & X86_64_PML5E_PRESENT) != 0);
virtualPML4 = (uint64*)fKernelPhysicalPageMapper->GetPageTableAt(
*pml5e & X86_64_PML5E_ADDRESS_MASK);
}
// Get the PDPT. We should be mapping on an existing PDPT at this stage.
uint64* pml4e = &fKernelVirtualPML4[VADDR_TO_PML4E(virtualAddress)];
uint64* pml4e = &virtualPML4[VADDR_TO_PML4E(virtualAddress)];
ASSERT((*pml4e & X86_64_PML4E_PRESENT) != 0);
uint64* virtualPDPT = (uint64*)fKernelPhysicalPageMapper->GetPageTableAt(
*pml4e & X86_64_PML4E_ADDRESS_MASK);
@@ -206,11 +219,44 @@ X86PagingMethod64Bit::IsKernelPageAccessible(addr_t virtualAddress,
for a virtual address, allocating new tables if required.
*/
/*static*/ uint64*
X86PagingMethod64Bit::PageDirectoryForAddress(uint64* virtualPML4,
X86PagingMethod64Bit::PageDirectoryForAddress(uint64* virtualPMLTop,
addr_t virtualAddress, bool isKernel, bool allocateTables,
vm_page_reservation* reservation,
TranslationMapPhysicalPageMapper* pageMapper, int32& mapCount)
{
uint64* virtualPML4 = virtualPMLTop;
if (la57) {
// Get the PDPT.
uint64* pml5e = &virtualPMLTop[VADDR_TO_PML5E(virtualAddress)];
if ((*pml5e & X86_64_PML5E_PRESENT) == 0) {
if (!allocateTables)
return NULL;
// Allocate a new PDPT.
vm_page* page = vm_page_allocate_page(reservation,
PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
DEBUG_PAGE_ACCESS_END(page);
phys_addr_t physicalPDPT
= (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
TRACE("X86PagingMethod64Bit::PageTableForAddress(): creating PML4T"
" for va %#" B_PRIxADDR " at %#" B_PRIxPHYSADDR "\n",
virtualAddress, physicalPDPT);
SetTableEntry(pml5e, (physicalPDPT & X86_64_PML5E_ADDRESS_MASK)
| X86_64_PML5E_PRESENT
| X86_64_PML5E_WRITABLE
| X86_64_PML5E_USER);
mapCount++;
}
virtualPML4 = (uint64*)pageMapper->GetPageTableAt(
*pml5e & X86_64_PML5E_ADDRESS_MASK);
}
// Get the PDPT.
uint64* pml4e = &virtualPML4[VADDR_TO_PML4E(virtualAddress)];
if ((*pml4e & X86_64_PML4E_PRESENT) == 0) {
@@ -274,12 +320,12 @@ X86PagingMethod64Bit::PageDirectoryForAddress(uint64* virtualPML4,
/*static*/ uint64*
X86PagingMethod64Bit::PageDirectoryEntryForAddress(uint64* virtualPML4,
X86PagingMethod64Bit::PageDirectoryEntryForAddress(uint64* virtualPMLTop,
addr_t virtualAddress, bool isKernel, bool allocateTables,
vm_page_reservation* reservation,
TranslationMapPhysicalPageMapper* pageMapper, int32& mapCount)
{
uint64* virtualPageDirectory = PageDirectoryForAddress(virtualPML4,
uint64* virtualPageDirectory = PageDirectoryForAddress(virtualPMLTop,
virtualAddress, isKernel, allocateTables, reservation, pageMapper,
mapCount);
if (virtualPageDirectory == NULL)
@@ -293,7 +339,7 @@ X86PagingMethod64Bit::PageDirectoryEntryForAddress(uint64* virtualPML4,
virtual address, allocating new tables if required.
*/
/*static*/ uint64*
X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPMLTop,
addr_t virtualAddress, bool isKernel, bool allocateTables,
vm_page_reservation* reservation,
TranslationMapPhysicalPageMapper* pageMapper, int32& mapCount)
@@ -301,7 +347,7 @@ X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
TRACE("X86PagingMethod64Bit::PageTableForAddress(%#" B_PRIxADDR ", "
"%d)\n", virtualAddress, allocateTables);
uint64* pde = PageDirectoryEntryForAddress(virtualPML4, virtualAddress,
uint64* pde = PageDirectoryEntryForAddress(virtualPMLTop, virtualAddress,
isKernel, allocateTables, reservation, pageMapper, mapCount);
if (pde == NULL)
return NULL;
@@ -341,12 +387,12 @@ X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
/*static*/ uint64*
X86PagingMethod64Bit::PageTableEntryForAddress(uint64* virtualPML4,
X86PagingMethod64Bit::PageTableEntryForAddress(uint64* virtualPMLTop,
addr_t virtualAddress, bool isKernel, bool allocateTables,
vm_page_reservation* reservation,
TranslationMapPhysicalPageMapper* pageMapper, int32& mapCount)
{
uint64* virtualPageTable = PageTableForAddress(virtualPML4, virtualAddress,
uint64* virtualPageTable = PageTableForAddress(virtualPMLTop, virtualAddress,
isKernel, allocateTables, reservation, pageMapper, mapCount);
if (virtualPageTable == NULL)
return NULL;
@@ -27,7 +27,7 @@ struct vm_page_reservation;
class X86PagingMethod64Bit final : public X86PagingMethod {
public:
X86PagingMethod64Bit();
X86PagingMethod64Bit(bool la57);
virtual ~X86PagingMethod64Bit();
virtual status_t Init(kernel_args* args,
@@ -51,10 +51,10 @@ public:
inline TranslationMapPhysicalPageMapper* KernelPhysicalPageMapper() const
{ return fKernelPhysicalPageMapper; }
inline uint64* KernelVirtualPML4() const
{ return fKernelVirtualPML4; }
inline phys_addr_t KernelPhysicalPML4() const
{ return fKernelPhysicalPML4; }
inline uint64* KernelVirtualPMLTop() const
{ return fKernelVirtualPMLTop; }
inline phys_addr_t KernelPhysicalPMLTop() const
{ return fKernelPhysicalPMLTop; }
static X86PagingMethod64Bit* Method();
@@ -103,11 +103,13 @@ public:
private:
static void _EnableExecutionDisable(void* dummy, int cpu);
phys_addr_t fKernelPhysicalPML4;
uint64* fKernelVirtualPML4;
phys_addr_t fKernelPhysicalPMLTop;
uint64* fKernelVirtualPMLTop;
X86PhysicalPageMapper* fPhysicalPageMapper;
TranslationMapPhysicalPageMapper* fKernelPhysicalPageMapper;
static bool la57;
};
@@ -18,23 +18,24 @@
X86PagingStructures64Bit::X86PagingStructures64Bit()
:
fVirtualPML4(NULL)
fVirtualPMLTop(NULL)
{
}
X86PagingStructures64Bit::~X86PagingStructures64Bit()
{
// Free the PML4.
free(fVirtualPML4);
// Free the PMLTop.
free(fVirtualPMLTop);
}
void
X86PagingStructures64Bit::Init(uint64* virtualPML4, phys_addr_t physicalPML4)
X86PagingStructures64Bit::Init(uint64* virtualPMLTop,
phys_addr_t physicalPMLTop)
{
fVirtualPML4 = virtualPML4;
pgdir_phys = physicalPML4;
fVirtualPMLTop = virtualPMLTop;
pgdir_phys = physicalPMLTop;
}
@@ -14,16 +14,16 @@ struct X86PagingStructures64Bit final : X86PagingStructures {
X86PagingStructures64Bit();
virtual ~X86PagingStructures64Bit();
void Init(uint64* virtualPML4,
phys_addr_t physicalPML4);
void Init(uint64* virtualPMLTop,
phys_addr_t physicalPMLTop);
virtual void Delete();
uint64* VirtualPML4()
{ return fVirtualPML4; }
uint64* VirtualPMLTop()
{ return fVirtualPMLTop; }
private:
uint64* fVirtualPML4;
uint64* fVirtualPMLTop;
};
@@ -35,9 +35,10 @@
// #pragma mark - X86VMTranslationMap64Bit
X86VMTranslationMap64Bit::X86VMTranslationMap64Bit()
X86VMTranslationMap64Bit::X86VMTranslationMap64Bit(bool la57)
:
fPagingStructures(NULL)
fPagingStructures(NULL),
fLA57(la57)
{
}
@@ -53,8 +54,8 @@ X86VMTranslationMap64Bit::~X86VMTranslationMap64Bit()
phys_addr_t address;
vm_page* page;
// Free all structures in the bottom half of the PML4 (user memory).
uint64* virtualPML4 = fPagingStructures->VirtualPML4();
// Free all structures in the bottom half of the PMLTop (user memory).
uint64* virtualPML4 = fPagingStructures->VirtualPMLTop();
for (uint32 i = 0; i < 256; i++) {
if ((virtualPML4[i] & X86_64_PML4E_PRESENT) == 0)
continue;
@@ -128,9 +129,9 @@ X86VMTranslationMap64Bit::Init(bool kernel)
// Get the page mapper.
fPageMapper = method->KernelPhysicalPageMapper();
// Kernel PML4 is already mapped.
fPagingStructures->Init(method->KernelVirtualPML4(),
method->KernelPhysicalPML4());
// Kernel PMLTop is already mapped.
fPagingStructures->Init(method->KernelVirtualPMLTop(),
method->KernelPhysicalPMLTop());
} else {
// Allocate a physical page mapper.
status_t error = method->PhysicalPageMapper()
@@ -138,28 +139,28 @@ X86VMTranslationMap64Bit::Init(bool kernel)
if (error != B_OK)
return error;
// Assuming that only the top 2 PML4 entries are occupied for the
// Assuming that only the top 2 PMLTop entries are occupied for the
// kernel.
STATIC_ASSERT(KERNEL_PMAP_BASE == 0xffffff0000000000);
STATIC_ASSERT(KERNEL_BASE == 0xffffff0000000000);
// Allocate and clear the PML4.
uint64* virtualPML4 = (uint64*)memalign(B_PAGE_SIZE, B_PAGE_SIZE);
if (virtualPML4 == NULL)
// Allocate and clear the PMLTop.
uint64* virtualPMLTop = (uint64*)memalign(B_PAGE_SIZE, B_PAGE_SIZE);
if (virtualPMLTop == NULL)
return B_NO_MEMORY;
memset(virtualPML4, 0, B_PAGE_SIZE);
memset(virtualPMLTop, 0, B_PAGE_SIZE);
// Copy the top 2 PML4 entries.
virtualPML4[510] = method->KernelVirtualPML4()[510];
virtualPML4[511] = method->KernelVirtualPML4()[511];
// Copy the top 2 PMLTop entries.
virtualPMLTop[510] = method->KernelVirtualPMLTop()[510];
virtualPMLTop[511] = method->KernelVirtualPMLTop()[511];
// Look up the PML4 physical address.
phys_addr_t physicalPML4;
vm_get_page_mapping(VMAddressSpace::KernelID(), (addr_t)virtualPML4,
&physicalPML4);
// Look up the PMLTop physical address.
phys_addr_t physicalPMLTop;
vm_get_page_mapping(VMAddressSpace::KernelID(), (addr_t)virtualPMLTop,
&physicalPMLTop);
// Initialize the paging structures.
fPagingStructures->Init(virtualPML4, physicalPML4);
fPagingStructures->Init(virtualPMLTop, physicalPMLTop);
}
return B_OK;
@@ -171,12 +172,17 @@ X86VMTranslationMap64Bit::MaxPagesNeededToMap(addr_t start, addr_t end) const
{
// If start == 0, the actual base address is not yet known to the caller and
// we shall assume the worst case, which is where the start address is the
// last page covered by a PDPT.
// last page covered by a PDPT or PML4.
if (start == 0) {
start = k64BitPDPTRange - B_PAGE_SIZE;
start = (fLA57 ? k64BitPML4TRange : k64BitPDPTRange) - B_PAGE_SIZE;
end += start;
}
size_t requiredPML4s = 0;
if (fLA57) {
requiredPML4s = end / k64BitPML4TRange + 1
- start / k64BitPML4TRange;
}
size_t requiredPDPTs = end / k64BitPDPTRange + 1
- start / k64BitPDPTRange;
size_t requiredPageDirs = end / k64BitPageDirectoryRange + 1
@@ -184,7 +190,8 @@ X86VMTranslationMap64Bit::MaxPagesNeededToMap(addr_t start, addr_t end) const
size_t requiredPageTables = end / k64BitPageTableRange + 1
- start / k64BitPageTableRange;
return requiredPDPTs + requiredPageDirs + requiredPageTables;
return requiredPML4s + requiredPDPTs + requiredPageDirs
+ requiredPageTables;
}
@@ -200,7 +207,7 @@ X86VMTranslationMap64Bit::Map(addr_t virtualAddress, phys_addr_t physicalAddress
// Look up the page table for the virtual address, allocating new tables
// if required. Shouldn't fail.
uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress(
fPagingStructures->VirtualPML4(), virtualAddress, fIsKernelMap,
fPagingStructures->VirtualPMLTop(), virtualAddress, fIsKernelMap,
true, reservation, fPageMapper, fMapCount);
ASSERT(entry != NULL);
@@ -236,7 +243,7 @@ X86VMTranslationMap64Bit::Unmap(addr_t start, addr_t end)
do {
uint64* pageTable = X86PagingMethod64Bit::PageTableForAddress(
fPagingStructures->VirtualPML4(), start, fIsKernelMap, false,
fPagingStructures->VirtualPMLTop(), start, fIsKernelMap, false,
NULL, fPageMapper, fMapCount);
if (pageTable == NULL) {
// Move on to the next page table.
@@ -286,7 +293,7 @@ X86VMTranslationMap64Bit::DebugMarkRangePresent(addr_t start, addr_t end,
do {
uint64* pageTable = X86PagingMethod64Bit::PageTableForAddress(
fPagingStructures->VirtualPML4(), start, fIsKernelMap, false,
fPagingStructures->VirtualPMLTop(), start, fIsKernelMap, false,
NULL, fPageMapper, fMapCount);
if (pageTable == NULL) {
// Move on to the next page table.
@@ -336,7 +343,7 @@ X86VMTranslationMap64Bit::UnmapPage(VMArea* area, addr_t address,
// Look up the page table for the virtual address.
uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress(
fPagingStructures->VirtualPML4(), address, fIsKernelMap,
fPagingStructures->VirtualPMLTop(), address, fIsKernelMap,
false, NULL, fPageMapper, fMapCount);
if (entry == NULL)
return B_ENTRY_NOT_FOUND;
@@ -403,7 +410,7 @@ X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
do {
uint64* pageTable = X86PagingMethod64Bit::PageTableForAddress(
fPagingStructures->VirtualPML4(), start, fIsKernelMap, false,
fPagingStructures->VirtualPMLTop(), start, fIsKernelMap, false,
NULL, fPageMapper, fMapCount);
if (pageTable == NULL) {
// Move on to the next page table.
@@ -536,7 +543,7 @@ X86VMTranslationMap64Bit::UnmapArea(VMArea* area, bool deletingAddressSpace,
+ ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset);
uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress(
fPagingStructures->VirtualPML4(), address, fIsKernelMap,
fPagingStructures->VirtualPMLTop(), address, fIsKernelMap,
false, NULL, fPageMapper, fMapCount);
if (entry == NULL) {
panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
@@ -607,7 +614,7 @@ X86VMTranslationMap64Bit::Query(addr_t virtualAddress,
// large pages here. Look up the page directory entry for the virtual
// address.
uint64* pde = X86PagingMethod64Bit::PageDirectoryEntryForAddress(
fPagingStructures->VirtualPML4(), virtualAddress, fIsKernelMap,
fPagingStructures->VirtualPMLTop(), virtualAddress, fIsKernelMap,
false, NULL, fPageMapper, fMapCount);
if (pde == NULL || (*pde & X86_64_PDE_PRESENT) == 0)
return B_OK;
@@ -684,7 +691,7 @@ X86VMTranslationMap64Bit::Protect(addr_t start, addr_t end, uint32 attributes,
do {
uint64* pageTable = X86PagingMethod64Bit::PageTableForAddress(
fPagingStructures->VirtualPML4(), start, fIsKernelMap, false,
fPagingStructures->VirtualPMLTop(), start, fIsKernelMap, false,
NULL, fPageMapper, fMapCount);
if (pageTable == NULL) {
// Move on to the next page table.
@@ -741,7 +748,7 @@ X86VMTranslationMap64Bit::ClearFlags(addr_t address, uint32 flags)
ThreadCPUPinner pinner(thread_get_current_thread());
uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress(
fPagingStructures->VirtualPML4(), address, fIsKernelMap,
fPagingStructures->VirtualPMLTop(), address, fIsKernelMap,
false, NULL, fPageMapper, fMapCount);
if (entry == NULL)
return B_OK;
@@ -772,7 +779,7 @@ X86VMTranslationMap64Bit::ClearAccessedAndModified(VMArea* area, addr_t address,
ThreadCPUPinner pinner(thread_get_current_thread());
uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress(
fPagingStructures->VirtualPML4(), address, fIsKernelMap,
fPagingStructures->VirtualPMLTop(), address, fIsKernelMap,
false, NULL, fPageMapper, fMapCount);
if (entry == NULL)
return false;
@@ -14,7 +14,7 @@ struct X86PagingStructures64Bit;
struct X86VMTranslationMap64Bit final : X86VMTranslationMap {
X86VMTranslationMap64Bit();
X86VMTranslationMap64Bit(bool la57);
virtual ~X86VMTranslationMap64Bit();
status_t Init(bool kernel);
@@ -63,6 +63,7 @@ struct X86VMTranslationMap64Bit final : X86VMTranslationMap {
private:
X86PagingStructures64Bit* fPagingStructures;
bool fLA57;
};
@@ -9,6 +9,16 @@
#include <OS.h>
// PML5 entry bits.
#define X86_64_PML5E_PRESENT (1LL << 0)
#define X86_64_PML5E_WRITABLE (1LL << 1)
#define X86_64_PML5E_USER (1LL << 2)
#define X86_64_PML5E_WRITE_THROUGH (1LL << 3)
#define X86_64_PML5E_CACHING_DISABLED (1LL << 4)
#define X86_64_PML5E_ACCESSED (1LL << 5)
#define X86_64_PML5E_NOT_EXECUTABLE (1LL << 63)
#define X86_64_PML5E_ADDRESS_MASK 0x000ffffffffff000L
// PML4 entry bits.
#define X86_64_PML4E_PRESENT (1LL << 0)
#define X86_64_PML4E_WRITABLE (1LL << 1)
@@ -69,11 +79,13 @@
static const size_t k64BitPageTableRange = 0x200000L;
static const size_t k64BitPageDirectoryRange = 0x40000000L;
static const size_t k64BitPDPTRange = 0x8000000000L;
static const size_t k64BitPML4TRange = 0x1000000000000L;
static const size_t k64BitTableEntryCount = 512;
#define VADDR_TO_PML4E(va) (((va) & 0x0000fffffffff000L) / k64BitPDPTRange)
#define VADDR_TO_PML5E(va) (((va) & 0x01fffffffffff000L) / k64BitPML4TRange)
#define VADDR_TO_PML4E(va) (((va) % k64BitPML4TRange) / k64BitPDPTRange)
#define VADDR_TO_PDPTE(va) (((va) % k64BitPDPTRange) / k64BitPageDirectoryRange)
#define VADDR_TO_PDE(va) (((va) % k64BitPageDirectoryRange) / k64BitPageTableRange)
#define VADDR_TO_PTE(va) (((va) % k64BitPageTableRange) / B_PAGE_SIZE)