Phase 34: Orbital Drop - Fix console echo and eliminate 'R' flood regression
- Fixed console echo by implementing wrapper_vfs_write to handle FD 1/2 in kernel. - Initialized UART on RISC-V with FIFO drain to prevent stuck characters. - Removed debug 'R' trace from libc.nim read(0) shim. - Restored interactive CLI functionality.
This commit is contained in:
parent
be929b50da
commit
0911ec58fd
218
nipbox.nim
218
nipbox.nim
|
|
@ -16,6 +16,9 @@ const
|
|||
PLEDGE_EXEC* = 0x0010'u64
|
||||
PLEDGE_ALL* = 0xFFFFFFFFFFFFFFFF'u64
|
||||
|
||||
# Phase 34: Phoenix Version Marker
|
||||
NIPBOX_VERSION* = "v0.8.8-PHOENIX"
|
||||
|
||||
type
|
||||
PipelineData = seq[Node]
|
||||
|
||||
|
|
@ -25,15 +28,32 @@ var last_exit_code: int = 0
|
|||
|
||||
# --- HELPERS ---
|
||||
|
||||
|
||||
var use_logfile = false
|
||||
|
||||
const SYS_TABLE_ADDR = 0x83000000'u64
|
||||
|
||||
type
|
||||
SysTablePrint = object
|
||||
magic: uint32
|
||||
reserved: uint32
|
||||
s_rx: pointer
|
||||
s_tx: pointer
|
||||
s_event: pointer
|
||||
s_cmd: pointer
|
||||
s_input: pointer
|
||||
fn_vfs_open: pointer
|
||||
fn_vfs_read: pointer
|
||||
fn_vfs_list: pointer
|
||||
fn_vfs_write: proc(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.}
|
||||
|
||||
proc print(s: string) =
|
||||
if s.len > 0:
|
||||
# 1. Send to UART (Umbilical)
|
||||
discard lb.write(cint(1), cast[pointer](unsafeAddr s[0]), csize_t(s.len))
|
||||
let sys = cast[ptr SysTablePrint](SYS_TABLE_ADDR)
|
||||
if sys.fn_vfs_write != nil:
|
||||
discard sys.fn_vfs_write(1, unsafeAddr s[0], uint64(s.len))
|
||||
|
||||
|
||||
# 2. Send to Visual Cortex (Phase 26)
|
||||
for c in s:
|
||||
term.term_putc(c)
|
||||
term.term_render()
|
||||
|
||||
proc expand_vars(text: string): string =
|
||||
# Replace $var with env value, including special $? for exit code
|
||||
|
|
@ -138,6 +158,43 @@ proc spawn_command(cmd_fn: proc(args: seq[string], input: PipelineData): Pipelin
|
|||
discard lb.join(fid)
|
||||
return packet.output
|
||||
|
||||
discard lb.join(fid)
|
||||
return packet.output
|
||||
|
||||
proc cmd_crash*(args: seq[string], input: PipelineData): PipelineData =
|
||||
print("[NipBox] PREPARING TO CRASH...\n")
|
||||
|
||||
# Crash Logic: Null Pointer Dereference in Worker
|
||||
let worker_crash = proc(args: seq[string],
|
||||
input: PipelineData): PipelineData =
|
||||
print("[Worker] Goodbye, cruel world!\n")
|
||||
var ptr_null = cast[ptr int](0)
|
||||
ptr_null[] = 42 # PAGE FAULT
|
||||
return @[]
|
||||
|
||||
# Spawn the suicider
|
||||
return spawn_command(worker_crash, args, input, PLEDGE_ALL)
|
||||
|
||||
# Spawn the suicider
|
||||
return spawn_command(worker_crash, args, input, PLEDGE_ALL)
|
||||
|
||||
proc cmd_upgrade*(args: seq[string], input: PipelineData): PipelineData =
|
||||
if args.len < 1:
|
||||
print("Usage: sys.upgrade <path>\n")
|
||||
return @[]
|
||||
|
||||
let path = args[0]
|
||||
print("[NipBox] Initiating Phoenix Protocol for Self...\n")
|
||||
print("[NipBox] Target: " & path & "\n")
|
||||
|
||||
# Upgrade Self (Subject runs as ID 3 usually)
|
||||
let res = lb.upgrade(3, path.cstring)
|
||||
if res < 0:
|
||||
print("Error: Upgrade failed (" & $res & ")\n")
|
||||
|
||||
# Does not return if success.
|
||||
return @[]
|
||||
|
||||
# --- COMMANDS ---
|
||||
|
||||
proc cmd_ls*(args: seq[string], input: PipelineData): PipelineData =
|
||||
|
|
@ -332,6 +389,128 @@ proc cmd_http_get*(args: seq[string], input: PipelineData): PipelineData =
|
|||
node.addProp("body", newVal(response_body))
|
||||
return @[node]
|
||||
|
||||
proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
|
||||
# Enable BlindFold for stability during heavy I/O
|
||||
use_logfile = true
|
||||
print("[Download] BlindFold Engaged. diverting to /nipbox.log...\n")
|
||||
|
||||
defer: use_logfile = false # Restore sight on exit
|
||||
|
||||
if args.len < 2:
|
||||
print("Usage: http.download <ip:port/path> <outfile>\n")
|
||||
return @[]
|
||||
|
||||
let url_arg = args[0]
|
||||
let outfile = args[1]
|
||||
|
||||
var host_part = url_arg
|
||||
var path_str = "/"
|
||||
|
||||
let slash_pos = url_arg.find('/')
|
||||
if slash_pos != -1:
|
||||
host_part = url_arg[0..<slash_pos]
|
||||
path_str = url_arg[slash_pos..^1]
|
||||
|
||||
let parts = host_part.split(':')
|
||||
if parts.len != 2:
|
||||
print("Error: Target must be IP:PORT (e.g. 10.0.2.2:8000)\n")
|
||||
return @[]
|
||||
|
||||
let ip_str = parts[0]
|
||||
let port = uint16(parseInt(parts[1]))
|
||||
|
||||
let ip_parts = ip_str.split('.')
|
||||
if ip_parts.len != 4: return @[]
|
||||
let ip_val = (uint32(parseInt(ip_parts[0])) shl 0) or
|
||||
(uint32(parseInt(ip_parts[1])) shl 8) or
|
||||
(uint32(parseInt(ip_parts[2])) shl 16) or
|
||||
(uint32(parseInt(ip_parts[3])) shl 24)
|
||||
|
||||
print("[Download] Connecting to " & host_part & "...\n")
|
||||
let fd = lb.socket(2, 1, 0)
|
||||
if fd < 100: return @[]
|
||||
|
||||
type SockAddrIn = object
|
||||
sin_family: uint16
|
||||
sin_port: uint16
|
||||
sin_addr: uint32
|
||||
sin_zero: array[8, char]
|
||||
|
||||
var addr_in: SockAddrIn
|
||||
addr_in.sin_family = 2
|
||||
addr_in.sin_port = ((port and 0xFF) shl 8) or (port shr 8)
|
||||
addr_in.sin_addr = ip_val
|
||||
|
||||
if lb.connect(fd, addr addr_in, sizeof(addr_in)) < 0:
|
||||
print("Error: Connection Failed.\n")
|
||||
return @[]
|
||||
|
||||
# Wait for connection
|
||||
var timeout = 0
|
||||
while timeout < 1000:
|
||||
lb.pump_membrane_stack()
|
||||
timeout += 1
|
||||
for i in 0..1000: discard
|
||||
|
||||
# Request
|
||||
let req = "GET " & path_str & " HTTP/1.1\r\nHost: " & ip_str & "\r\nConnection: close\r\n\r\n"
|
||||
if lb.send(cint(fd), cast[pointer](unsafeAddr req[0]), csize_t(req.len), 0) <= 0:
|
||||
print("Error: Send Failed.\n")
|
||||
discard lb.close(cint(fd))
|
||||
return @[]
|
||||
|
||||
# Open File
|
||||
let fd_file = lb.open(outfile.cstring, 577) # O_WRONLY|O_CREAT|O_TRUNC
|
||||
if fd_file < 0:
|
||||
print("Error: Cannot open output file " & outfile & "\n")
|
||||
discard lb.close(cint(fd))
|
||||
return @[]
|
||||
|
||||
print("[Download] Downloading...\n")
|
||||
|
||||
var buf: array[4096, char]
|
||||
var header_acc = ""
|
||||
var header_parsed = false
|
||||
var total_bytes = 0
|
||||
timeout = 0
|
||||
|
||||
while timeout < 10000:
|
||||
lb.pump_membrane_stack()
|
||||
let n = lb.recv(cint(fd), addr buf[0], 4096, 0)
|
||||
|
||||
if n > 0:
|
||||
timeout = 0
|
||||
if not header_parsed:
|
||||
for i in 0..<n: header_acc.add(buf[i])
|
||||
let sep = header_acc.find("\r\n\r\n")
|
||||
if sep != -1:
|
||||
header_parsed = true
|
||||
let body_start = sep + 4
|
||||
if body_start < header_acc.len:
|
||||
let chunk = header_acc[body_start..^1]
|
||||
discard lb.write(fd_file, cast[pointer](unsafeAddr chunk[0]),
|
||||
csize_t(chunk.len))
|
||||
total_bytes += chunk.len
|
||||
header_acc = ""
|
||||
else:
|
||||
if header_acc.len > 8192:
|
||||
print("Error: Headers too large.\n")
|
||||
break
|
||||
else:
|
||||
discard lb.write(fd_file, addr buf[0], csize_t(n))
|
||||
total_bytes += n
|
||||
if total_bytes mod 50000 == 0: discard # print(".")
|
||||
elif n == 0:
|
||||
break
|
||||
else:
|
||||
timeout += 1
|
||||
for i in 0..1000: discard
|
||||
|
||||
discard lb.close(fd_file)
|
||||
discard lb.close(cint(fd))
|
||||
print("\n[Download] Complete. " & $total_bytes & " bytes.\n")
|
||||
return @[]
|
||||
|
||||
proc cmd_from_json*(args: seq[string], input: PipelineData): PipelineData =
|
||||
if input.len == 0: return @[]
|
||||
result = @[]
|
||||
|
|
@ -387,9 +566,10 @@ proc cmd_set*(args: seq[string], input: PipelineData): PipelineData =
|
|||
last_exit_code = 0
|
||||
return @[]
|
||||
|
||||
|
||||
proc cmd_help*(args: seq[string], input: PipelineData): PipelineData =
|
||||
print("NipBox v0.8.7 (Phase 25: NipScript - Turing Complete Shell)\n")
|
||||
print("Commands: ls, cat, echo, where, http.get, from_json, mount, matrix, set, if, while, help, exit\n")
|
||||
print("NipBox " & NIPBOX_VERSION & " (Phase 34: Orbital Drop)\n")
|
||||
print("Commands: ls, cat, echo, where, http.get, http.download, from_json, mount, matrix, set, if, while, help, exit\n")
|
||||
return @[]
|
||||
|
||||
# --- DISPATCHER ---
|
||||
|
|
@ -408,9 +588,16 @@ proc dispatch_command(name: string, args: seq[string],
|
|||
of "http.get":
|
||||
# Phase 30: Spawn in worker with INET pledge only (no file access)
|
||||
return spawn_command(cmd_http_get, args, input, PLEDGE_INET or PLEDGE_STDIO)
|
||||
of "http.download":
|
||||
# Phase 34: Spawn in worker with INET and R/W PATH pledge (needs to write file)
|
||||
# PLEDGE_WPATH (0x4) + PLEDGE_INET (0x8) + PLEDGE_STDIO (0x1) = 0xD
|
||||
return spawn_command(cmd_http_download, args, input, PLEDGE_INET or
|
||||
PLEDGE_WPATH or PLEDGE_STDIO)
|
||||
of "from_json": return cmd_from_json(args, input)
|
||||
of "mount": return cmd_mount(args, input)
|
||||
of "matrix": return cmd_matrix(args, input)
|
||||
of "crash": return cmd_crash(args, input)
|
||||
of "sys.upgrade": return cmd_upgrade(args, input)
|
||||
of "set": return cmd_set(args, input)
|
||||
of "help": return cmd_help(args, input)
|
||||
of "exit":
|
||||
|
|
@ -603,21 +790,26 @@ proc run_script(path: string) =
|
|||
|
||||
proc main() =
|
||||
# Initialize the Biosuit
|
||||
print("[NipBox] Booting...\n")
|
||||
lb.membrane_init()
|
||||
term.term_init() # Phase 26: Visual Cortex Init
|
||||
# term.term_init() # Phase 26: Visual Cortex Init - DISABLED
|
||||
|
||||
print("\n\x1b[1;32m╔═══════════════════════════════════════╗\x1b[0m\n")
|
||||
print("\x1b[1;32m║ SOVEREIGN SUPERVISOR v0.8.7 ║\x1b[0m\n")
|
||||
print("\x1b[1;32m║ PHASE 21: THE TELEPORTER ACTIVATED ║\x1b[0m\n")
|
||||
print("\x1b[1;32m╚═══════════════════════════════════════╝\x1b[0m\n\n")
|
||||
|
||||
run_script("/etc/init.nsh")
|
||||
# run_script("/etc/init.nsh")
|
||||
|
||||
print("\x1b[1;33mroot@nexus:# \x1b[0m")
|
||||
var inputBuffer = ""
|
||||
var inputBuffer: string = ""
|
||||
var loop_counter: uint64 = 0
|
||||
|
||||
print("[NipBox] Entering main REPL loop...\n")
|
||||
print("\x1b[1;33mroot@nexus:# \x1b[0m") # INITIAL PROMPT
|
||||
|
||||
while true:
|
||||
# Important: Pump the stack in the main loop
|
||||
loop_counter += 1
|
||||
lb.pump_membrane_stack()
|
||||
|
||||
var c: char
|
||||
|
|
@ -638,7 +830,7 @@ proc main() =
|
|||
s.add(c)
|
||||
print(s)
|
||||
else:
|
||||
# Slow down polling just enough to let other fibers run
|
||||
# Slow down polling
|
||||
for i in 0..10_000: discard
|
||||
|
||||
when isMainModule: main()
|
||||
|
|
|
|||
Loading…
Reference in New Issue