feat: multi-user system, bug fixes, security & performance fixes, and more
This commit is contained in:
@@ -36,11 +36,19 @@ namespace Montauk {
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (proc == nullptr) return 0;
|
||||
|
||||
// Guard against overflow before rounding
|
||||
static constexpr uint64_t USER_SPACE_END = 0x0000800000000000ULL;
|
||||
if (size > 0xFFFFFFFFFFFF0000ULL) return 0;
|
||||
|
||||
// Round up to page boundary
|
||||
size = (size + 0xFFF) & ~0xFFFULL;
|
||||
if (size == 0) size = 0x1000;
|
||||
|
||||
uint64_t userVa = proc->heapNext;
|
||||
|
||||
// Ensure allocation stays within user address space
|
||||
if (userVa + size < userVa || userVa + size > USER_SPACE_END) return 0;
|
||||
|
||||
uint64_t numPages = size / 0x1000;
|
||||
|
||||
// Allocate physical pages and map them into the process
|
||||
|
||||
@@ -38,6 +38,23 @@ extern "C" void SyscallEntry();
|
||||
|
||||
namespace Montauk {
|
||||
|
||||
// ---- User pointer validation ----
|
||||
// Reject pointers that fall in the kernel-half of the address space
|
||||
// (canonical high addresses, i.e. >= 0x0000800000000000).
|
||||
// This prevents userspace from tricking the kernel into reading/writing
|
||||
// kernel memory via syscall arguments.
|
||||
|
||||
static constexpr uint64_t USER_SPACE_END = 0x0000800000000000ULL;
|
||||
|
||||
static bool IsUserPtr(uint64_t addr) {
|
||||
return addr == 0 || addr < USER_SPACE_END;
|
||||
}
|
||||
|
||||
// Validate that a pointer is non-null and in user space
|
||||
static bool ValidUserPtr(uint64_t addr) {
|
||||
return addr != 0 && addr < USER_SPACE_END;
|
||||
}
|
||||
|
||||
// ---- Dispatch ----
|
||||
|
||||
extern "C" int64_t SyscallDispatch(SyscallFrame* frame) {
|
||||
@@ -59,14 +76,17 @@ namespace Montauk {
|
||||
case SYS_GETPID:
|
||||
return (int64_t)Sys_GetPid();
|
||||
case SYS_PRINT:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_Print((const char*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_PUTCHAR:
|
||||
Sys_Putchar((char)frame->arg1);
|
||||
return 0;
|
||||
case SYS_OPEN:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_Open((const char*)frame->arg1);
|
||||
case SYS_READ:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_Read((int)frame->arg1, (uint8_t*)frame->arg2,
|
||||
frame->arg3, frame->arg4);
|
||||
case SYS_GETSIZE:
|
||||
@@ -75,6 +95,7 @@ namespace Montauk {
|
||||
Sys_Close((int)frame->arg1);
|
||||
return 0;
|
||||
case SYS_READDIR:
|
||||
if (!ValidUserPtr(frame->arg1) || !ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_ReadDir((const char*)frame->arg1,
|
||||
(const char**)frame->arg2,
|
||||
(int)frame->arg3);
|
||||
@@ -88,11 +109,13 @@ namespace Montauk {
|
||||
case SYS_GETMILLISECONDS:
|
||||
return (int64_t)Sys_GetMilliseconds();
|
||||
case SYS_GETINFO:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_GetInfo((SysInfo*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_ISKEYAVAILABLE:
|
||||
return (int64_t)Sys_IsKeyAvailable();
|
||||
case SYS_GETKEY:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_GetKey((KeyEvent*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_GETCHAR:
|
||||
@@ -100,11 +123,14 @@ namespace Montauk {
|
||||
case SYS_PING:
|
||||
return (int64_t)Sys_Ping((uint32_t)frame->arg1, (uint32_t)frame->arg2);
|
||||
case SYS_SPAWN:
|
||||
return (int64_t)Sys_Spawn((const char*)frame->arg1, (const char*)frame->arg2);
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_Spawn((const char*)frame->arg1,
|
||||
IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
|
||||
case SYS_WAITPID:
|
||||
Sys_WaitPid((int)frame->arg1);
|
||||
return 0;
|
||||
case SYS_FBINFO:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_FbInfo((FbInfo*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_FBMAP:
|
||||
@@ -112,6 +138,7 @@ namespace Montauk {
|
||||
case SYS_TERMSIZE:
|
||||
return (int64_t)Sys_TermSize();
|
||||
case SYS_GETARGS:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_GetArgs((char*)frame->arg1, frame->arg2);
|
||||
case SYS_RESET:
|
||||
Sys_Reset();
|
||||
@@ -120,6 +147,7 @@ namespace Montauk {
|
||||
Sys_Shutdown();
|
||||
return 0;
|
||||
case SYS_GETTIME:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_GetTime((DateTime*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_SOCKET:
|
||||
@@ -133,61 +161,83 @@ namespace Montauk {
|
||||
case SYS_ACCEPT:
|
||||
return (int64_t)Sys_Accept((int)frame->arg1);
|
||||
case SYS_SEND:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_Send((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
|
||||
case SYS_RECV:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_Recv((int)frame->arg1, (uint8_t*)frame->arg2, (uint32_t)frame->arg3);
|
||||
case SYS_CLOSESOCK:
|
||||
Sys_CloseSock((int)frame->arg1);
|
||||
return 0;
|
||||
case SYS_GETNETCFG:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_GetNetCfg((NetCfg*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_SETNETCFG:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_SetNetCfg((const NetCfg*)frame->arg1);
|
||||
case SYS_SENDTO:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_SendTo((int)frame->arg1, (const uint8_t*)frame->arg2,
|
||||
(uint32_t)frame->arg3, (uint32_t)frame->arg4,
|
||||
(uint16_t)frame->arg5);
|
||||
case SYS_RECVFROM:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_RecvFrom((int)frame->arg1, (uint8_t*)frame->arg2,
|
||||
(uint32_t)frame->arg3, (uint32_t*)frame->arg4,
|
||||
(uint16_t*)frame->arg5);
|
||||
(uint32_t)frame->arg3,
|
||||
IsUserPtr(frame->arg4) ? (uint32_t*)frame->arg4 : nullptr,
|
||||
IsUserPtr(frame->arg5) ? (uint16_t*)frame->arg5 : nullptr);
|
||||
case SYS_FWRITE:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_FWrite((int)frame->arg1, (const uint8_t*)frame->arg2,
|
||||
frame->arg3, frame->arg4);
|
||||
case SYS_FCREATE:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_FCreate((const char*)frame->arg1);
|
||||
case SYS_FDELETE:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_FDelete((const char*)frame->arg1);
|
||||
case SYS_FMKDIR:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_FMkdir((const char*)frame->arg1);
|
||||
case SYS_DRIVELIST:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_DriveList((int*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_TERMSCALE:
|
||||
return Sys_TermScale(frame->arg1, frame->arg2);
|
||||
case SYS_RESOLVE:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_Resolve((const char*)frame->arg1);
|
||||
case SYS_GETRANDOM:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_GetRandom((uint8_t*)frame->arg1, frame->arg2);
|
||||
case SYS_KLOG:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Kt::ReadKernelLog((char*)frame->arg1, frame->arg2);
|
||||
case SYS_MOUSESTATE:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_MouseState((MouseState*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_SETMOUSEBOUNDS:
|
||||
Sys_SetMouseBounds((int32_t)frame->arg1, (int32_t)frame->arg2);
|
||||
return 0;
|
||||
case SYS_SPAWN_REDIR:
|
||||
return (int64_t)Sys_SpawnRedir((const char*)frame->arg1, (const char*)frame->arg2);
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_SpawnRedir((const char*)frame->arg1,
|
||||
IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
|
||||
case SYS_CHILDIO_READ:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_ChildIoRead((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3);
|
||||
case SYS_CHILDIO_WRITE:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_ChildIoWrite((int)frame->arg1, (const char*)frame->arg2, (int)frame->arg3);
|
||||
case SYS_CHILDIO_WRITEKEY:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_ChildIoWriteKey((int)frame->arg1, (const KeyEvent*)frame->arg2);
|
||||
case SYS_CHILDIO_SETTERMSZ:
|
||||
return (int64_t)Sys_ChildIoSetTermsz((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
|
||||
case SYS_WINCREATE:
|
||||
if (!ValidUserPtr(frame->arg1) || !ValidUserPtr(frame->arg4)) return -1;
|
||||
return (int64_t)Sys_WinCreate((const char*)frame->arg1, (int)frame->arg2,
|
||||
(int)frame->arg3, (WinCreateResult*)frame->arg4);
|
||||
case SYS_WINDESTROY:
|
||||
@@ -195,16 +245,20 @@ namespace Montauk {
|
||||
case SYS_WINPRESENT:
|
||||
return (int64_t)Sys_WinPresent((int)frame->arg1);
|
||||
case SYS_WINPOLL:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_WinPoll((int)frame->arg1, (WinEvent*)frame->arg2);
|
||||
case SYS_WINENUM:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_WinEnum((WinInfo*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_WINMAP:
|
||||
return (int64_t)Sys_WinMap((int)frame->arg1);
|
||||
case SYS_WINSENDEVENT:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return (int64_t)Sys_WinSendEvent((int)frame->arg1, (const WinEvent*)frame->arg2);
|
||||
case SYS_WINRESIZE:
|
||||
return (int64_t)Sys_WinResize((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
|
||||
case SYS_PROCLIST:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_KILL: {
|
||||
// Free heap allocations for the target process before killing it
|
||||
@@ -217,8 +271,10 @@ namespace Montauk {
|
||||
return (int64_t)Sys_Kill((int)frame->arg1);
|
||||
}
|
||||
case SYS_DEVLIST:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_DevList((DevInfo*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_DISKINFO:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_DiskInfo((DiskInfo*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_WINSETSCALE:
|
||||
return (int64_t)Sys_WinSetScale((int)frame->arg1);
|
||||
@@ -227,41 +283,53 @@ namespace Montauk {
|
||||
case SYS_WINSETCURSOR:
|
||||
return (int64_t)Sys_WinSetCursor((int)frame->arg1, (int)frame->arg2);
|
||||
case SYS_MEMSTATS:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
Sys_MemStats((MemStats*)frame->arg1);
|
||||
return 0;
|
||||
case SYS_PARTLIST:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_PartList((PartInfo*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_DISKREAD:
|
||||
if (!ValidUserPtr(frame->arg4)) return -1;
|
||||
return (int64_t)Sys_DiskRead((int)frame->arg1, frame->arg2,
|
||||
(uint32_t)frame->arg3, (void*)frame->arg4);
|
||||
case SYS_DISKWRITE:
|
||||
if (!ValidUserPtr(frame->arg4)) return -1;
|
||||
return (int64_t)Sys_DiskWrite((int)frame->arg1, frame->arg2,
|
||||
(uint32_t)frame->arg3, (const void*)frame->arg4);
|
||||
case SYS_GPTINIT:
|
||||
return (int64_t)Sys_GptInit((int)frame->arg1);
|
||||
case SYS_GPTADD:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_GptAdd((const GptAddParams*)frame->arg1);
|
||||
case SYS_FSMOUNT:
|
||||
return (int64_t)Sys_FsMount((int)frame->arg1, (int)frame->arg2);
|
||||
case SYS_FSFORMAT:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return (int64_t)Sys_FsFormat((const FsFormatParams*)frame->arg1);
|
||||
case SYS_AUDIOOPEN:
|
||||
return Sys_AudioOpen((uint32_t)frame->arg1, (uint8_t)frame->arg2, (uint8_t)frame->arg3);
|
||||
case SYS_AUDIOCLOSE:
|
||||
return Sys_AudioClose((int)frame->arg1);
|
||||
case SYS_AUDIOWRITE:
|
||||
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||
return Sys_AudioWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
|
||||
case SYS_AUDIOCTL:
|
||||
return Sys_AudioCtl((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
|
||||
case SYS_BTSCAN:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_BtScan((BtScanResult*)frame->arg1, (int)frame->arg2, (uint32_t)frame->arg3);
|
||||
case SYS_BTCONNECT:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_BtConnect((const uint8_t*)frame->arg1);
|
||||
case SYS_BTDISCONNECT:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_BtDisconnect((const uint8_t*)frame->arg1);
|
||||
case SYS_BTLIST:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_BtList((BtDevInfo*)frame->arg1, (int)frame->arg2);
|
||||
case SYS_BTINFO:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_BtInfo((BtAdapterInfo*)frame->arg1);
|
||||
default:
|
||||
return -1;
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace WinServer {
|
||||
}
|
||||
if (slotIdx < 0) return -1;
|
||||
|
||||
// Validate dimensions
|
||||
if (w <= 0 || h <= 0) return -1;
|
||||
// Validate dimensions (cap at 16384 to prevent integer overflow in w*h*4)
|
||||
if (w <= 0 || h <= 0 || w > 16384 || h > 16384) return -1;
|
||||
uint64_t bufSize = (uint64_t)w * h * 4;
|
||||
int numPages = (int)((bufSize + 0xFFF) / 0x1000);
|
||||
if (numPages > MaxPixelPages) return -1;
|
||||
@@ -207,7 +207,7 @@ namespace WinServer {
|
||||
if (windowId < 0 || windowId >= MaxWindows) return -1;
|
||||
WindowSlot& slot = g_slots[windowId];
|
||||
if (!slot.used || slot.ownerPid != callerPid) return -1;
|
||||
if (newW <= 0 || newH <= 0) return -1;
|
||||
if (newW <= 0 || newH <= 0 || newW > 16384 || newH > 16384) return -1;
|
||||
if (newW == slot.width && newH == slot.height) {
|
||||
outVa = slot.ownerVa;
|
||||
return 0;
|
||||
|
||||
@@ -338,6 +338,73 @@ namespace Fs::Ramdisk {
|
||||
return fileCount++;
|
||||
}
|
||||
|
||||
int Delete(const char* path) {
|
||||
if (path == nullptr) return -1;
|
||||
if (path[0] == '/') path++;
|
||||
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
if (StrEqual(fileTable[i].name, path)) {
|
||||
// Free heap-allocated data
|
||||
if (fileTable[i].heapAllocated && fileTable[i].data) {
|
||||
Memory::g_heap->Free(fileTable[i].data);
|
||||
}
|
||||
|
||||
// Shift remaining entries down
|
||||
for (int j = i; j < fileCount - 1; j++) {
|
||||
fileTable[j] = fileTable[j + 1];
|
||||
}
|
||||
fileCount--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
int Mkdir(const char* path) {
|
||||
if (path == nullptr) return -1;
|
||||
if (fileCount >= MaxFiles) return -1;
|
||||
if (path[0] == '/') path++;
|
||||
|
||||
// Check if directory already exists
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
if (StrEqual(fileTable[i].name, path) && fileTable[i].isDirectory) {
|
||||
return 0; // already exists
|
||||
}
|
||||
// Also check with trailing slash
|
||||
int pathLen = StrLen(path);
|
||||
int entryLen = StrLen(fileTable[i].name);
|
||||
if (entryLen == pathLen + 1 && fileTable[i].name[entryLen - 1] == '/' &&
|
||||
fileTable[i].isDirectory) {
|
||||
bool match = true;
|
||||
for (int j = 0; j < pathLen; j++) {
|
||||
if (path[j] != fileTable[i].name[j]) { match = false; break; }
|
||||
}
|
||||
if (match) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create directory entry (stored with trailing slash for tar convention)
|
||||
FileEntry& entry = fileTable[fileCount];
|
||||
|
||||
int nameLen = 0;
|
||||
while (nameLen < MaxNameLen - 2 && path[nameLen] != '\0') {
|
||||
entry.name[nameLen] = path[nameLen];
|
||||
nameLen++;
|
||||
}
|
||||
// Add trailing slash
|
||||
entry.name[nameLen++] = '/';
|
||||
entry.name[nameLen] = '\0';
|
||||
|
||||
entry.data = nullptr;
|
||||
entry.size = 0;
|
||||
entry.capacity = 0;
|
||||
entry.isDirectory = true;
|
||||
entry.heapAllocated = false;
|
||||
|
||||
fileCount++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetFileCount() {
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ namespace Fs::Ramdisk {
|
||||
void Close(int handle);
|
||||
|
||||
int ReadDir(const char* path, const char** outNames, int maxEntries);
|
||||
int Delete(const char* path);
|
||||
int Mkdir(const char* path);
|
||||
int GetFileCount();
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -199,8 +199,8 @@ extern "C" void kmain() {
|
||||
Fs::Ramdisk::ReadDir,
|
||||
Fs::Ramdisk::Write,
|
||||
Fs::Ramdisk::Create,
|
||||
nullptr,
|
||||
nullptr
|
||||
Fs::Ramdisk::Delete,
|
||||
Fs::Ramdisk::Mkdir
|
||||
};
|
||||
Fs::Vfs::RegisterDrive(0, &ramdiskDriver);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace Memory {
|
||||
|
||||
void* PageFrameAllocator::AllocateZeroed() {
|
||||
auto page = Allocate();
|
||||
if (page == nullptr) return nullptr;
|
||||
memset(page, 0, 0x1000);
|
||||
|
||||
return page;
|
||||
|
||||
@@ -171,7 +171,9 @@ namespace Net::Dns {
|
||||
// Compression pointer
|
||||
if (offset + 1 >= packetLen) return -1;
|
||||
if (!jumped) returnOffset = offset + 2;
|
||||
offset = ((len & 0x3F) << 8) | packet[offset + 1];
|
||||
int target = ((len & 0x3F) << 8) | packet[offset + 1];
|
||||
if (target >= packetLen) return -1; // Pointer beyond packet bounds
|
||||
offset = target;
|
||||
jumped = true;
|
||||
maxJumps--;
|
||||
continue;
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Net::Ipv4 {
|
||||
}
|
||||
|
||||
uint16_t totalLen = Ntohs(hdr->TotalLength);
|
||||
if (totalLen > length) {
|
||||
if (totalLen < ihl || totalLen > length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,9 @@ namespace Sched {
|
||||
// Load ELF into the process's address space
|
||||
uint64_t entry = ElfLoad(vfsPath, pml4Phys);
|
||||
if (entry == 0) {
|
||||
// Free the PML4 and any pages allocated during ELF load
|
||||
Memory::VMM::Paging::FreeUserHalf(pml4Phys);
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pml4Phys));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -127,18 +130,29 @@ namespace Sched {
|
||||
void* firstPage = Memory::g_pfa->AllocateZeroed();
|
||||
if (firstPage == nullptr) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched") << "Out of memory for kernel stack";
|
||||
Memory::VMM::Paging::FreeUserHalf(pml4Phys);
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pml4Phys));
|
||||
return -1;
|
||||
}
|
||||
void* stackMem = Memory::g_pfa->ReallocConsecutive(firstPage, StackPages);
|
||||
if (stackMem == nullptr) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched") << "Failed to allocate contiguous kernel stack";
|
||||
Memory::g_pfa->Free(firstPage);
|
||||
Memory::VMM::Paging::FreeUserHalf(pml4Phys);
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pml4Phys));
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t* kernelStackBase = (uint8_t*)stackMem;
|
||||
uint64_t kernelStackTop = (uint64_t)kernelStackBase + StackSize;
|
||||
|
||||
// Helper to clean up all resources allocated so far on failure
|
||||
auto cleanupOnFail = [&]() {
|
||||
Memory::VMM::Paging::FreeUserHalf(pml4Phys);
|
||||
Memory::g_pfa->Free((void*)Memory::HHDM(pml4Phys));
|
||||
Memory::g_pfa->Free(stackMem, StackPages);
|
||||
};
|
||||
|
||||
// Allocate user stack pages and map them in the process PML4
|
||||
uint64_t userStackBase = UserStackTop - UserStackSize;
|
||||
uint64_t topStackPagePhys = 0;
|
||||
@@ -146,11 +160,14 @@ namespace Sched {
|
||||
void* page = Memory::g_pfa->AllocateZeroed();
|
||||
if (page == nullptr) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched") << "Out of memory for user stack";
|
||||
cleanupOnFail();
|
||||
return -1;
|
||||
}
|
||||
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
|
||||
if (!Memory::VMM::Paging::MapUserIn(pml4Phys, physAddr, userStackBase + i * 0x1000)) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched") << "Failed to map user stack page";
|
||||
Memory::g_pfa->Free(page);
|
||||
cleanupOnFail();
|
||||
return -1;
|
||||
}
|
||||
if (i == UserStackPages - 1) topStackPagePhys = physAddr;
|
||||
@@ -162,11 +179,14 @@ namespace Sched {
|
||||
void* stubPage = Memory::g_pfa->AllocateZeroed();
|
||||
if (stubPage == nullptr) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched") << "Out of memory for exit stub";
|
||||
cleanupOnFail();
|
||||
return -1;
|
||||
}
|
||||
uint64_t stubPhys = Memory::SubHHDM((uint64_t)stubPage);
|
||||
if (!Memory::VMM::Paging::MapUserIn(pml4Phys, stubPhys, ExitStubAddr)) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched") << "Failed to map exit stub";
|
||||
Memory::g_pfa->Free(stubPage);
|
||||
cleanupOnFail();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -291,19 +311,26 @@ namespace Sched {
|
||||
oldRspPtr = &idleSavedRsp;
|
||||
}
|
||||
|
||||
int oldPid = currentPid;
|
||||
currentPid = next;
|
||||
processTable[next].state = ProcessState::Running;
|
||||
processTable[next].sliceRemaining = TimeSliceMs;
|
||||
|
||||
uint64_t newCR3 = processTable[next].pml4Phys;
|
||||
|
||||
// Disable interrupts while updating global kernel RSP and TSS,
|
||||
// preventing an interrupt from using stale values mid-update.
|
||||
asm volatile("cli");
|
||||
|
||||
// Update kernel RSP for SYSCALL entry
|
||||
g_kernelRsp = processTable[next].kernelStackTop;
|
||||
|
||||
// Update TSS RSP0 for hardware interrupts from ring 3
|
||||
Hal::g_tss.rsp0 = processTable[next].kernelStackTop;
|
||||
|
||||
uint8_t* oldFpu = (currentPid >= 0) ? processTable[currentPid].fpuState : nullptr;
|
||||
asm volatile("sti");
|
||||
|
||||
uint8_t* oldFpu = (oldPid >= 0) ? processTable[oldPid].fpuState : nullptr;
|
||||
uint8_t* newFpu = processTable[next].fpuState;
|
||||
SchedContextSwitch(oldRspPtr, processTable[next].savedRsp, newCR3, oldFpu, newFpu);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user