wip: shared library support
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* LibSyscall.hpp
|
||||
* SYS_LOAD_LIB, SYS_UNLOAD_LIB, SYS_DLSYM syscalls
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <Sched/Scheduler.hpp>
|
||||
#include <Sched/ElfLoader.hpp>
|
||||
#include <Memory/Paging.hpp>
|
||||
#include <Memory/HHDM.hpp>
|
||||
#include <Memory/PageFrameAllocator.hpp>
|
||||
#include <Terminal/Terminal.hpp>
|
||||
#include <Libraries/Memory.hpp>
|
||||
#include <Libraries/String.hpp>
|
||||
|
||||
namespace Montauk {
|
||||
|
||||
// Maximum libraries per process
|
||||
static constexpr int MaxLibsPerProcess = 8;
|
||||
static constexpr int MaxProcesses = 64;
|
||||
|
||||
// Library entry tracking
|
||||
struct LibEntry {
|
||||
char path[128];
|
||||
uint64_t baseAddr;
|
||||
uint32_t refcount;
|
||||
bool inUse;
|
||||
};
|
||||
|
||||
// Per-process library table
|
||||
static LibEntry g_libTable[MaxProcesses][MaxLibsPerProcess];
|
||||
|
||||
// Initialize library table for a process slot
|
||||
static void InitLibTable(int slot) {
|
||||
if (slot < 0 || slot >= MaxProcesses) return;
|
||||
for (int i = 0; i < MaxLibsPerProcess; i++) {
|
||||
g_libTable[slot][i].inUse = false;
|
||||
g_libTable[slot][i].refcount = 0;
|
||||
g_libTable[slot][i].baseAddr = 0;
|
||||
g_libTable[slot][i].path[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Load a shared library into the current process's address space.
|
||||
// Returns a library handle (slot index + 1) on success, or 0 on failure.
|
||||
// The library is loaded at a fixed address based on the slot.
|
||||
static uint64_t Sys_LoadLib(const char* path) {
|
||||
int slot = GetCurrentSlot();
|
||||
if (slot < 0) return 0;
|
||||
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (proc == nullptr) return 0;
|
||||
|
||||
// Validate path
|
||||
if (path == nullptr) return 0;
|
||||
size_t pathLen = Lib::strlen(path);
|
||||
if (pathLen == 0 || pathLen >= sizeof(LibEntry::path)) return 0;
|
||||
|
||||
// Find a free slot or reuse an existing slot with the same path
|
||||
int libSlot = -1;
|
||||
for (int i = 0; i < MaxLibsPerProcess; i++) {
|
||||
if (g_libTable[slot][i].inUse) {
|
||||
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++;
|
||||
return (uint64_t)(i + 1); // Handle = slot + 1 (0 = invalid)
|
||||
}
|
||||
} else if (libSlot < 0) {
|
||||
libSlot = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (libSlot < 0) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Lib") << "No free library slots";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load the library into the process's address space
|
||||
uint64_t libBase = Sched::ElfLoadLib(path, proc->pml4Phys, libSlot);
|
||||
if (libBase == 0) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "Lib") << "Failed to load library: " << path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Store library info
|
||||
g_libTable[slot][libSlot].inUse = true;
|
||||
g_libTable[slot][libSlot].refcount = 1;
|
||||
g_libTable[slot][libSlot].baseAddr = libBase;
|
||||
Lib::strncpy(g_libTable[slot][libSlot].path, path, sizeof(LibEntry::path));
|
||||
|
||||
Kt::KernelLogStream(Kt::OK, "Lib") << "Loaded library: " << path << " at base " << kcp::hex << libBase << kcp::dec;
|
||||
|
||||
return (uint64_t)(libSlot + 1); // Handle = slot + 1 (0 = invalid)
|
||||
}
|
||||
|
||||
// Unload a shared library.
|
||||
// Decrements refcount; actually unmaps when refcount reaches 0.
|
||||
static int Sys_UnloadLib(uint64_t handle) {
|
||||
int slot = GetCurrentSlot();
|
||||
if (slot < 0) return -1;
|
||||
|
||||
int libSlot = (int)handle - 1;
|
||||
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return -1;
|
||||
|
||||
if (!g_libTable[slot][libSlot].inUse) return -1;
|
||||
|
||||
g_libTable[slot][libSlot].refcount--;
|
||||
if (g_libTable[slot][libSlot].refcount == 0) {
|
||||
// Actually unload - free the pages
|
||||
uint64_t libBase = g_libTable[slot][libSlot].baseAddr;
|
||||
uint64_t libEnd = libBase + Sched::LIB_MAX_SIZE;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_libTable[slot][libSlot].inUse = false;
|
||||
g_libTable[slot][libSlot].baseAddr = 0;
|
||||
g_libTable[slot][libSlot].path[0] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Resolve a symbol in a loaded library.
|
||||
// handle = library handle from LoadLib
|
||||
// symbolOffset = offset of the symbol from the library's base address
|
||||
// Returns the virtual address of the symbol, or 0 if not found.
|
||||
static uint64_t Sys_DLSym(uint64_t handle, uint64_t symbolOffset) {
|
||||
int slot = GetCurrentSlot();
|
||||
if (slot < 0) return 0;
|
||||
|
||||
int libSlot = (int)handle - 1;
|
||||
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return 0;
|
||||
|
||||
if (!g_libTable[slot][libSlot].inUse) return 0;
|
||||
|
||||
uint64_t libBase = g_libTable[slot][libSlot].baseAddr;
|
||||
return libBase + symbolOffset;
|
||||
}
|
||||
|
||||
// Get library base address (for userspace symbol resolution)
|
||||
static uint64_t Sys_GetLibBase(uint64_t handle) {
|
||||
int slot = GetCurrentSlot();
|
||||
if (slot < 0) return 0;
|
||||
|
||||
int libSlot = (int)handle - 1;
|
||||
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return 0;
|
||||
|
||||
if (!g_libTable[slot][libSlot].inUse) return 0;
|
||||
|
||||
return g_libTable[slot][libSlot].baseAddr;
|
||||
}
|
||||
|
||||
// Cleanup library table for a process slot
|
||||
static void CleanupLibTable(int slot) {
|
||||
if (slot < 0 || slot >= MaxProcesses) return;
|
||||
|
||||
auto* proc = Sched::GetProcessSlot(slot);
|
||||
if (proc == nullptr) return;
|
||||
|
||||
// Unmap all libraries for this process
|
||||
for (int i = 0; i < MaxLibsPerProcess; i++) {
|
||||
if (g_libTable[slot][i].inUse) {
|
||||
uint64_t libBase = g_libTable[slot][i].baseAddr;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
g_libTable[slot][i].inUse = false;
|
||||
g_libTable[slot][i].refcount = 0;
|
||||
g_libTable[slot][i].baseAddr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "Audio.hpp" // SYS_AUDIOOPEN, SYS_AUDIOCLOSE, SYS_AUDIOWRITE, SYS_AUDIOCTL
|
||||
#include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
|
||||
#include "IpcSyscall.hpp" // SYS_DUPHANDLE, SYS_WAIT_HANDLE, SYS_STREAM_CREATE, SYS_STREAM_READ, SYS_STREAM_WRITE, SYS_MAILBOX_CREATE, SYS_MAILBOX_SEND, SYS_MAILBOX_RECV, SYS_WAITSET_CREATE, SYS_WAITSET_ADD, SYS_WAITSET_REMOVE, SYS_WAITSET_WAIT, SYS_PROC_OPEN, SYS_SURFACE_CREATE, SYS_SURFACE_MAP, SYS_SURFACE_RESIZE
|
||||
#include "LibSyscall.hpp" // SYS_LOAD_LIB, SYS_UNLOAD_LIB, SYS_DLSYM
|
||||
|
||||
// Assembly entry point
|
||||
extern "C" void SyscallEntry();
|
||||
@@ -65,6 +66,8 @@ namespace Montauk {
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (slot >= 0 && proc)
|
||||
CleanupHeapForSlot(slot, proc->pml4Phys);
|
||||
if (slot >= 0)
|
||||
CleanupLibTable(slot);
|
||||
Sys_Exit((int)frame->arg1);
|
||||
return 0;
|
||||
}
|
||||
@@ -274,6 +277,7 @@ namespace Montauk {
|
||||
auto* slot0 = Sched::GetProcessSlot(0);
|
||||
int targetSlot = (int)(target - slot0);
|
||||
CleanupHeapForSlot(targetSlot, target->pml4Phys);
|
||||
CleanupLibTable(targetSlot);
|
||||
}
|
||||
return (int64_t)Sys_Kill((int)frame->arg1);
|
||||
}
|
||||
@@ -406,6 +410,13 @@ namespace Montauk {
|
||||
return (int64_t)Sys_SurfaceMap((int)frame->arg1);
|
||||
case SYS_SURFACE_RESIZE:
|
||||
return Sys_SurfaceResize((int)frame->arg1, frame->arg2);
|
||||
case SYS_LOAD_LIB:
|
||||
if (!ValidUserPtr(frame->arg1)) return 0;
|
||||
return (int64_t)Sys_LoadLib((const char*)frame->arg1);
|
||||
case SYS_UNLOAD_LIB:
|
||||
return Sys_UnloadLib(frame->arg1);
|
||||
case SYS_DLSYM:
|
||||
return (int64_t)Sys_DLSym(frame->arg1, frame->arg2);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -206,6 +206,11 @@ namespace Montauk {
|
||||
static constexpr uint64_t SYS_SURFACE_MAP = 112;
|
||||
static constexpr uint64_t SYS_SURFACE_RESIZE = 113;
|
||||
|
||||
/* LibSyscall.hpp */
|
||||
static constexpr uint64_t SYS_LOAD_LIB = 114;
|
||||
static constexpr uint64_t SYS_UNLOAD_LIB = 115;
|
||||
static constexpr uint64_t SYS_DLSYM = 116;
|
||||
|
||||
static constexpr uint32_t IPC_SIGNAL_READABLE = 1u << 0;
|
||||
static constexpr uint32_t IPC_SIGNAL_WRITABLE = 1u << 1;
|
||||
static constexpr uint32_t IPC_SIGNAL_PEER_CLOSED = 1u << 2;
|
||||
|
||||
Reference in New Issue
Block a user