kernel/x86_64: Handle LA57 paging in VMTranslationMap page table walks.

Without this, we will fail to free the last level of page tables.
This bug has apparently been present since LA57 was originally
introduced years ago, however it was likely not a problem before
now because only the BIOS bootloader has support for it, while
systems that support LA57 are more likely to be booted via EFI.

While at it, fix the address mask for non-LA57 in
DebugGetReverseMappingInfo.

Should fix #19460.
This commit is contained in:
Augustin Cavalier
2025-03-12 12:56:01 -04:00
parent 92e002641e
commit 3d196bd28c
@@ -51,14 +51,34 @@ X86VMTranslationMap64Bit::~X86VMTranslationMap64Bit()
if (fPagingStructures == NULL) if (fPagingStructures == NULL)
return; return;
if (fPageMapper != NULL) { if (fPageMapper == NULL) {
fPagingStructures->RemoveReference();
return;
}
vm_page_reservation reservation = {}; vm_page_reservation reservation = {};
phys_addr_t address; phys_addr_t address;
vm_page* page; vm_page* page;
// Free all structures in the bottom half of the PMLTop (user memory). // Free all structures in the bottom half of the PMLTop (user memory).
uint64* virtualPML4 = fPagingStructures->VirtualPMLTop(); uint64* virtualPML5 = NULL;
for (uint32 i = 0; i < 256; i++) { if (fLA57)
virtualPML5 = fPagingStructures->VirtualPMLTop();
for (uint32 p = 0; p < 256; p++) {
uint64* virtualPML4 = NULL;
uint32 limitPML4 = 256;
if (fLA57) {
if ((virtualPML5[p] & X86_64_PML5E_PRESENT) == 0)
continue;
virtualPML4 = (uint64*)fPageMapper->GetPageTableAt(
virtualPML5[p] & X86_64_PML5E_ADDRESS_MASK);
limitPML4 = 512;
} else {
virtualPML4 = fPagingStructures->VirtualPMLTop();
}
for (uint32 i = 0; i < limitPML4; i++) {
if ((virtualPML4[i] & X86_64_PML4E_PRESENT) == 0) if ((virtualPML4[i] & X86_64_PML4E_PRESENT) == 0)
continue; continue;
@@ -107,10 +127,24 @@ X86VMTranslationMap64Bit::~X86VMTranslationMap64Bit()
vm_page_free_etc(NULL, page, &reservation); vm_page_free_etc(NULL, page, &reservation);
} }
if (fLA57) {
address = virtualPML5[p] & X86_64_PML5E_ADDRESS_MASK;
page = vm_lookup_page(address / B_PAGE_SIZE);
if (page == NULL) {
panic("PML4 %u on invalid page %#" B_PRIxPHYSADDR "\n", p,
address);
}
DEBUG_PAGE_ACCESS_START(page);
vm_page_free_etc(NULL, page, &reservation);
} else {
break;
}
}
vm_page_unreserve_pages(&reservation); vm_page_unreserve_pages(&reservation);
fPageMapper->Delete(); fPageMapper->Delete();
}
fPagingStructures->RemoveReference(); fPagingStructures->RemoveReference();
} }
@@ -731,16 +765,29 @@ bool
X86VMTranslationMap64Bit::DebugGetReverseMappingInfo(phys_addr_t physicalAddress, X86VMTranslationMap64Bit::DebugGetReverseMappingInfo(phys_addr_t physicalAddress,
ReverseMappingInfoCallback& callback) ReverseMappingInfoCallback& callback)
{ {
uint64* virtualPML5 = NULL;
if (fLA57)
virtualPML5 = fPagingStructures->VirtualPMLTop();
for (uint32 p = 0; p < (fIsKernelMap ? 512 : 256); p++) {
uint64* virtualPML4 = NULL;
uint32 limitPML4 = (fIsKernelMap ? 512 : 256);
if (fLA57) { if (fLA57) {
kprintf("X86VMTranslationMap64Bit::DebugGetReverseMappingInfo not implemented for LA57\n"); if ((virtualPML5[p] & X86_64_PML5E_PRESENT) == 0)
return false; continue;
virtualPML4 = (uint64*)fPageMapper->GetPageTableAt(
virtualPML5[p] & X86_64_PML5E_ADDRESS_MASK);
limitPML4 = 512;
} else {
virtualPML4 = fPagingStructures->VirtualPMLTop();
} }
const uint64* virtualPML4 = fPagingStructures->VirtualPMLTop(); for (uint32 i = 0; i < limitPML4; i++) {
for (uint32 i = 0; i < (fIsKernelMap ? 512 : 256); i++) {
if ((virtualPML4[i] & X86_64_PML4E_PRESENT) == 0) if ((virtualPML4[i] & X86_64_PML4E_PRESENT) == 0)
continue; continue;
const uint64 addressMask = (i >= 256) ? 0xffffff0000000000LL : 0; uint64 addressMask = 0;
if (i >= 256)
addressMask = fLA57 ? 0xff00000000000000LL : 0xfffff00000000000LL;
const uint64* virtualPDPT = (uint64*)fPageMapper->GetPageTableAt( const uint64* virtualPDPT = (uint64*)fPageMapper->GetPageTableAt(
virtualPML4[i] & X86_64_PML4E_ADDRESS_MASK); virtualPML4[i] & X86_64_PML4E_ADDRESS_MASK);
@@ -759,7 +806,8 @@ X86VMTranslationMap64Bit::DebugGetReverseMappingInfo(phys_addr_t physicalAddress
if (physicalAddress >= largeAddress if (physicalAddress >= largeAddress
&& physicalAddress < (largeAddress + k64BitPageTableRange)) { && physicalAddress < (largeAddress + k64BitPageTableRange)) {
off_t offset = physicalAddress - largeAddress; off_t offset = physicalAddress - largeAddress;
addr_t virtualAddress = i * k64BitPDPTRange addr_t virtualAddress = p * k64BitPML4TRange
+ i * k64BitPDPTRange
+ j * k64BitPageDirectoryRange + j * k64BitPageDirectoryRange
+ k * k64BitPageTableRange + k * k64BitPageTableRange
+ offset; + offset;
@@ -777,7 +825,8 @@ X86VMTranslationMap64Bit::DebugGetReverseMappingInfo(phys_addr_t physicalAddress
continue; continue;
if ((virtualPageTable[l] & X86_64_PTE_ADDRESS_MASK) == physicalAddress) { if ((virtualPageTable[l] & X86_64_PTE_ADDRESS_MASK) == physicalAddress) {
addr_t virtualAddress = i * k64BitPDPTRange addr_t virtualAddress = p * k64BitPML4TRange
+ i * k64BitPDPTRange
+ j * k64BitPageDirectoryRange + j * k64BitPageDirectoryRange
+ k * k64BitPageTableRange + k * k64BitPageTableRange
+ l * B_PAGE_SIZE; + l * B_PAGE_SIZE;
@@ -790,6 +839,10 @@ X86VMTranslationMap64Bit::DebugGetReverseMappingInfo(phys_addr_t physicalAddress
} }
} }
if (!fLA57)
break;
}
return false; return false;
} }