feat: overhaul userspace heap and virtual memory

This commit is contained in:
daniel committed 2026-08-10 12:25:27 +02:00
1 parent 4ecec32c5c
commit 9b23d99082
21 files changed
+905 -451

No files matched your search

+52 -8
View File
@@ -493,6 +493,8 @@ namespace Sched {
proc.kernelStackTop = kernelStackTop;
proc.userStackTop = UserStackTop - 8;
proc.heapNext = UserHeapBase;
for (uint64_t i = 0; i < UserHeapBitmapWords; i++)
g_userHeapPageMap[slot][i] = 0;
proc.fsBase = tls.fsBase;
proc.tlsTemplateVaddr = tls.templateVaddr;
proc.tlsFileSize = tls.fileSize;
@@ -651,6 +653,7 @@ namespace Sched {
}
if (!ok) {
Ipc::UnmapAndFreeUserRange(sharedPml4, base, mappedPages);
ReleaseUserHeapRange(primarySlot_, base, numPages * 0x1000ULL);
Kt::KernelLogStream(Kt::ERROR, "Sched")
<< "Thread TLS allocation failed";
return -1;
@@ -675,8 +678,11 @@ namespace Sched {
// Allocate kernel stack.
void* stackMem = Memory::g_pfa->ReallocConsecutive(nullptr, StackPages);
if (stackMem == nullptr) {
if (threadTlsPages != 0)
if (threadTlsPages != 0) {
Ipc::UnmapAndFreeUserRange(sharedPml4, threadTlsBase, threadTlsPages);
ReleaseUserHeapRange(primarySlot_, threadTlsBase,
threadTlsPages * 0x1000ULL);
}
return -1;
}
memset(stackMem, 0, StackSize);
@@ -698,8 +704,11 @@ namespace Sched {
if (slot < 0) {
schedLock.Release();
Memory::g_pfa->Free(stackMem, StackPages);
if (threadTlsPages != 0)
if (threadTlsPages != 0) {
Ipc::UnmapAndFreeUserRange(sharedPml4, threadTlsBase, threadTlsPages);
ReleaseUserHeapRange(primarySlot_, threadTlsBase,
threadTlsPages * 0x1000ULL);
}
return -1;
}
@@ -774,20 +783,54 @@ namespace Sched {
schedLock.Acquire();
Process& primary = processTable[primarySlot_];
uint64_t base = primary.heapNext;
bool validOwner = primary.primarySlot == primarySlot_ &&
primary.state != ProcessState::Free &&
primary.state != ProcessState::Terminated;
bool fits = validOwner && base >= UserHeapBase &&
base <= UserHeapLimit && size <= UserHeapLimit - base;
if (fits) {
primary.heapNext = base + size;
outVa = base;
bool fits = false;
uint64_t pages = size / 0x1000ULL;
uint64_t runStart = 0;
uint64_t runLength = 0;
if (validOwner && pages <= UserHeapPages) {
for (uint64_t page = 0; page < UserHeapPages; page++) {
bool used = (g_userHeapPageMap[primarySlot_][page / 64]
& (1ULL << (page % 64))) != 0;
if (used) {
runLength = 0;
continue;
}
if (runLength == 0) runStart = page;
runLength++;
if (runLength == pages) {
for (uint64_t p = runStart; p < runStart + pages; p++)
g_userHeapPageMap[primarySlot_][p / 64] |= 1ULL << (p % 64);
outVa = UserHeapBase + runStart * 0x1000ULL;
uint64_t end = outVa + size;
if (end > primary.heapNext) primary.heapNext = end;
fits = true;
break;
}
}
}
schedLock.Release();
return fits;
}
void ReleaseUserHeapRange(int primarySlot_, uint64_t va, uint64_t size) {
if (primarySlot_ < 0 || primarySlot_ >= MaxProcesses || size == 0 ||
(va & 0xFFFULL) != 0 || (size & 0xFFFULL) != 0 ||
va < UserHeapBase || va > UserHeapLimit || size > UserHeapLimit - va) {
return;
}
uint64_t first = (va - UserHeapBase) / 0x1000ULL;
uint64_t pages = size / 0x1000ULL;
schedLock.Acquire();
for (uint64_t p = first; p < first + pages; p++)
g_userHeapPageMap[primarySlot_][p / 64] &= ~(1ULL << (p % 64));
schedLock.Release();
}
static void FreeSiblingThreadTls(Process& thr) {
int primarySlot_ = thr.primarySlot;
if (primarySlot_ < 0 || primarySlot_ >= MaxProcesses ||
@@ -811,6 +854,7 @@ namespace Sched {
uint64_t pages = (blockSize + 16 + 0xFFF) / 0x1000;
thr.fsBase = 0;
Ipc::UnmapAndFreeUserRange(primary.pml4Phys, base, pages);
ReleaseUserHeapRange(primarySlot_, base, pages * 0x1000ULL);
}
// Switch away from a slot we have just marked non-runnable while holding