fix: continue fix page fault heap regression
This commit is contained in:
@@ -69,25 +69,43 @@ namespace Memory {
|
||||
}
|
||||
|
||||
void* PageFrameAllocator::ReallocConsecutive(void* ptr, int n) {
|
||||
auto first = Allocate();
|
||||
Lock.Acquire();
|
||||
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
if (Allocate() == nullptr) {
|
||||
Panic("PageFrameAllocator Reallocation failed", nullptr);
|
||||
};
|
||||
// Search the free list for a single contiguous region >= n pages.
|
||||
// The old implementation assumed N consecutive Allocate() calls gave
|
||||
// adjacent pages, which breaks when individual pages are freed back.
|
||||
size_t needed = (size_t)n * 0x1000;
|
||||
Page* current = head.next;
|
||||
Page* prev = &head;
|
||||
|
||||
while (current != nullptr) {
|
||||
if (current->size >= needed) {
|
||||
// Carve from the top of this contiguous region
|
||||
current->size -= needed;
|
||||
void* base;
|
||||
if (current->size == 0) {
|
||||
base = (void*)current;
|
||||
prev->next = current->next;
|
||||
} else {
|
||||
base = (void*)((uint64_t)current + current->size);
|
||||
}
|
||||
|
||||
Lock.Release();
|
||||
|
||||
if (ptr != nullptr) {
|
||||
memcpy(base, ptr, 0x1000); // copy one page (ptr is always a single page)
|
||||
Free(ptr);
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
prev = current;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
// Allocate() returns pages from the top of a free region in descending
|
||||
// order, so 'first' is the highest address. The contiguous block
|
||||
// actually starts (n-1) pages below 'first'.
|
||||
void* base = (void*)((uint64_t)first - (uint64_t)(n - 1) * 0x1000);
|
||||
|
||||
if (ptr != nullptr) {
|
||||
memcpy(base, ptr, (uint64_t)n * 0x1000);
|
||||
Free(ptr);
|
||||
}
|
||||
|
||||
return base;
|
||||
Lock.Release();
|
||||
Panic("PageFrameAllocator: no contiguous region available", nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PageFrameAllocator::Free(void* ptr) {
|
||||
@@ -102,7 +120,7 @@ namespace Memory {
|
||||
|
||||
void PageFrameAllocator::Free(void* ptr, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
Free((void*)(uint64_t)ptr + (0x1000 * n));
|
||||
Free((void*)((uint64_t)ptr + 0x1000 * i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -268,6 +268,60 @@ namespace Memory::VMM {
|
||||
asm volatile("invlpg (%0)" :: "r"(virtualAddress) : "memory");
|
||||
}
|
||||
|
||||
void Paging::FreeUserHalf(std::uint64_t pml4Phys) {
|
||||
// PageTable* pointers store PHYSICAL addresses (same convention as MapUserIn/UnmapUserIn).
|
||||
// Each individual entry access goes through HHDM() to get a valid virtual pointer.
|
||||
PageTable* pml4 = (PageTable*)pml4Phys;
|
||||
|
||||
// Walk user-half entries (0-255); kernel-half (256-511) is shared and must not be touched.
|
||||
for (int i4 = 0; i4 < 256; i4++) {
|
||||
PageTableEntry* pml4e = (PageTableEntry*)Memory::HHDM(&pml4->entries[i4]);
|
||||
if (!pml4e->Present) continue;
|
||||
|
||||
uint64_t pdptPhys = (uint64_t)pml4e->Address << 12;
|
||||
PageTable* pdpt = (PageTable*)pdptPhys;
|
||||
|
||||
for (int i3 = 0; i3 < 512; i3++) {
|
||||
PageTableEntry* pdpte = (PageTableEntry*)Memory::HHDM(&pdpt->entries[i3]);
|
||||
if (!pdpte->Present) continue;
|
||||
|
||||
uint64_t pdPhys = (uint64_t)pdpte->Address << 12;
|
||||
PageTable* pd = (PageTable*)pdPhys;
|
||||
|
||||
for (int i2 = 0; i2 < 512; i2++) {
|
||||
PageTableEntry* pde = (PageTableEntry*)Memory::HHDM(&pd->entries[i2]);
|
||||
if (!pde->Present) continue;
|
||||
|
||||
uint64_t ptPhys = (uint64_t)pde->Address << 12;
|
||||
PageTable* pt = (PageTable*)ptPhys;
|
||||
|
||||
// Free all leaf physical pages
|
||||
for (int i1 = 0; i1 < 512; i1++) {
|
||||
PageTableEntry* pte = (PageTableEntry*)Memory::HHDM(&pt->entries[i1]);
|
||||
if (!pte->Present) continue;
|
||||
|
||||
// Skip MMIO/WC pages (not PFA-managed)
|
||||
if (pte->WriteThrough || pte->CacheDisabled) continue;
|
||||
|
||||
uint64_t pagePhys = (uint64_t)pte->Address << 12;
|
||||
if (pagePhys != 0) {
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pagePhys));
|
||||
}
|
||||
}
|
||||
|
||||
// Free the PT page itself
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(ptPhys));
|
||||
}
|
||||
|
||||
// Free the PD page
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pdPhys));
|
||||
}
|
||||
|
||||
// Free the PDPT page
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pdptPhys));
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t Paging::GetPhysAddr(std::uint64_t pml4, std::uint64_t virtualAddress, bool use40BitL1) {
|
||||
VirtualAddress virtualAddressObj(virtualAddress);
|
||||
|
||||
|
||||
@@ -112,6 +112,11 @@ public:
|
||||
// Unmap a single page from an arbitrary PML4 (clears PTE + invalidates TLB).
|
||||
static void UnmapUserIn(std::uint64_t pml4Phys, std::uint64_t virtualAddress);
|
||||
|
||||
// Free all user-half page table structures and physical pages (PML4 entries 0-255).
|
||||
// Does NOT free the PML4 page itself (caller handles that).
|
||||
// Skips MMIO/WC pages (WriteThrough or CacheDisabled set in PTE).
|
||||
static void FreeUserHalf(std::uint64_t pml4Phys);
|
||||
|
||||
// Identity-map EFI runtime service regions so firmware code can
|
||||
// reference its own data at physical addresses.
|
||||
void MapEfiRuntime(limine_efi_memmap_response* efiMemmap);
|
||||
|
||||
Reference in New Issue
Block a user