feat(rumpk): Phase 8 - The Summoning (ELF Loader) - 95% Complete
## 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: <ai@voxisforge.dev>
This commit is contained in:
parent
d1918d9770
commit
932a70ab7b
242
nipbox.nim
242
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 <path>")
|
||||
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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue