feat: add mmapRelease and mmapFaultHandler to mmap

This commit is contained in:
dualfroz committed 2026-09-06 15:26:00 +02:00
1 parent 2e9bb0a476
commit 19f79ca2fe
1 file changed
+98
+98
View File
@@ -159,3 +159,101 @@ bool mmapReserve(struct Thread* thread, uint64 addr, uint64 length, uint32 prot,
slot->fd = anonymous ? -1 : fd;
slot->fileOffset = anonymous ? 0 : fileOffset;
*outAddr = start;
return true;
}
bool mmapRelease(struct Thread* thread, uint64 addr, uint64 length)
{
if (length == 0 || addr % frameSize != 0)
return false;
uint64 unmapStart = addr;
uint64 unmapEnd = addr + pageAlignUp(length);
if (unmapEnd < unmapStart)
return false;
/* Up-front check: refuse the WHOLE call if releasing this range would
need to split a Vma in the middle (touching neither end) and no free
slot exists to hold the resulting upper half. A thread's own Vmas
never overlap each other, so at most one can ever need splitting. */
for (int i = 0; i < maxVmasPerThread; i++) {
Vma* v = &thread->vmas[i];
if (v->used && v->start < unmapStart && v->end > unmapEnd && !findFreeVmaSlot(thread))
return false;
}
for (int i = 0; i < maxVmasPerThread; i++) {
Vma* v = &thread->vmas[i];
if (!v->used || !rangesOverlap(v->start, v->end, unmapStart, unmapEnd))
continue;
uint64 freeFrom = v->start > unmapStart ? v->start : unmapStart;
uint64 freeTo = v->end < unmapEnd ? v->end : unmapEnd;
pagingUnmapUserRange(freeFrom, freeTo - freeFrom);
if (v->start >= unmapStart && v->end <= unmapEnd) {
v->used = false;
} else if (v->start < unmapStart && v->end > unmapEnd) {
Vma* upper = findFreeVmaSlot(thread);
*upper = *v;
upper->start = unmapEnd;
v->end = unmapStart;
} else if (v->start < unmapStart) {
v->end = unmapStart;
} else {
uint64 trimmed = unmapEnd - v->start;
if (!v->anonymous)
v->fileOffset += trimmed;
v->start = unmapEnd;
}
}
return true;
}
bool mmapFaultHandler(struct Thread* thread, uint64 faultAddr, bool forWrite)
{
Vma* v = mmapFind(thread, faultAddr);
if (!v)
return false;
if (forWrite && !(v->prot & mmapProtWrite))
return false;
if (!forWrite && !(v->prot & mmapProtRead))
return false;
uint64 pageAddr = pageAlignDown(faultAddr);
if (pagingResolve(pageAddr) != 0)
return true;
uint64 frame = pmmAlloc();
if (frame == 0)
return false;
memset((void*)frame, 0, frameSize);
if (!v->anonymous) {
FileDescriptor* fdEntry = &thread->fds[v->fd];
if (fdEntry->kind == fdFree) {
pmmFree(frame);
return false;
}
uint64 savedOffset = fdEntry->offset;
fdEntry->offset = v->fileOffset + (pageAddr - v->start);
vfsRead(v->fd, (void*)frame, frameSize);
fdEntry->offset = savedOffset;
}
uint64 flags = pageUser | ((v->prot & mmapProtWrite) ? pageWrite : 0);
if (!(v->prot & mmapProtExec))
flags |= pageNoExecute;
if (!pagingMap(pageAddr, frame, flags)) {
pmmFree(frame);
return false;
}
return true;
}
void mmapReleaseAll(struct Thread* thread)
{
memset(thread->vmas, 0, sizeof(thread->vmas));
}