feat: add mmapRelease and mmapFaultHandler to mmap
This commit is contained in:
1 parent
2e9bb0a476
commit
19f79ca2fe
1 file changed
+98
+98
@@ -159,3 +159,101 @@ bool mmapReserve(struct Thread* thread, uint64 addr, uint64 length, uint32 prot,
|
|||||||
slot->fd = anonymous ? -1 : fd;
|
slot->fd = anonymous ? -1 : fd;
|
||||||
slot->fileOffset = anonymous ? 0 : fileOffset;
|
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));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user