From 6045726e414285fe07740395512a73ddd759beaf Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 20 May 2026 16:16:44 +0300 Subject: [PATCH] Kernel: Optimize PageTable::unmap_range on x86_64 --- kernel/arch/x86_64/PageTable.cpp | 66 ++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index 04c4ef91..56314cb0 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -564,12 +564,70 @@ namespace Kernel { ASSERT(vaddr % PAGE_SIZE == 0); - const size_t page_count = range_page_count(vaddr, size); + ASSERT(is_canonical(vaddr)); + ASSERT(is_canonical(vaddr + size - 1)); + + const vaddr_t uc_vaddr_start = uncanonicalize(vaddr); + const vaddr_t uc_vaddr_end = uncanonicalize(vaddr + size - 1); + + uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF; + uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF; + uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF; + uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF; + + const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF; + const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF; + const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF; + const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF; SpinLockGuard _(m_lock); - for (vaddr_t page = 0; page < page_count; page++) - unmap_page(vaddr + page * PAGE_SIZE, false); - invalidate_range(vaddr, page_count, true); + + uint64_t* pml4 = P2V(m_highest_paging_struct); + for (; pml4e <= e_pml4e; pml4e++) + { +#define UNALLOCATE_TABLE_IF_EMPTY(outer, inner) \ + if (old_##inner##e == 0 && inner##e == 512) { \ + unallocate_page(outer[outer##e] & s_page_addr_mask); \ + outer[outer##e] = 0; \ + } + if (!(pml4[pml4e] & Flags::Present)) + continue; + const uint16_t old_pdpte = pdpte; + uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask); + for (; pdpte < 512; pdpte++) + { + if (pml4e == e_pml4e && pdpte > e_pdpte) + break; + if (!(pdpt[pdpte] & Flags::Present)) + continue; + const uint16_t old_pde = pde; + uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); + for (; pde < 512; pde++) + { + if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde) + break; + if (!(pd[pde] & Flags::Present)) + continue; + const uint16_t old_pte = pte; + uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); + for (; pte < 512; pte++) + { + if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte) + break; + pt[pte] = 0; + } + UNALLOCATE_TABLE_IF_EMPTY(pd, pt); + pte = 0; + } + UNALLOCATE_TABLE_IF_EMPTY(pdpt, pd); + pde = 0; + } + UNALLOCATE_TABLE_IF_EMPTY(pml4, pdpt); + pdpte = 0; +#undef UNALLOCATE_TABLE_IF_EMPTY + } + + invalidate_range(vaddr, range_page_count(vaddr, size), true); } void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)