feat: implement SYS_FREE
This commit is contained in:
+62
-3
@@ -11,6 +11,27 @@
|
|||||||
#include <Memory/PageFrameAllocator.hpp>
|
#include <Memory/PageFrameAllocator.hpp>
|
||||||
|
|
||||||
namespace Zenith {
|
namespace Zenith {
|
||||||
|
|
||||||
|
// Per-process heap allocation tracking (separate from Process struct to avoid bloating it)
|
||||||
|
struct HeapAlloc {
|
||||||
|
uint64_t va;
|
||||||
|
uint64_t numPages;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr int MaxHeapAllocs = 128;
|
||||||
|
|
||||||
|
static HeapAlloc g_heapAllocs[Sched::MaxProcesses][MaxHeapAllocs];
|
||||||
|
static int g_heapAllocCount[Sched::MaxProcesses];
|
||||||
|
|
||||||
|
// Get the process table slot index for the current process
|
||||||
|
static int GetCurrentSlot() {
|
||||||
|
auto* proc = Sched::GetCurrentProcessPtr();
|
||||||
|
if (proc == nullptr) return -1;
|
||||||
|
// Process slot index = pointer offset from slot 0
|
||||||
|
auto* slot0 = Sched::GetProcessSlot(0);
|
||||||
|
return (int)(proc - slot0);
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t Sys_Alloc(uint64_t size) {
|
static uint64_t Sys_Alloc(uint64_t size) {
|
||||||
auto* proc = Sched::GetCurrentProcessPtr();
|
auto* proc = Sched::GetCurrentProcessPtr();
|
||||||
if (proc == nullptr) return 0;
|
if (proc == nullptr) return 0;
|
||||||
@@ -30,10 +51,48 @@ namespace Zenith {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc->heapNext += size;
|
proc->heapNext += size;
|
||||||
|
|
||||||
|
// Track the allocation so Sys_Free can release it
|
||||||
|
int slot = GetCurrentSlot();
|
||||||
|
if (slot >= 0 && g_heapAllocCount[slot] < MaxHeapAllocs) {
|
||||||
|
g_heapAllocs[slot][g_heapAllocCount[slot]++] = { userVa, numPages };
|
||||||
|
}
|
||||||
|
|
||||||
return userVa;
|
return userVa;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Sys_Free(uint64_t) {
|
static void Sys_Free(uint64_t addr) {
|
||||||
// TODO No-op for now (pages leak)
|
auto* proc = Sched::GetCurrentProcessPtr();
|
||||||
|
if (proc == nullptr) return;
|
||||||
|
|
||||||
|
int slot = GetCurrentSlot();
|
||||||
|
if (slot < 0) return;
|
||||||
|
|
||||||
|
// Find the allocation record matching this address
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < g_heapAllocCount[slot]; i++) {
|
||||||
|
if (g_heapAllocs[slot][i].va == addr) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idx < 0) return; // Unknown address — ignore
|
||||||
|
|
||||||
|
uint64_t va = g_heapAllocs[slot][idx].va;
|
||||||
|
uint64_t numPages = g_heapAllocs[slot][idx].numPages;
|
||||||
|
|
||||||
|
// Free each physical page and unmap the virtual address
|
||||||
|
for (uint64_t i = 0; i < numPages; i++) {
|
||||||
|
uint64_t pageVa = va + i * 0x1000;
|
||||||
|
uint64_t physAddr = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, pageVa);
|
||||||
|
if (physAddr != 0) {
|
||||||
|
Memory::g_pfa->Free((void*)Memory::HHDM(physAddr));
|
||||||
|
}
|
||||||
|
Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, pageVa);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove tracking entry by swapping with the last element
|
||||||
|
g_heapAllocs[slot][idx] = g_heapAllocs[slot][g_heapAllocCount[slot] - 1];
|
||||||
|
g_heapAllocCount[slot]--;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -240,6 +240,34 @@ namespace Memory::VMM {
|
|||||||
pageEntry->Address = physicalAddress >> 12;
|
pageEntry->Address = physicalAddress >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Paging::UnmapUserIn(std::uint64_t pml4Phys, std::uint64_t virtualAddress) {
|
||||||
|
VirtualAddress va(virtualAddress);
|
||||||
|
|
||||||
|
// Walk without allocating — if any level is absent, nothing is mapped.
|
||||||
|
auto walkRead = [](PageTable* table, uint64_t index) -> PageTable* {
|
||||||
|
PageTableEntry* entry = (PageTableEntry*)Memory::HHDM(&table->entries[index]);
|
||||||
|
if (!entry->Present) return nullptr;
|
||||||
|
return (PageTable*)(entry->Address << 12);
|
||||||
|
};
|
||||||
|
|
||||||
|
PageTable* pml4 = (PageTable*)pml4Phys;
|
||||||
|
auto pml3 = walkRead(pml4, va.GetL4Index());
|
||||||
|
if (!pml3) return;
|
||||||
|
auto pml2 = walkRead(pml3, va.GetL3Index());
|
||||||
|
if (!pml2) return;
|
||||||
|
auto pml1 = walkRead(pml2, va.GetL2Index());
|
||||||
|
if (!pml1) return;
|
||||||
|
|
||||||
|
PageTableEntry* pageEntry = (PageTableEntry*)Memory::HHDM(&pml1->entries[va.GetPageIndex()]);
|
||||||
|
if (!pageEntry->Present) return;
|
||||||
|
|
||||||
|
// Clear the entire 8-byte PTE
|
||||||
|
*(uint64_t*)pageEntry = 0;
|
||||||
|
|
||||||
|
// Invalidate TLB for this virtual address
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(virtualAddress) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
std::uint64_t Paging::GetPhysAddr(std::uint64_t pml4, std::uint64_t virtualAddress, bool use40BitL1) {
|
std::uint64_t Paging::GetPhysAddr(std::uint64_t pml4, std::uint64_t virtualAddress, bool use40BitL1) {
|
||||||
VirtualAddress virtualAddressObj(virtualAddress);
|
VirtualAddress virtualAddressObj(virtualAddress);
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,9 @@ public:
|
|||||||
// Map a page into an arbitrary PML4 with User + Write-Combining attributes.
|
// Map a page into an arbitrary PML4 with User + Write-Combining attributes.
|
||||||
static void MapUserInWC(std::uint64_t pml4Phys, std::uint64_t physicalAddress, std::uint64_t virtualAddress);
|
static void MapUserInWC(std::uint64_t pml4Phys, std::uint64_t physicalAddress, std::uint64_t virtualAddress);
|
||||||
|
|
||||||
|
// Unmap a single page from an arbitrary PML4 (clears PTE + invalidates TLB).
|
||||||
|
static void UnmapUserIn(std::uint64_t pml4Phys, std::uint64_t virtualAddress);
|
||||||
|
|
||||||
// Identity-map EFI runtime service regions so firmware code can
|
// Identity-map EFI runtime service regions so firmware code can
|
||||||
// reference its own data at physical addresses.
|
// reference its own data at physical addresses.
|
||||||
void MapEfiRuntime(limine_efi_memmap_response* efiMemmap);
|
void MapEfiRuntime(limine_efi_memmap_response* efiMemmap);
|
||||||
|
|||||||
Reference in New Issue
Block a user