From 932a70ab7b1e9eb573de188ca454d8c2f55e469c Mon Sep 17 00:00:00 2001 From: Markus Maiwald Date: Wed, 31 Dec 2025 20:18:15 +0100 Subject: [PATCH] feat(rumpk): Phase 8 - The Summoning (ELF Loader) - 95% Complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Major Features ### 1. Dynamic ELF64 Binary Loading - Implemented ELF parser with full header validation (core/loader/elf.nim) - Created kexec() loader supporting PT_LOAD segment mapping - Added BSS initialization and data copying from VFS - Assembly trampoline (rumpk_enter_userland) for userland entry ### 2. Syscall Infrastructure - Added CMD_SYS_EXEC (0x400) for consciousness swapping - Integrated exec command in NipBox shell - Implemented syscall routing through command ring - Added provenance tracking via SipHash ### 3. Test Binary & Build System - Created hello.c test program for alien binary execution - Automated compilation and initrd inclusion in build.sh - Added libnexus.h header for standalone C programs ### 4. VFS Integration - Implemented TarFS file cursor system for sequential reads - Fixed infinite loop bug in cat command - Added debug logging for VFS mount process ## Technical Improvements ### Memory Management - Fixed input ring null pointer dereference - Implemented CMD_ION_FREE syscall for packet reclamation - Resolved memory leak in input/output pipeline - Added FileHandle with persistent offset tracking ### ABI Stability - Split kprint into 1-arg (Nim) and kwrite (C ABI) - Fixed cstring conversion warnings across codebase - Corrected RISC-V assembly (csrw sie, zero) ### Documentation - Comprehensive Phase 8 documentation (docs/PHASE-8-ELF-LOADER.md) - Detailed implementation notes and debugging status ## Current Status ✅ ELF parser, loader, and syscall infrastructure complete ✅ Test binary compiles and embeds in VFS ✅ Shell integration functional 🔧 Debugging command ring communication (syscall not reaching kernel) ## Files Changed Core: - core/loader.nim, core/loader/elf.nim (NEW) - core/kernel.nim, core/ion.nim (syscall handling) - core/fs/tar.nim (file cursor system) - hal/arch/riscv64/switch.S (userland trampoline) Userland: - npl/nipbox/nipbox.nim (exec command) - libs/membrane/libc_shim.zig (syscall implementation) - libs/membrane/ion.zig (command ring API) Build & Test: - build.sh (hello.c compilation) - rootfs/src/hello.c, rootfs/src/libnexus.h (NEW) - apps/subject_entry.S (NEW) ## Next Steps 1. Debug SysTable and command ring communication 2. Verify ION fiber polling of chan_cmd 3. Test full ELF loading and execution flow 4. Add memory protection (future phase) Co-authored-by: --- nipbox.nim | 242 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 174 insertions(+), 68 deletions(-) diff --git a/nipbox.nim b/nipbox.nim index 990246e..14e597a 100644 --- a/nipbox.nim +++ b/nipbox.nim @@ -1,89 +1,195 @@ # src/npl/nipbox/nipbox.nim -import std/[strutils, tables] -# --- COMMANDS --- +# --- 1. RAW IMPORTS (The Physics) --- +# We talk directly to libc_shim.zig -proc do_echo(args: seq[string]) = - echo args.join(" ") +type + cint = int32 + csize_t = uint + cptr = pointer -proc do_ls(args: seq[string]) = - # A Sovereign 'ls' - eventually this will query the NPL filesystem - echo ". .." - echo "kernel subject" - echo "matrix ion" - echo "vault pki" +# Standard POSIX-ish +proc write(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.} +proc read(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.} +proc open(pathname: cstring, flags: cint): cint {.importc, cdecl.} +proc close(fd: cint): cint {.importc, cdecl.} +proc exit(status: cint) {.importc, cdecl.} +proc list_files(buf: pointer, len: uint64): int64 {.importc, cdecl.} + +# Our Custom Syscalls (Defined in libc_shim) +proc nexus_syscall(cmd: cint, arg: uint64): cint {.importc, cdecl.} +proc nexus_yield() {.importc, cdecl.} const CMD_GPU_MATRIX = 0x100 -const CMD_GPU_CLEAR = 0x101 - -proc nexus_syscall(cmd: uint32, arg: uint32): cint {.importc, cdecl.} - -proc do_matrix(args: seq[string]) = - let enable = if args.len > 0 and args[0] == "off": 0'u32 else: 1'u32 - let state = if enable == 1: "ON" else: "OFF" - echo "[NipBox] Matrix Protocol: Setting state to " & state - if nexus_syscall(CMD_GPU_MATRIX, enable) != 0: - echo "[Error] Command Ring Full!" - else: - echo "[NipBox] Command Sent Successfully." - -proc do_help(args: seq[string]) = - echo "NipBox v0.1 (Sovereign Coreutils)" - echo " echo [args...] : Print arguments" - echo " ls : List sovereign objects" - echo " matrix [on/off]: Toggle visualizer" - echo " help : Show this message" - echo " version : Show version info" - -proc do_version(args: seq[string]) = - echo "NipBox v0.1.0" - echo "Built: 2025-12-31" - echo "Architect: Markus Maiwald | Voxis Forge (AI)" - +const CMD_GPU_STATUS = 0x102 const CMD_GET_GPU_STATUS = 0x102 +const CMD_SYS_EXEC = 0x400 -proc do_status(args: seq[string]) = - echo "[NipBox] Querying GPU Status..." - let status = nexus_syscall(CMD_GET_GPU_STATUS, 0) - echo "GPU Status: ", if status == 1: "ONLINE (Retina Active)" else: "OFFLINE" +# --- 2. MINIMAL RUNTIME (The Tools) --- -# --- DISPATCHER --- +# Helper: Print to Stdout (FD 1) +proc print(s: string) = + if s.len > 0: + discard write(1, unsafeAddr s[0], csize_t(s.len)) + var nl = "\n" + discard write(1, unsafeAddr nl[0], 1) -const commands = { - "echo": do_echo, - "ls": do_ls, - "matrix": do_matrix, - "status": do_status, - "help": do_help, - "version": do_version -}.toTable +proc print_raw(s: string) = + if s.len > 0: + discard write(1, unsafeAddr s[0], csize_t(s.len)) -proc main() = - proc nexus_yield() {.importc, cdecl.} - echo "\n[NipBox] Shell Ready. Waiting for orders..." +# Helper: Read Line from Stdin (FD 0) +# Returns true if line read, false if EOF +var read_buffer: array[256, char] +var read_pos: int = 0 +var read_len: int = 0 + +proc my_readline(buf: var string): bool = + buf.setLen(0) + while true: + # Buffer empty? Fill it. + if read_pos >= read_len: + let n = read(0, addr read_buffer[0], 256) + if n <= 0: + nexus_yield() + continue + read_len = int(n) + read_pos = 0 + + # Process buffer + while read_pos < read_len: + let c = read_buffer[read_pos] + read_pos += 1 + + # Handle Backspace + if c == char(127) or c == char(8): + if buf.len > 0: + var seq = "\b \b" + discard write(1, unsafeAddr seq[0], 3) + buf.setLen(buf.len - 1) + continue + + # Echo logic skipped (Host handles it mostly) + + if c == '\n' or c == '\r': + return true + + buf.add(c) + +# --- 3. COMMAND LOGIC --- + +proc do_echo(arg: string) = + print(arg) + +proc do_matrix(arg: string) = + if arg == "on": + print("[NipBox] Engaging Matrix...") + discard nexus_syscall(CMD_GPU_MATRIX, 1) + elif arg == "off": + print("[NipBox] Disengaging Matrix...") + discard nexus_syscall(CMD_GPU_MATRIX, 0) + else: + print("Usage: matrix on|off") + +proc do_cat(filename: string) = + # 1. Open + let fd = open(cstring(filename), 0) # O_RDONLY + if fd < 0: + print("cat: cannot open file") + return + + # 2. Read Loop + const BUF_SIZE = 1024 + var buffer: array[BUF_SIZE, char] while true: - stdout.write("root@nexus:# ") - stdout.flushFile() + let bytesRead = read(fd, addr buffer[0], BUF_SIZE) + if bytesRead <= 0: break - let line = try: stdin.readLine() except: "" + # Write to Stdout + discard write(1, addr buffer[0], bytesRead) - if line.len == 0: - nexus_yield() - continue + # 3. Close + discard close(fd) + print("") # Final newline - let parts = line.split(' ') - if parts.len == 0: continue - let cmd = parts[0] - let args = if parts.len > 1: parts[1..^1] else: @[] +proc do_ls() = + var buf: array[2048, char] + let n = list_files(addr buf[0], 2048) + if n > 0: + var s = newString(n) + copyMem(addr s[0], addr buf[0], n) + print(s) - if commands.hasKey(cmd): - commands[cmd](args) - elif cmd == "exit": - echo "[NipBox] Dropping to Kernel View..." - break +proc do_exec(filename: string) = + if filename.len == 0: + print("Usage: exec ") + return + print("[NipBox] Summoning " & filename & "...") + let result = nexus_syscall(CMD_SYS_EXEC, cast[uint64](cstring(filename))) + if result != 0: + print("[NipBox] Syscall failed!") + else: + print("[NipBox] Syscall sent successfully") + +proc do_help() = + print("NipBox v0.2 (Sovereign)") + print("Commands: echo, cat, ls, matrix, exec, help, exit") + +# --- 4. MAIN LOOP --- + +proc main() = + var inputBuffer = newStringOfCap(256) + + print("\n[NipBox] Interactive Shell Ready.") + + while true: + print_raw("root@nexus:# ") + + if not my_readline(inputBuffer): + break # EOF + + if inputBuffer.len == 0: continue + + # Simple manual parsing + + # Reset manual parsing + var cmd = newStringOfCap(32) + var arg = newStringOfCap(128) + var spaceFound = false + + var i = 0 + while i < inputBuffer.len: + let c = inputBuffer[i] + i += 1 + + if not spaceFound and c == ' ': + spaceFound = true + continue + if not spaceFound: + cmd.add(c) + else: + arg.add(c) + + + if cmd == "exit": + print("Exiting...") + exit(0) + elif cmd == "echo": + do_echo(arg) + elif cmd == "cat": + do_cat(arg) + elif cmd == "ls": + do_ls() + elif cmd == "matrix": + do_matrix(arg) + elif cmd == "exec": + do_exec(arg) + elif cmd == "help": + do_help() else: - echo "nipbox: command not found: ", cmd + print_raw("Unknown command: ") + print(cmd) when isMainModule: main()