fix: fix hot loader page reuse for overlapping init segments

This commit is contained in:
karina
2026-04-21 00:30:41 +04:00
parent 41578c29d6
commit b7a4a90e63
3 changed files with 56 additions and 4 deletions
+51
View File
@@ -94,6 +94,28 @@ static UInt64* sVMVirtualMemoryMapPageInternal(UInt64* pml4, UInt64 phys, UInt64
return (UInt64*)virt;
}
static void* sVMVirtualMemoryGetMappedPageInternal(UInt64* pml4, UInt64 virt) {
UInt64 pt_idx = VMM_PT_INDEX(virt);
UInt64 pd_idx = VMM_PD_INDEX(virt);
UInt64 pdpt_idx = VMM_PDPT_INDEX(virt);
UInt64 pml4_idx = VMM_PML4_INDEX(virt);
UInt64* pml4_virt = pml4;
if (isInitialized) pml4_virt = (UInt64*)PHYS_TO_HHDM((UInt64)pml4);
if (!(pml4_virt[pml4_idx] & PTE_PRESENT)) return nullptr;
UInt64* pdpt_virt = sVMGetVirtualTable(PTE_GET_ADDR(pml4_virt[pml4_idx]));
if (!(pdpt_virt[pdpt_idx] & PTE_PRESENT)) return nullptr;
UInt64* pd_virt = sVMGetVirtualTable(PTE_GET_ADDR(pdpt_virt[pdpt_idx]));
if (!(pd_virt[pd_idx] & PTE_PRESENT)) return nullptr;
UInt64* pt_virt = sVMGetVirtualTable(PTE_GET_ADDR(pd_virt[pd_idx]));
if (!(pt_virt[pt_idx] & PTE_PRESENT)) return nullptr;
return (void*)PHYS_TO_HHDM(PTE_GET_ADDR(pt_virt[pt_idx]));
}
static void sVMVirtualMemoryUnmapPageInternal(UInt64* pml4, UInt64 virt) {
UInt64 pt_idx = VMM_PT_INDEX(virt);
UInt64 pd_idx = VMM_PD_INDEX(virt);
@@ -128,6 +150,35 @@ UInt64* VMVirtualMemoryMapPage(UInt64* pml4, UInt64 phys, UInt64 virt, UInt64 fl
return result;
}
void* VMVirtualMemoryGetOrAllocatePage(UInt64* pml4, UInt64 virt, UInt64 flags) {
OSSpinlockState state;
OSSpinlockLockIRQ(&sVMVMMlock, &state);
void* mappedPage = sVMVirtualMemoryGetMappedPageInternal(pml4, virt);
if (mappedPage) {
OSSpinlockUnlockIRQ(&sVMVMMlock, &state);
return mappedPage;
}
void* physicalPage = VMPhysicalMemoryAllocatePage();
if (!physicalPage) {
OSSpinlockUnlockIRQ(&sVMVMMlock, &state);
return nullptr;
}
UInt64* result = sVMVirtualMemoryMapPageInternal(pml4, (UInt64)physicalPage, virt, flags);
if (!result) {
OSSpinlockUnlockIRQ(&sVMVMMlock, &state);
return nullptr;
}
void* kernelVirtualAddress = (void*)PHYS_TO_HHDM((UInt64)physicalPage);
MemorySet(kernelVirtualAddress, 0, kVMPageSize);
OSSpinlockUnlockIRQ(&sVMVMMlock, &state);
return kernelVirtualAddress;
}
void VMVirtualMemoryUnmapPage(UInt64* pml4, UInt64 virt) {
OSSpinlockState state;
OSSpinlockLockIRQ(&sVMVMMlock, &state);