From 1542e80a3f205c63326d710b4edf4457a9654e86 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Tue, 24 Mar 2026 17:17:47 +0100 Subject: [PATCH] feat: ACPI parsing improvements, username in process struct + syscalls --- kernel/src/ACPI/AML/AmlInterpreter.cpp | 3 +- kernel/src/ACPI/AML/AmlNamespace.cpp | 95 ++++++++++++++++++-------- kernel/src/ACPI/AML/AmlNamespace.hpp | 21 ++++-- kernel/src/ACPI/AML/AmlParser.cpp | 3 + kernel/src/Api/Process.hpp | 21 ++++++ kernel/src/Api/Syscall.hpp | 10 +++ kernel/src/Sched/Scheduler.cpp | 18 +++++ kernel/src/Sched/Scheduler.hpp | 1 + programs/include/Api/Syscall.hpp | 10 +++ programs/include/gui/desktop.hpp | 8 +++ programs/include/montauk/syscall.h | 8 +++ programs/src/login/main.cpp | 3 + programs/src/whoami/main.cpp | 17 +++-- scripts/copy_icons.sh | 1 + 14 files changed, 176 insertions(+), 43 deletions(-) diff --git a/kernel/src/ACPI/AML/AmlInterpreter.cpp b/kernel/src/ACPI/AML/AmlInterpreter.cpp index 320a49c..aeb904f 100644 --- a/kernel/src/ACPI/AML/AmlInterpreter.cpp +++ b/kernel/src/ACPI/AML/AmlInterpreter.cpp @@ -1652,8 +1652,7 @@ namespace Hal { } if (space == RegionSpace::PciConfig) { - // PCI config space access — address encodes bus/dev/func/offset - // Not implemented yet; would need PCI config read support + // PCI config space access -- not yet implemented return false; } diff --git a/kernel/src/ACPI/AML/AmlNamespace.cpp b/kernel/src/ACPI/AML/AmlNamespace.cpp index 4a14470..1e2ae6c 100644 --- a/kernel/src/ACPI/AML/AmlNamespace.cpp +++ b/kernel/src/ACPI/AML/AmlNamespace.cpp @@ -6,29 +6,74 @@ #include "AmlNamespace.hpp" #include +#include namespace Hal { namespace AML { - Namespace::Namespace() : m_nodeCount(0) { - for (int i = 0; i < MaxNamespaceNodes; i++) - m_nodes[i].Clear(); + Namespace::Namespace() : m_chunkCount(0), m_nodeCount(0) { + for (int i = 0; i < MaxChunks; i++) + m_chunks[i] = nullptr; + // Root node is created lazily by the first CreateNode/AllocNode call, + // which happens during LoadTable -- after the kernel heap is ready. + } - // Create root node "\" + void Namespace::EnsureRoot() { + if (m_nodeCount > 0) return; int32_t root = AllocNode(); - m_nodes[root].Name[0] = '\\'; - m_nodes[root].Name[1] = '\0'; - m_nodes[root].ParentIndex = -1; + auto* rootNode = GetNode(root); + if (rootNode) { + rootNode->Name[0] = '\\'; + rootNode->Name[1] = '\0'; + rootNode->ParentIndex = -1; + } + } + + bool Namespace::AllocChunk() { + if (m_chunkCount >= MaxChunks) return false; + + auto* chunk = (NamespaceNode*)Memory::g_heap->Request( + sizeof(NamespaceNode) * NodesPerChunk); + if (!chunk) return false; + + // Zero-initialize the chunk + memset(chunk, 0, sizeof(NamespaceNode) * NodesPerChunk); + for (int i = 0; i < NodesPerChunk; i++) + chunk[i].Clear(); + + m_chunks[m_chunkCount++] = chunk; + return true; } int32_t Namespace::AllocNode() { - if (m_nodeCount >= MaxNamespaceNodes) - return -1; + // Check if we need a new chunk + int32_t capacity = m_chunkCount * NodesPerChunk; + if (m_nodeCount >= capacity) { + if (!AllocChunk()) return -1; + } + int32_t idx = m_nodeCount++; - m_nodes[idx].Clear(); + auto* node = GetNode(idx); + if (node) node->Clear(); return idx; } + NamespaceNode* Namespace::GetNode(int32_t index) { + if (index < 0 || index >= m_nodeCount) return nullptr; + int chunk = index / NodesPerChunk; + int offset = index % NodesPerChunk; + if (chunk >= m_chunkCount || !m_chunks[chunk]) return nullptr; + return &m_chunks[chunk][offset]; + } + + const NamespaceNode* Namespace::GetNode(int32_t index) const { + if (index < 0 || index >= m_nodeCount) return nullptr; + int chunk = index / NodesPerChunk; + int offset = index % NodesPerChunk; + if (chunk >= m_chunkCount || !m_chunks[chunk]) return nullptr; + return &m_chunks[chunk][offset]; + } + bool Namespace::SegmentEqual(const char* a, const char* b) { for (int i = 0; i < MaxNameSegLen; i++) { char ca = a[i] ? a[i] : '_'; @@ -63,7 +108,7 @@ namespace Hal { while (*p && count < maxSegments) { // Skip dots (parent prefix / dual/multi name prefix separator) if (*p == '.') { p++; continue; } - // Skip caret (parent prefix) — we don't handle relative paths here + // Skip caret (parent prefix) -- we don't handle relative paths here if (*p == '^') { p++; continue; } // Read up to 4 characters for a name segment @@ -91,14 +136,16 @@ namespace Hal { for (int32_t i = 0; i < parent->ChildCount; i++) { int32_t ci = parent->ChildIndices[i]; - if (ci < 0 || ci >= m_nodeCount) continue; - if (SegmentEqual(m_nodes[ci].Name, seg)) + auto* child = GetNode(ci); + if (!child) continue; + if (SegmentEqual(child->Name, seg)) return ci; } return -1; } int32_t Namespace::CreateNode(const char* absolutePath) { + EnsureRoot(); char segments[MaxPathDepth][MaxNameSegLen + 1]; int segCount = ParsePath(absolutePath, segments, MaxPathDepth); @@ -110,11 +157,14 @@ namespace Hal { child = AllocNode(); if (child < 0) return -1; - memcpy(m_nodes[child].Name, segments[i], MaxNameSegLen + 1); - m_nodes[child].ParentIndex = current; + auto* childNode = GetNode(child); + if (!childNode) return -1; + memcpy(childNode->Name, segments[i], MaxNameSegLen + 1); + childNode->ParentIndex = current; // Add to parent's children - auto* parent = &m_nodes[current]; + auto* parent = GetNode(current); + if (!parent) return -1; if (parent->ChildCount < MaxChildren) { parent->ChildIndices[parent->ChildCount++] = child; } else { @@ -151,22 +201,13 @@ namespace Hal { while (scope >= 0) { int32_t found = FindChildByName(scope, padded); if (found >= 0) return found; - scope = m_nodes[scope].ParentIndex; + auto* node = GetNode(scope); + scope = node ? node->ParentIndex : -1; } return -1; } - NamespaceNode* Namespace::GetNode(int32_t index) { - if (index < 0 || index >= m_nodeCount) return nullptr; - return &m_nodes[index]; - } - - const NamespaceNode* Namespace::GetNode(int32_t index) const { - if (index < 0 || index >= m_nodeCount) return nullptr; - return &m_nodes[index]; - } - char* Namespace::GetNodePath(int32_t index, char* outBuf, int maxLen) const { if (!outBuf || maxLen < 2) return outBuf; diff --git a/kernel/src/ACPI/AML/AmlNamespace.hpp b/kernel/src/ACPI/AML/AmlNamespace.hpp index 0b55699..ced9ac2 100644 --- a/kernel/src/ACPI/AML/AmlNamespace.hpp +++ b/kernel/src/ACPI/AML/AmlNamespace.hpp @@ -55,13 +55,17 @@ namespace Hal { // ============================================================================ static constexpr int MaxNameSegLen = 4; static constexpr int MaxPathDepth = 16; - static constexpr int MaxChildren = 32; + static constexpr int MaxChildren = 64; static constexpr int MaxStringLen = 64; static constexpr int MaxBufferLen = 256; static constexpr int MaxPackageElements = 16; static constexpr int MaxMethodArgs = 7; static constexpr int MaxMethodLocals = 8; - static constexpr int MaxNamespaceNodes = 256; + + // Nodes are allocated dynamically in chunks from the kernel heap. + // Each chunk holds this many nodes; new chunks are allocated on demand. + static constexpr int NodesPerChunk = 256; + static constexpr int MaxChunks = 128; // up to 32768 nodes // ============================================================================ @@ -143,7 +147,8 @@ namespace Hal { // Namespace // ============================================================================ - // Flat array of nodes forming a tree via parent/child indices. + // Dynamically-allocated node pool forming a tree via parent/child indices. + // Nodes are allocated in chunks from the kernel heap on demand. class Namespace { public: Namespace(); @@ -174,6 +179,9 @@ namespace Hal { // Get the number of nodes in the namespace. int32_t NodeCount() const { return m_nodeCount; } + // Maximum capacity with current chunk limit. + int32_t MaxCapacity() const { return MaxChunks * NodesPerChunk; } + // Iterate children of a node matching a given object type. // callback returns true to continue, false to stop. // Returns the index of the node that stopped iteration, or -1. @@ -208,6 +216,8 @@ namespace Hal { private: int32_t AllocNode(); + bool AllocChunk(); + void EnsureRoot(); int32_t FindChildByName(int32_t parentIndex, const char* seg) const; // Parse an absolute path into segments. Returns number of segments. @@ -215,8 +225,9 @@ namespace Hal { static bool SegmentEqual(const char* a, const char* b); static void PadSegment(const char* src, char* dst); // pad to 4 chars with '_' - NamespaceNode m_nodes[MaxNamespaceNodes]; - int32_t m_nodeCount; + NamespaceNode* m_chunks[MaxChunks]; // array of pointers to heap-allocated chunks + int32_t m_chunkCount; + int32_t m_nodeCount; }; }; diff --git a/kernel/src/ACPI/AML/AmlParser.cpp b/kernel/src/ACPI/AML/AmlParser.cpp index 11b2318..3c5d324 100644 --- a/kernel/src/ACPI/AML/AmlParser.cpp +++ b/kernel/src/ACPI/AML/AmlParser.cpp @@ -244,6 +244,9 @@ namespace Hal { if (!interp.LoadTable(dsdtData)) { KernelLogStream(ERROR, "AML") << "Failed to load DSDT into AML interpreter"; } + auto& ns = interp.GetNamespace(); + KernelLogStream(OK, "AML") << "Namespace: " << base::dec + << (uint64_t)ns.NodeCount() << " / " << (uint64_t)ns.MaxCapacity() << " nodes (dynamic)"; } }; diff --git a/kernel/src/Api/Process.hpp b/kernel/src/Api/Process.hpp index 12b90ba..198e857 100644 --- a/kernel/src/Api/Process.hpp +++ b/kernel/src/Api/Process.hpp @@ -99,4 +99,25 @@ namespace Montauk { static int Sys_Kill(int pid) { return Sched::KillProcess(pid); } + + static int Sys_SetUser(int pid, const char* name) { + if (name == nullptr) return -1; + auto* target = Sched::GetProcessByPid(pid); + if (target == nullptr) return -1; + int i = 0; + for (; i < 31 && name[i]; i++) + target->user[i] = name[i]; + target->user[i] = '\0'; + return 0; + } + + static int Sys_GetUser(char* buf, uint64_t maxLen) { + auto* proc = Sched::GetCurrentProcessPtr(); + if (proc == nullptr || buf == nullptr || maxLen == 0) return -1; + int i = 0; + for (; i < (int)maxLen - 1 && proc->user[i]; i++) + buf[i] = proc->user[i]; + buf[i] = '\0'; + return i; + } }; \ No newline at end of file diff --git a/kernel/src/Api/Syscall.hpp b/kernel/src/Api/Syscall.hpp index 639a2b1..b0ca727 100644 --- a/kernel/src/Api/Syscall.hpp +++ b/kernel/src/Api/Syscall.hpp @@ -178,6 +178,10 @@ namespace Montauk { static constexpr uint64_t SYS_SETTZ = 90; static constexpr uint64_t SYS_GETTZ = 91; + /* Process.hpp */ + static constexpr uint64_t SYS_SETUSER = 92; + static constexpr uint64_t SYS_GETUSER = 93; + static constexpr int SOCK_TCP = 1; static constexpr int SOCK_UDP = 2; @@ -371,6 +375,12 @@ namespace Montauk { char name[64]; }; + struct ThermalInfo { + char name[32]; // short zone name (e.g. "THRM", "TZ00") + int32_t temperature; // tenths of degrees Celsius, or -1 if unavailable + uint32_t _pad; + }; + // Stack frame pushed by SyscallEntry.asm struct SyscallFrame { uint64_t r15, r14, r13, r12, rbp, rbx; // callee-saved diff --git a/kernel/src/Sched/Scheduler.cpp b/kernel/src/Sched/Scheduler.cpp index 3ab9cfc..efdb766 100644 --- a/kernel/src/Sched/Scheduler.cpp +++ b/kernel/src/Sched/Scheduler.cpp @@ -90,6 +90,7 @@ namespace Sched { processTable[i].userStackTop = 0; processTable[i].heapNext = 0; processTable[i].args[0] = '\0'; + processTable[i].user[0] = '\0'; processTable[i].runningOnCpu = -1; processTable[i].killPending = false; processTable[i].waitingForPid = -1; @@ -283,6 +284,23 @@ namespace Sched { proc.args[i] = '\0'; } + // Inherit user string from parent, or default to "system" if no parent + { + auto* cpu = Smp::GetCurrentCpuData(); + int parentSlot = cpu->currentSlot; + if (parentSlot >= 0) { + int i = 0; + for (; i < 31 && processTable[parentSlot].user[i]; i++) + proc.user[i] = processTable[parentSlot].user[i]; + proc.user[i] = '\0'; + } else { + // Spawned from kernel (no parent process) - set to "system" + proc.user[0] = 's'; proc.user[1] = 'y'; proc.user[2] = 's'; + proc.user[3] = 't'; proc.user[4] = 'e'; proc.user[5] = 'm'; + proc.user[6] = '\0'; + } + } + proc.redirected = false; proc.parentPid = -1; proc.outBuf = nullptr; diff --git a/kernel/src/Sched/Scheduler.hpp b/kernel/src/Sched/Scheduler.hpp index 2849795..bf81c55 100644 --- a/kernel/src/Sched/Scheduler.hpp +++ b/kernel/src/Sched/Scheduler.hpp @@ -43,6 +43,7 @@ namespace Sched { uint64_t userStackTop; // User-space stack top uint64_t heapNext; // Simple bump allocator for user heap char args[256]; // Command-line arguments (set by parent via Spawn) + char user[32]; // Owner user name (inherited from parent on spawn) int runningOnCpu; // CPU index running this process (-1 if not running) bool killPending = false; // Set by Sys_Kill when target is running on another CPU diff --git a/programs/include/Api/Syscall.hpp b/programs/include/Api/Syscall.hpp index f04b8b2..64eb5ae 100644 --- a/programs/include/Api/Syscall.hpp +++ b/programs/include/Api/Syscall.hpp @@ -120,6 +120,10 @@ namespace Montauk { static constexpr uint64_t SYS_SETTZ = 90; static constexpr uint64_t SYS_GETTZ = 91; + // User management + static constexpr uint64_t SYS_SETUSER = 92; + static constexpr uint64_t SYS_GETUSER = 93; + // Audio control commands (for SYS_AUDIOCTL) static constexpr int AUDIO_CTL_SET_VOLUME = 0; static constexpr int AUDIO_CTL_GET_VOLUME = 1; @@ -306,6 +310,12 @@ namespace Montauk { char name[64]; }; + struct ThermalInfo { + char name[32]; // short zone name (e.g. "THRM", "TZ00") + int32_t temperature; // tenths of degrees Celsius, or -1 if unavailable + uint32_t _pad; + }; + struct ProcInfo { int32_t pid; int32_t parentPid; diff --git a/programs/include/gui/desktop.hpp b/programs/include/gui/desktop.hpp index f8b3143..3fa44f8 100644 --- a/programs/include/gui/desktop.hpp +++ b/programs/include/gui/desktop.hpp @@ -120,6 +120,7 @@ struct DesktopState { SvgIcon icon_procmgr; SvgIcon icon_mandelbrot; SvgIcon icon_volume; + SvgIcon icon_temperature; // External apps discovered from 0:/apps/ manifests ExternalApp external_apps[MAX_EXTERNAL_APPS]; @@ -141,6 +142,13 @@ struct DesktopState { bool vol_dragging; // slider drag in progress uint64_t vol_last_poll; + // Temperature monitoring + static constexpr int MAX_THERMAL_ZONES = 8; + Montauk::ThermalInfo thermal_zones[MAX_THERMAL_ZONES]; + int thermal_zone_count; + uint64_t thermal_last_poll; + Rect temp_icon_rect; + int screen_w, screen_h; // IDs of external windows we've sent a close event to but that haven't diff --git a/programs/include/montauk/syscall.h b/programs/include/montauk/syscall.h index 71d0431..11c08aa 100644 --- a/programs/include/montauk/syscall.h +++ b/programs/include/montauk/syscall.h @@ -402,6 +402,14 @@ namespace montauk { // Kernel introspection inline void memstats(Montauk::MemStats* out) { syscall1(Montauk::SYS_MEMSTATS, (uint64_t)out); } + // User management + inline int setuser(int pid, const char* name) { + return (int)syscall2(Montauk::SYS_SETUSER, (uint64_t)pid, (uint64_t)name); + } + inline int getuser(char* buf, uint64_t maxLen) { + return (int)syscall2(Montauk::SYS_GETUSER, (uint64_t)buf, maxLen); + } + // Window server inline int win_create(const char* title, int w, int h, Montauk::WinCreateResult* result) { return (int)syscall4(Montauk::SYS_WINCREATE, (uint64_t)title, (uint64_t)w, (uint64_t)h, (uint64_t)result); diff --git a/programs/src/login/main.cpp b/programs/src/login/main.cpp index ed5673d..d8b378c 100644 --- a/programs/src/login/main.cpp +++ b/programs/src/login/main.cpp @@ -546,6 +546,7 @@ static void handle_key(LoginState* ls, const Montauk::KeyEvent& key) { // Spawn desktop with username int pid = montauk::spawn("0:/os/desktop.elf", ls->username); if (pid >= 0) { + montauk::setuser(pid, ls->username); montauk::waitpid(pid); } // Desktop exited (logout) — clear session and fields @@ -688,6 +689,7 @@ static void handle_mouse(LoginState* ls) { if (try_login(ls)) { int pid = montauk::spawn("0:/os/desktop.elf", ls->username); if (pid >= 0) { + montauk::setuser(pid, ls->username); montauk::waitpid(pid); } montauk::user::clear_session(); @@ -772,6 +774,7 @@ extern "C" void _start() { // Launch desktop directly -- no login required int pid = montauk::spawn("0:/os/desktop.elf", user); if (pid >= 0) { + montauk::setuser(pid, user); montauk::waitpid(pid); } // Desktop exited (reboot/shutdown expected in setup mode). diff --git a/programs/src/whoami/main.cpp b/programs/src/whoami/main.cpp index a3be060..4fe98c0 100644 --- a/programs/src/whoami/main.cpp +++ b/programs/src/whoami/main.cpp @@ -9,15 +9,14 @@ #include #include +/* + Mar 24, 2026 - update to use getuser() syscall +*/ extern "C" void _start() { - auto doc = montauk::config::load("session"); - const char* name = doc.get_string("session.username", ""); - if (name[0]) { - montauk::print(name); - montauk::putchar('\n'); - } else { - montauk::print("unknown\n"); - } - doc.destroy(); + char username[32] = { }; + montauk::getuser((char*)&username, 32); + montauk::print((const char*)username); + montauk::print("\n"); + montauk::exit(0); } diff --git a/scripts/copy_icons.sh b/scripts/copy_icons.sh index 5f54f06..9e3fb57 100755 --- a/scripts/copy_icons.sh +++ b/scripts/copy_icons.sh @@ -109,6 +109,7 @@ ICONS=( "apps/scalable/lock.svg" "apps/scalable/sleep.svg" "apps/scalable/kolourpaint.svg" # paint app + "panel/sensors-temperature-symbolic.svg" # temperature panel icon ) copied=0