fix: kernel concurrency, interrupt context, and user VA safety

This commit is contained in:
daniel committed 2026-08-01 15:43:38 +02:00
1 parent f222bf1f04
commit b1c55073c7
71 files changed
+2654 -1092

No files matched your search

+6
View File
@@ -9,6 +9,9 @@
#include <Drivers/USB/Bluetooth/Bluetooth.hpp>
#include <Drivers/USB/Bluetooth/Hci.hpp>
#include <Libraries/Memory.hpp>
#include <Sched/Scheduler.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include "Syscall.hpp"
@@ -53,6 +56,9 @@ namespace montauk::abi {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid()
<< " entered Bluetooth disconnect stage";
return (int64_t)Drivers::USB::Bluetooth::Disconnect(bdAddr);
}
+1 -1
View File
@@ -12,4 +12,4 @@
#pragma once
#define MONTAUK_BUILD_NUMBER 33
#define MONTAUK_BUILD_NUMBER 37
+18 -29
View File
@@ -14,59 +14,47 @@ namespace montauk::abi {
}
static bool ResolveProcessHandle(Sched::Process* proc, int handle, Ipc::HandleType expectedType,
Ipc::Object*& outObject, uint32_t* outRights = nullptr) {
Ipc::HandleSnapshot& snapshot) {
if (proc == nullptr || handle < 0) return false;
int slot = Ipc::SlotForPid(proc->pid);
if (slot < 0) return false;
Ipc::HandleType type = Ipc::HandleType::None;
Ipc::Object* object = nullptr;
uint32_t rights = 0;
if (!Ipc::SnapshotHandleForSlot(slot, handle, type, object, rights)) return false;
if (type != expectedType || object == nullptr) return false;
outObject = object;
if (outRights != nullptr) *outRights = rights;
return true;
if (!snapshot.Capture(slot, handle)) return false;
return snapshot.type == expectedType && snapshot.object != nullptr;
}
static Ipc::Stream* GetRedirOutStream(Sched::Process* proc) {
static Ipc::Stream* GetRedirOutStream(Sched::Process* proc, Ipc::HandleSnapshot& snapshot) {
proc = GetRedirTarget(proc);
if (proc == nullptr) return nullptr;
Ipc::Object* object = nullptr;
if (!ResolveProcessHandle(proc, proc->ioOutHandle, Ipc::HandleType::Stream, object)) return nullptr;
return (Ipc::Stream*)object;
if (!ResolveProcessHandle(proc, proc->ioOutHandle, Ipc::HandleType::Stream, snapshot)) return nullptr;
return (Ipc::Stream*)snapshot.object;
}
static Ipc::Stream* GetRedirInStream(Sched::Process* proc) {
static Ipc::Stream* GetRedirInStream(Sched::Process* proc, Ipc::HandleSnapshot& snapshot) {
proc = GetRedirTarget(proc);
if (proc == nullptr) return nullptr;
Ipc::Object* object = nullptr;
if (!ResolveProcessHandle(proc, proc->ioInHandle, Ipc::HandleType::Stream, object)) return nullptr;
return (Ipc::Stream*)object;
if (!ResolveProcessHandle(proc, proc->ioInHandle, Ipc::HandleType::Stream, snapshot)) return nullptr;
return (Ipc::Stream*)snapshot.object;
}
static Ipc::Mailbox* GetRedirKeyMailbox(Sched::Process* proc) {
static Ipc::Mailbox* GetRedirKeyMailbox(Sched::Process* proc, Ipc::HandleSnapshot& snapshot) {
proc = GetRedirTarget(proc);
if (proc == nullptr) return nullptr;
Ipc::Object* object = nullptr;
if (!ResolveProcessHandle(proc, proc->ioKeyHandle, Ipc::HandleType::Mailbox, object)) return nullptr;
return (Ipc::Mailbox*)object;
if (!ResolveProcessHandle(proc, proc->ioKeyHandle, Ipc::HandleType::Mailbox, snapshot)) return nullptr;
return (Ipc::Mailbox*)snapshot.object;
}
static int DuplicateHandleBetweenSlots(int srcSlot, int handle, int dstSlot) {
if (srcSlot < 0 || dstSlot < 0 || handle < 0) return -1;
Ipc::HandleType type = Ipc::HandleType::None;
Ipc::Object* object = nullptr;
uint32_t rights = 0;
if (!Ipc::SnapshotHandleForSlot(srcSlot, handle, type, object, rights)) return -1;
if ((rights & Ipc::RightDup) == 0) return -1;
return Ipc::InstallHandleForSlot(dstSlot, object, type, rights);
Ipc::HandleSnapshot snapshot;
if (!snapshot.Capture(srcSlot, handle)) return -1;
if ((snapshot.rights & Ipc::RightDup) == 0) return -1;
return Ipc::InstallHandleForSlot(dstSlot, snapshot.object, snapshot.type, snapshot.rights);
}
static bool ConfigureRedirWaitsetForSlot(int slot, Sched::Process* proc) {
@@ -100,12 +88,13 @@ namespace montauk::abi {
int total = 0;
while (total < len) {
uint64_t observedWake = Sched::ObserveObjectWake(stream);
int written = Ipc::StreamWrite(stream, data + total, len - total, false);
if (written < 0) {
return (total > 0) ? total : -1;
}
if (written == 0) {
Sched::BlockOnObject(stream, 0);
Sched::BlockOnObjectSince(stream, 0, observedWake);
continue;
}
total += written;
+40 -8
View File
@@ -36,8 +36,17 @@ namespace montauk::abi {
if (fbBase == nullptr) return 0;
uint64_t fbPhys = Memory::SubHHDM((uint64_t)fbBase);
uint64_t fbSize = Graphics::Framebuffer::GetHeight()
* Graphics::Framebuffer::GetPitch();
uint64_t width = Graphics::Framebuffer::GetWidth();
uint64_t height = Graphics::Framebuffer::GetHeight();
uint64_t pitch = Graphics::Framebuffer::GetPitch();
if (width == 0 || height == 0 || pitch == 0
|| width > (~0ULL / 4) || pitch < width * 4
|| height > (~0ULL / pitch)) {
Kt::KernelLogStream(Kt::ERROR, "FbMap")
<< "Invalid or overflowing framebuffer geometry";
return 0;
}
uint64_t fbSize = height * pitch;
uint64_t numPages = (fbSize + 0xFFF) / 0x1000;
Kt::KernelLogStream(Kt::INFO, "FbMap") << "fbPhys=" << kcp::hex << fbPhys
@@ -47,8 +56,28 @@ namespace montauk::abi {
<< "x" << Graphics::Framebuffer::GetHeight()
<< " pitch=" << Graphics::Framebuffer::GetPitch() << ")";
// Map at a fixed user VA
constexpr uint64_t userVa = 0x50000000ULL;
// Map in the dedicated framebuffer arena, away from the heap,
// shared libraries, reusable IPC surfaces, and the user stack.
constexpr uint64_t userVa = Sched::UserFramebufferBase;
uint64_t mappedBytes = numPages * 0x1000ULL;
bool flipSupported = Drivers::Graphics::IntelGPU::FlipSupported();
uint64_t buffers = flipSupported ? 2 : 1;
if (mappedBytes > (Sched::UserFramebufferLimit - userVa) / buffers) {
Kt::KernelLogStream(Kt::ERROR, "FbMap")
<< "Framebuffer mappings exceed reserved user VA range";
return 0;
}
// Never expose more of buffer 1 than the GPU driver allocated. This
// independently contains a future geometry-contract regression before
// any partial framebuffer mapping is installed in the process.
if (flipSupported
&& (Drivers::Graphics::IntelGPU::GetBufferPhys(1) == 0
|| Drivers::Graphics::IntelGPU::GetBufferPageCount(1) < numPages)) {
Kt::KernelLogStream(Kt::ERROR, "FbMap")
<< "Page-flip buffer is smaller than firmware framebuffer";
return 0;
}
for (uint64_t i = 0; i < numPages; i++) {
if (!Memory::VMM::Paging::MapUserInWC(
@@ -63,7 +92,7 @@ namespace montauk::abi {
// When page flipping is available, map the second scanout buffer
// immediately after the first so a double-buffered client can reach
// both. Single-buffer clients never touch the extra pages.
if (Drivers::Graphics::IntelGPU::FlipSupported()) {
if (flipSupported) {
uint64_t buf1Phys = Drivers::Graphics::IntelGPU::GetBufferPhys(1);
for (uint64_t i = 0; i < numPages; i++) {
if (!Memory::VMM::Paging::MapUserInWC(
@@ -82,6 +111,7 @@ namespace montauk::abi {
// SYS_FBFLIP: point scanout at buffer `index` (0 or 1). The hardware
// latches the new surface at vblank, so the flip is tear-free.
// index == -1 queries support without side effects.
// index == -2 acquires flip ownership and returns the live front buffer.
static int64_t Sys_FbFlip(uint64_t index, uint64_t flags) {
namespace GPU = Drivers::Graphics::IntelGPU;
@@ -91,9 +121,11 @@ namespace montauk::abi {
if (!GPU::FlipSupported()) return -1;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc != nullptr) GPU::SetFlipOwner(proc->pid);
return GPU::Flip((int)index, (flags & 1) != 0);
if ((int64_t)index == -2) {
return proc != nullptr ? GPU::AcquireFlip(proc->pid) : -1;
}
if (proc == nullptr) return -1;
return GPU::Flip((int)index, (flags & 1) != 0, proc->pid);
}
static int64_t Sys_DisplayInfo(DisplayInfo* out) {
+32 -35
View File
@@ -9,6 +9,8 @@
#include <Memory/Paging.hpp>
#include <Memory/HHDM.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include <CppLib/Spinlock.hpp>
#include <Ipc/Ipc.hpp>
namespace montauk::abi {
@@ -22,6 +24,7 @@ namespace montauk::abi {
inline HeapAlloc g_heapAllocs[Sched::MaxProcesses][MaxHeapAllocs] = {};
inline int g_heapAllocCount[Sched::MaxProcesses] = {};
inline kcp::Mutex g_heapLocks[Sched::MaxProcesses];
// Get the process table slot index for the current process
inline int GetCurrentSlot() {
@@ -38,20 +41,15 @@ namespace montauk::abi {
int slot = GetCurrentSlot();
if (slot < 0) return 0;
// Guard against overflow before rounding
static constexpr uint64_t USER_SPACE_END = 0x0000800000000000ULL;
// Guard against overflow before rounding.
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;
g_heapLocks[slot].Acquire();
if (g_heapAllocCount[slot] >= MaxHeapAllocs) {
// Out of allocation records, not out of memory. Log it: a
// silent 0 here surfaced as bogus downstream errors (BFD
@@ -60,6 +58,16 @@ namespace montauk::abi {
<< "pid " << proc->pid << " (" << proc->name
<< ") hit MaxHeapAllocs (" << (uint64_t)MaxHeapAllocs
<< "), SYS_ALLOC refused";
g_heapLocks[slot].Release();
return 0;
}
uint64_t userVa = 0;
if (!Sched::ReserveUserHeapRange(slot, size, userVa)) {
Kt::KernelLogStream(Kt::ERROR, "Heap")
<< "pid " << proc->pid << " (" << proc->name
<< ") exhausted bounded user heap";
g_heapLocks[slot].Release();
return 0;
}
@@ -68,38 +76,25 @@ namespace montauk::abi {
for (uint64_t i = 0; i < numPages; i++) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) {
for (uint64_t j = 0; j < mappedPages; j++) {
uint64_t pageVa = userVa + j * 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);
}
Ipc::UnmapAndFreeUserRange(proc->pml4Phys, userVa, mappedPages);
g_heapLocks[slot].Release();
return 0;
}
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
if (!Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa + i * 0x1000)) {
Memory::g_pfa->Free(page);
for (uint64_t j = 0; j < mappedPages; j++) {
uint64_t pageVa = userVa + j * 0x1000;
uint64_t mappedPhys = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, pageVa);
if (mappedPhys != 0) {
Memory::g_pfa->Free((void*)Memory::HHDM(mappedPhys));
}
Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, pageVa);
}
Ipc::UnmapAndFreeUserRange(proc->pml4Phys, userVa, mappedPages);
g_heapLocks[slot].Release();
return 0;
}
mappedPages++;
}
proc->heapNext += size;
// Track the allocation so Sys_Free can release it
Sched::g_allocatedPages[slot] += numPages;
g_heapAllocs[slot][g_heapAllocCount[slot]++] = { userVa, numPages };
g_heapLocks[slot].Release();
return userVa;
}
@@ -107,8 +102,10 @@ namespace montauk::abi {
// The actual physical pages are freed by Paging::FreeUserHalf() during process cleanup.
inline void CleanupHeapForSlot(int slot, uint64_t /*pml4Phys*/) {
if (slot < 0 || slot >= Sched::MaxProcesses) return;
g_heapLocks[slot].Acquire();
g_heapAllocCount[slot] = 0;
Sched::g_allocatedPages[slot] = 0;
g_heapLocks[slot].Release();
}
inline void Sys_Free(uint64_t addr) {
@@ -118,6 +115,8 @@ namespace montauk::abi {
int slot = GetCurrentSlot();
if (slot < 0) return;
g_heapLocks[slot].Acquire();
// Find the allocation record matching this address
int idx = -1;
for (int i = 0; i < g_heapAllocCount[slot]; i++) {
@@ -126,25 +125,23 @@ namespace montauk::abi {
break;
}
}
if (idx < 0) return; // Unknown address — ignore
if (idx < 0) {
g_heapLocks[slot].Release();
return; // Unknown address — ignore
}
uint64_t va = g_heapAllocs[slot][idx].va;
uint64_t numPages = g_heapAllocs[slot][idx].numPages;
// Free physical pages in bulk and unmap virtual addresses
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);
}
// Unmap and invalidate sibling CPUs before recycling the frames. A
// stale user TLB entry can otherwise corrupt the frame's next owner.
Ipc::UnmapAndFreeUserRange(proc->pml4Phys, va, numPages);
Sched::g_allocatedPages[slot] -= numPages;
// Remove tracking entry by swapping with the last element
g_heapAllocs[slot][idx] = g_heapAllocs[slot][g_heapAllocCount[slot] - 1];
g_heapAllocCount[slot]--;
g_heapLocks[slot].Release();
}
};
+8 -4
View File
@@ -85,14 +85,16 @@ namespace montauk::abi {
static int Sys_ChildIoRead(int childPid, char* buf, int maxLen) {
auto* child = Sched::GetProcessByPid(childPid);
Ipc::Stream* stream = GetRedirOutStream(child);
Ipc::HandleSnapshot snapshot;
Ipc::Stream* stream = GetRedirOutStream(child, snapshot);
if (child == nullptr || !child->redirected || stream == nullptr) return -1;
return Ipc::StreamRead(stream, (uint8_t*)buf, maxLen, true);
}
static int Sys_ChildIoWrite(int childPid, const char* data, int len) {
auto* child = Sched::GetProcessByPid(childPid);
Ipc::Stream* stream = GetRedirInStream(child);
Ipc::HandleSnapshot snapshot;
Ipc::Stream* stream = GetRedirInStream(child, snapshot);
if (child == nullptr || !child->redirected || stream == nullptr) return -1;
return WriteAllToStream(stream, (const uint8_t*)data, len);
}
@@ -100,14 +102,16 @@ namespace montauk::abi {
static int Sys_ChildIoWriteKey(int childPid, const KeyEvent* key) {
if (key == nullptr) return -1;
auto* child = Sched::GetProcessByPid(childPid);
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(child);
Ipc::HandleSnapshot snapshot;
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(child, snapshot);
if (child == nullptr || !child->redirected || mailbox == nullptr) return -1;
for (;;) {
uint64_t observedWake = Sched::ObserveObjectWake(mailbox);
int rc = Ipc::MailboxSend(mailbox, 0, key, sizeof(KeyEvent));
if (rc < 0) return -1;
if (rc == 0) {
Sched::BlockOnObject(mailbox, 0);
Sched::BlockOnObjectSince(mailbox, 0, observedWake);
continue;
}
return 0;
+14 -7
View File
@@ -15,7 +15,8 @@ namespace montauk::abi {
static bool Sys_IsKeyAvailable() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(proc);
Ipc::HandleSnapshot snapshot;
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(proc, snapshot);
if (mailbox != nullptr) return Ipc::MailboxHasMessage(mailbox);
}
return Drivers::PS2::Keyboard::IsKeyAvailable();
@@ -25,9 +26,11 @@ namespace montauk::abi {
if (outEvent == nullptr) return;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(proc);
Ipc::HandleSnapshot snapshot;
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(proc, snapshot);
if (mailbox != nullptr) {
for (;;) {
uint64_t observedWake = Sched::ObserveObjectWake(mailbox);
uint16_t len = sizeof(KeyEvent);
int rc = Ipc::MailboxRecv(mailbox, nullptr, outEvent, &len, true);
if (rc > 0) return;
@@ -35,7 +38,7 @@ namespace montauk::abi {
memset(outEvent, 0, sizeof(KeyEvent));
return;
}
Sched::BlockOnObject(mailbox, 0);
Sched::BlockOnObjectSince(mailbox, 0, observedWake);
}
}
}
@@ -51,10 +54,14 @@ namespace montauk::abi {
static char Sys_GetChar() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
Ipc::Stream* input = GetRedirInStream(proc);
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(proc);
Ipc::HandleSnapshot inputSnapshot;
Ipc::HandleSnapshot mailboxSnapshot;
Ipc::Stream* input = GetRedirInStream(proc, inputSnapshot);
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(proc, mailboxSnapshot);
if (input != nullptr || mailbox != nullptr) {
for (;;) {
uint64_t inputWake = input ? Sched::ObserveObjectWake(input) : 0;
uint64_t mailboxWake = mailbox ? Sched::ObserveObjectWake(mailbox) : 0;
if (input != nullptr) {
uint8_t c = 0;
int rc = Ipc::StreamRead(input, &c, 1, true);
@@ -79,9 +86,9 @@ namespace montauk::abi {
return 0;
}
} else if (input != nullptr) {
Sched::BlockOnObject(input, 0);
Sched::BlockOnObjectSince(input, 0, inputWake);
} else if (mailbox != nullptr) {
Sched::BlockOnObject(mailbox, 0);
Sched::BlockOnObjectSince(mailbox, 0, mailboxWake);
} else {
return 0;
}
+39 -19
View File
@@ -13,6 +13,8 @@
#include <Terminal/Terminal.hpp>
#include <Libraries/Memory.hpp>
#include <Libraries/String.hpp>
#include <CppLib/Spinlock.hpp>
#include <Ipc/Ipc.hpp>
namespace montauk::abi {
@@ -34,16 +36,19 @@ namespace montauk::abi {
// Per-process library table
inline LibEntry g_libTable[MaxProcesses][MaxLibsPerProcess] = {};
inline kcp::Mutex g_libLocks[MaxProcesses];
// Initialize library table for a process slot
inline void InitLibTable(int slot) {
if (slot < 0 || slot >= MaxProcesses) return;
g_libLocks[slot].Acquire();
for (int i = 0; i < MaxLibsPerProcess; i++) {
g_libTable[slot][i].inUse = false;
g_libTable[slot][i].refcount = 0;
g_libTable[slot][i].loadBias = 0;
g_libTable[slot][i].path[0] = '\0';
}
g_libLocks[slot].Release();
}
// Load a shared library into the current process's address space.
@@ -61,6 +66,8 @@ namespace montauk::abi {
size_t pathLen = Lib::strlen(path);
if (pathLen == 0 || pathLen >= sizeof(LibEntry::path)) return 0;
g_libLocks[slot].Acquire();
// Find a free slot or reuse an existing slot with the same path
int libSlot = -1;
for (int i = 0; i < MaxLibsPerProcess; i++) {
@@ -68,6 +75,7 @@ namespace montauk::abi {
if (Lib::strncmp(g_libTable[slot][i].path, path, sizeof(LibEntry::path)) == 0) {
// Same library already loaded - just increment refcount
g_libTable[slot][i].refcount++;
g_libLocks[slot].Release();
return (uint64_t)(i + 1); // Handle = slot + 1 (0 = invalid)
}
} else if (libSlot < 0) {
@@ -77,6 +85,7 @@ namespace montauk::abi {
if (libSlot < 0) {
Kt::KernelLogStream(Kt::ERROR, "Lib") << "No free library slots";
g_libLocks[slot].Release();
return 0;
}
@@ -84,6 +93,7 @@ namespace montauk::abi {
uint64_t loadBias = Sched::ElfLoadLib(path, proc->pml4Phys, libSlot);
if (loadBias == 0) {
Kt::KernelLogStream(Kt::ERROR, "Lib") << "Failed to load library: " << path;
g_libLocks[slot].Release();
return 0;
}
@@ -93,6 +103,8 @@ namespace montauk::abi {
g_libTable[slot][libSlot].loadBias = loadBias;
Lib::strncpy(g_libTable[slot][libSlot].path, path, sizeof(LibEntry::path));
g_libLocks[slot].Release();
Kt::KernelLogStream(Kt::OK, "Lib") << "Loaded library: " << path << " with load bias " << kcp::hex << loadBias << kcp::dec;
return (uint64_t)(libSlot + 1); // Handle = slot + 1 (0 = invalid)
@@ -107,7 +119,11 @@ namespace montauk::abi {
int libSlot = (int)handle - 1;
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return -1;
if (!g_libTable[slot][libSlot].inUse) return -1;
g_libLocks[slot].Acquire();
if (!g_libTable[slot][libSlot].inUse) {
g_libLocks[slot].Release();
return -1;
}
g_libTable[slot][libSlot].refcount--;
if (g_libTable[slot][libSlot].refcount == 0) {
@@ -117,14 +133,8 @@ namespace montauk::abi {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc != nullptr) {
// Unmap all pages in the library region
for (uint64_t va = libBase; va < libEnd; va += 0x1000) {
uint64_t physAddr = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, va);
if (physAddr != 0) {
Memory::g_pfa->Free((void*)Memory::HHDM(physAddr));
Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, va);
}
}
Ipc::UnmapAndFreeUserRange(proc->pml4Phys, libBase,
(libEnd - libBase) / 0x1000ULL);
}
g_libTable[slot][libSlot].inUse = false;
@@ -132,6 +142,7 @@ namespace montauk::abi {
g_libTable[slot][libSlot].path[0] = '\0';
}
g_libLocks[slot].Release();
return 0;
}
@@ -146,9 +157,14 @@ namespace montauk::abi {
int libSlot = (int)handle - 1;
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return 0;
if (!g_libTable[slot][libSlot].inUse) return 0;
g_libLocks[slot].Acquire();
if (!g_libTable[slot][libSlot].inUse) {
g_libLocks[slot].Release();
return 0;
}
uint64_t loadBias = g_libTable[slot][libSlot].loadBias;
g_libLocks[slot].Release();
return loadBias + symbolOffset;
}
@@ -160,9 +176,15 @@ namespace montauk::abi {
int libSlot = (int)handle - 1;
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return 0;
if (!g_libTable[slot][libSlot].inUse) return 0;
g_libLocks[slot].Acquire();
if (!g_libTable[slot][libSlot].inUse) {
g_libLocks[slot].Release();
return 0;
}
return g_libTable[slot][libSlot].loadBias;
uint64_t loadBias = g_libTable[slot][libSlot].loadBias;
g_libLocks[slot].Release();
return loadBias;
}
// Cleanup library table for a process slot
@@ -172,25 +194,23 @@ namespace montauk::abi {
auto* proc = Sched::GetProcessSlot(slot);
if (proc == nullptr) return;
g_libLocks[slot].Acquire();
// Unmap all libraries for this process
for (int i = 0; i < MaxLibsPerProcess; i++) {
if (g_libTable[slot][i].inUse) {
uint64_t libBase = GetLibSlotBase(i);
uint64_t libEnd = libBase + Sched::LIB_MAX_SIZE;
for (uint64_t va = libBase; va < libEnd; va += 0x1000) {
uint64_t physAddr = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, va);
if (physAddr != 0) {
Memory::g_pfa->Free((void*)Memory::HHDM(physAddr));
Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, va);
}
}
Ipc::UnmapAndFreeUserRange(proc->pml4Phys, libBase,
(libEnd - libBase) / 0x1000ULL);
g_libTable[slot][i].inUse = false;
g_libTable[slot][i].refcount = 0;
g_libTable[slot][i].loadBias = 0;
}
}
g_libLocks[slot].Release();
}
}
+13
View File
@@ -14,6 +14,9 @@
#include <ACPI/AcpiSleep.hpp>
#include <ACPI/CpuIdle.hpp>
#include <Hal/CpuPower.hpp>
#include <Sched/Scheduler.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include "Syscall.hpp"
@@ -31,13 +34,21 @@ namespace montauk::abi {
if (action == POWER_REQ_QUERY) {
int pending = g_pendingPowerAction;
g_pendingPowerAction = POWER_REQ_QUERY;
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid()
<< " consumed graceful power request " << (uint64_t)pending;
return (int64_t)pending;
}
g_pendingPowerAction = action;
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid()
<< " posted graceful power request " << (uint64_t)action;
return 0;
}
static void Sys_Reset() {
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid() << " entered final reboot stage";
if (Efi::g_ResetSystem) {
/* Switch to kernel PML4 which has identity-mapped UEFI runtime regions */
Memory::VMM::LoadCR3(Memory::VMM::g_paging->PML4);
@@ -51,6 +62,8 @@ namespace montauk::abi {
}
static void Sys_Shutdown() {
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid() << " entered final shutdown stage";
/* Primary: ACPI S5 shutdown via PM1 control registers */
if (Hal::AcpiShutdown::IsAvailable()) {
Hal::AcpiShutdown::Shutdown();
+6
View File
@@ -12,6 +12,9 @@
#include <Fs/Fat32.hpp>
#include <Fs/Ext2.hpp>
#include <Api/UserMemory.hpp>
#include <Sched/Scheduler.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include "Syscall.hpp"
@@ -112,6 +115,9 @@ namespace montauk::abi {
// Flush all block-device write caches and cleanly unmount disk-backed
// volumes ahead of power-off. Returns the number of volumes unmounted.
static int64_t Sys_FsSync() {
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid()
<< " entered filesystem sync stage";
return (int64_t)Fs::FsProbe::SyncAndUnmountAll();
}
+4 -2
View File
@@ -15,7 +15,8 @@ namespace montauk::abi {
static void Sys_Print(const char* text) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
Ipc::Stream* stream = GetRedirOutStream(proc);
Ipc::HandleSnapshot snapshot;
Ipc::Stream* stream = GetRedirOutStream(proc, snapshot);
if (stream != nullptr) {
int len = 0;
while (text[len]) len++;
@@ -33,7 +34,8 @@ namespace montauk::abi {
static void Sys_Putchar(char c) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
Ipc::Stream* stream = GetRedirOutStream(proc);
Ipc::HandleSnapshot snapshot;
Ipc::Stream* stream = GetRedirOutStream(proc, snapshot);
if (stream != nullptr) {
uint8_t byte = (uint8_t)c;
WriteAllToStream(stream, &byte, 1);