feat(userland): NipBox LITE subject binary, ARM64 init support

This commit is contained in:
Markus Maiwald 2026-02-15 19:59:30 +01:00
parent 47f1078748
commit dfe9135b8a
1 changed files with 240 additions and 198 deletions

View File

@ -12,9 +12,49 @@ import strutils, parseutils, tables, sequtils, json
import kdl
import ../../libs/membrane/libc as lb
import ../../libs/membrane/libc_net as lnet
import ../../libs/membrane/fs/sfs_user as sfs
when not defined(NIPBOX_LITE):
import ../../libs/membrane/fs/sfs_user as sfs
import editor
import ../../libs/membrane/term # Phase 26: Visual Cortex
when not defined(NIPBOX_LITE):
import ../../libs/membrane/term # Phase 26: Visual Cortex
# --- M4.4: BKDL Capability Manifest (SPEC-071) ---
{.emit: """
__attribute__((section(".nexus.manifest"), used))
static const unsigned char nexus_manifest[166] = {
/* BkdlHeader (118 bytes) */
0x53, 0x55, 0x58, 0x4E, /* magic: "NXUS" (LE) */
0x01, 0x00, /* version: 1 */
0x00, 0x00, /* flags: 0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* signature[0..63]: zeros */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* pubkey_hash[0..31]: zeros */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, /* cap_count: 4 */
0x00, 0x00, 0x00, 0x00, /* blob_size: 0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* entry_point: 0 */
/* CapDescriptor[0]: console.output (0x1001) WRITE */
0x02, 0x02, 0x00, 0x00,
0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* CapDescriptor[1]: VFS (0x2000) READ */
0x02, 0x01, 0x00, 0x00,
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* CapDescriptor[2]: NET_TX (0x0500) WRITE */
0x02, 0x02, 0x00, 0x00,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* CapDescriptor[3]: NET_RX (0x0501) READ */
0x02, 0x01, 0x00, 0x00,
0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
""".}
# Phase 30: Pledge Constants
const
@ -291,45 +331,53 @@ proc cmd_cat*(args: seq[string], input: PipelineData): PipelineData =
proc cmd_write*(args: seq[string], input: PipelineData): PipelineData =
## write <filename> <content>
## Uses USERLAND SFS (Block Valve architecture)
if args.len < 2:
print("Usage: write <filename> <content>\n")
when not defined(NIPBOX_LITE):
if args.len < 2:
print("Usage: write <filename> <content>\n")
return @[]
let filename = args[0]
let content = args[1..^1].join(" ")
# Mount userland FS if not already done
if not sfs.sfs_is_mounted():
discard sfs.sfs_mount()
let bytes_written = sfs.sfs_write(filename, cast[pointer](unsafeAddr content[0]), content.len)
if bytes_written > 0:
print("[Glass Vault] Written " & $bytes_written & " bytes to: " & filename & " (Userland SFS)\n")
else:
print("Error: Could not write to " & filename & "\n")
return @[]
let filename = args[0]
let content = args[1..^1].join(" ")
# Mount userland FS if not already done
if not sfs.sfs_is_mounted():
discard sfs.sfs_mount()
let bytes_written = sfs.sfs_write(filename, cast[pointer](unsafeAddr content[0]), content.len)
if bytes_written > 0:
print("[Glass Vault] Written " & $bytes_written & " bytes to: " & filename & " (Userland SFS)\n")
else:
print("Error: Could not write to " & filename & "\n")
return @[]
print("[nipbox] 'write' requires SFS (not available in lite mode)\n")
return @[]
proc cmd_read*(args: seq[string], input: PipelineData): PipelineData =
## read <filename>
## Uses USERLAND SFS (Block Valve architecture)
if args.len == 0:
print("Usage: read <filename>\n")
when not defined(NIPBOX_LITE):
if args.len == 0:
print("Usage: read <filename>\n")
return @[]
let filename = args[0]
# Mount userland FS if not already done
if not sfs.sfs_is_mounted():
discard sfs.sfs_mount()
var buf: array[4096, char]
let bytes_read = sfs.sfs_read(filename, addr buf[0], 4096)
if bytes_read > 0:
discard lb.write(cint(1), addr buf[0], csize_t(bytes_read))
print("\n[Glass Vault] Read " & $bytes_read & " bytes from: " & filename & " (Userland SFS)\n")
else:
print("Error: Could not open " & filename & "\n")
return @[]
let filename = args[0]
# Mount userland FS if not already done
if not sfs.sfs_is_mounted():
discard sfs.sfs_mount()
var buf: array[4096, char]
let bytes_read = sfs.sfs_read(filename, addr buf[0], 4096)
if bytes_read > 0:
discard lb.write(cint(1), addr buf[0], csize_t(bytes_read))
print("\n[Glass Vault] Read " & $bytes_read & " bytes from: " & filename & " (Userland SFS)\n")
else:
print("Error: Could not open " & filename & "\n")
return @[]
print("[nipbox] 'read' requires SFS (not available in lite mode)\n")
return @[]
proc cmd_edit*(args: seq[string], input: PipelineData): PipelineData =
if args.len == 0:
@ -482,155 +530,142 @@ proc cmd_http_get*(args: seq[string], input: PipelineData): PipelineData =
return @[node]
proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
if args.len < 2:
print("Usage: http.download <ip:port/path> <outfile>\n")
return @[]
when not defined(NIPBOX_LITE):
if args.len < 2:
print("Usage: http.download <ip:port/path> <outfile>\n")
return @[]
let url_arg = args[0]
let outfile = args[1]
let url_arg = args[0]
let outfile = args[1]
var host_part = url_arg
var path_str = "/"
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 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 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_str = parts[0]
let port = uint16(parseInt(parts[1]))
# Parse IP
var ip_val: uint32 = 0
try:
let p = ip_str.split('.')
ip_val = (uint32(parseInt(p[0])) and 0xFF) or
((uint32(parseInt(p[1])) and 0xFF) shl 8) or
((uint32(parseInt(p[2])) and 0xFF) shl 16) or
((uint32(parseInt(p[3])) and 0xFF) shl 24)
except:
print("Error: Invalid IP\n")
return @[]
# Parse IP
var ip_val: uint32 = 0
try:
let p = ip_str.split('.')
ip_val = (uint32(parseInt(p[0])) and 0xFF) or
((uint32(parseInt(p[1])) and 0xFF) shl 8) or
((uint32(parseInt(p[2])) and 0xFF) shl 16) or
((uint32(parseInt(p[3])) and 0xFF) shl 24)
except:
print("Error: Invalid IP\n")
return @[]
print("[Download] Connecting to " & host_part & "...\n")
let fd = lb.socket(2, 1, 0)
if fd < 0: return @[]
print("[Download] Connecting to " & host_part & "...\n")
let fd = lb.socket(2, 1, 0)
if fd < 0: return @[]
# SockAddr setup
var addr_buf: array[16, byte]
copyMem(addr addr_buf[2], unsafeAddr port, 2)
copyMem(addr addr_buf[4], unsafeAddr ip_val, 4)
# SockAddr setup
var addr_buf: array[16, byte]
copyMem(addr addr_buf[2], unsafeAddr port, 2)
copyMem(addr addr_buf[4], unsafeAddr ip_val, 4)
if lb.connect(fd, addr addr_buf[0], 16) < 0:
print("Error: Connection Failed.\n")
return @[]
if lb.connect(fd, addr addr_buf[0], 16) < 0:
print("Error: Connection Failed.\n")
return @[]
# Request
let req = "GET " & path_str & " HTTP/1.0\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 @[]
# Mount SFS if needed
if not sfs.sfs_is_mounted():
if not sfs.sfs_mount():
print("Error: Could not mount SFS.\n")
# Request
let req = "GET " & path_str & " HTTP/1.0\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 SFS Stream
let sfs_h = sfs.sfs_open_write(outfile)
if sfs_h == nil:
print("Error: Could not create file " & outfile & "\n")
discard lb.close(cint(fd))
return @[]
# Mount SFS if needed
if not sfs.sfs_is_mounted():
if not sfs.sfs_mount():
print("Error: Could not mount SFS.\n")
discard lb.close(cint(fd))
return @[]
print("[Download] Downloading...\n")
# Open SFS Stream
let sfs_h = sfs.sfs_open_write(outfile)
if sfs_h == nil:
print("Error: Could not create file " & outfile & "\n")
discard lb.close(cint(fd))
return @[]
var buf: array[4096, char]
var header_acc = ""
var header_parsed = false
var total_bytes = 0
var content_len = -1
var timeout = 0
print("[Download] Downloading...\n")
while timeout < 10000:
# Use libc shim which pumps stack
let n = lb.recv(cint(fd), addr buf[0], 4096, 0)
var buf: array[4096, char]
var header_acc = ""
var header_parsed = false
var total_bytes = 0
var content_len = -1
var timeout = 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
while timeout < 10000:
let n = lb.recv(cint(fd), addr buf[0], 4096, 0)
# Try to find Content-Length
# Quick hacky parse
let lower_head = header_acc.toLowerAscii()
let cl_idx = lower_head.find("content-length:")
if cl_idx != -1:
let end_line = lower_head.find("\r\n", cl_idx)
if end_line != -1:
try:
content_len = parseInt(lower_head[cl_idx+15..<end_line].strip())
except:
content_len = -1
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]
sfs.sfs_write_chunk(sfs_h, cast[pointer](unsafeAddr chunk[0]), chunk.len)
total_bytes += chunk.len
header_acc = ""
let lower_head = header_acc.toLowerAscii()
let cl_idx = lower_head.find("content-length:")
if cl_idx != -1:
let end_line = lower_head.find("\r\n", cl_idx)
if end_line != -1:
try:
content_len = parseInt(lower_head[cl_idx+15..<end_line].strip())
except:
content_len = -1
let body_start = sep + 4
if body_start < header_acc.len:
let chunk = header_acc[body_start..^1]
sfs.sfs_write_chunk(sfs_h, cast[pointer](unsafeAddr chunk[0]), chunk.len)
total_bytes += chunk.len
header_acc = ""
else:
if header_acc.len > 8192:
print("Error: Headers too large.\n")
break
else:
if header_acc.len > 8192:
print("Error: Headers too large.\n")
break
sfs.sfs_write_chunk(sfs_h, addr buf[0], int(n))
total_bytes += int(n)
if content_len > 0:
if total_bytes mod 10240 < int(n): print(".")
else:
if total_bytes mod 10240 < int(n): print(".")
elif n == 0:
break
else:
# Stream directly to SFS
sfs.sfs_write_chunk(sfs_h, addr buf[0], int(n))
total_bytes += int(n)
break
# Progress Bar
if content_len > 0:
# let pct = (total_bytes * 100) div content_len
if total_bytes mod 10240 < int(n): print(".")
else:
if total_bytes mod 10240 < int(n): print(".")
elif n == 0:
break
else:
timeout += 1
# Busy wait / pump handled in recv?
# Recv calls pump_membrane_stack loop
# But if we return -1 (EAGAIN), we need to retry.
# My libc.libc_recv returns 0 on closed?
# Actually libc_recv in step 945 waits until data or closed.
# So n==0 means closed.
# Wait, libc.nim recv implementation:
# while true: pump; if data return n; if closed return 0.
# So it blocks until data.
# Thus n > 0 always unless closed.
break
sfs.sfs_close_write(sfs_h)
discard lb.close(cint(fd))
print("\n[Download] Complete. " & $total_bytes & " bytes written to " & outfile & " (Glass Vault).\n")
return @[]
sfs.sfs_close_write(sfs_h)
discard lb.close(cint(fd))
print("\n[Download] Complete. " & $total_bytes & " bytes written to " & outfile & " (Glass Vault).\n")
return @[]
else:
print("[nipbox] 'http.download' requires SFS (not available in lite mode)\n")
return @[]
# Phase 37: HTTP Verification Tool
proc cmd_http_test*(args: seq[string], input: PipelineData): PipelineData =
if args.len < 1:
print("Usage: http <host>\n")
print("Usage: http.test <host>\n")
return @[]
let host = args[0]
@ -646,16 +681,13 @@ proc cmd_http_test*(args: seq[string], input: PipelineData): PipelineData =
print("Waiting for response...\n")
# Simple read loop
var total = 0
while true:
# lb.pump_membrane_stack()
let resp = lnet.net_recv(fd, 512)
if resp.len > 0:
print(resp)
total += resp.len
else:
# End of stream or empty poll
break
print("\n[HTTP] Closed. Total bytes: " & $total & "\n")
@ -774,8 +806,18 @@ proc cmd_set*(args: seq[string], input: PipelineData): PipelineData =
proc cmd_help*(args: seq[string], input: PipelineData): PipelineData =
print("NipBox " & NIPBOX_VERSION & " (Phase 34: Orbital Drop)\n")
print("Commands: ls, cat, echo, where, http, http.get, http.download, from_json, mount, matrix, set, if, while, help, exit\n")
when defined(NIPBOX_LITE):
print("NipBox " & NIPBOX_VERSION & " [LITE] (Phase 34: Orbital Drop)\n")
print("Commands: ls, cat, cp, mv, touch, edit, echo, where, http, http.get,\n")
print(" http.test, http.serve, from_json, mount, matrix, crash,\n")
print(" sys.upgrade, set, if, while, help, exit\n")
print("Disabled: write, read, http.download (requires SFS)\n")
else:
print("NipBox " & NIPBOX_VERSION & " (Phase 34: Orbital Drop)\n")
print("Commands: ls, cat, cp, mv, touch, edit, echo, where, write, read,\n")
print(" http, http.get, http.download, http.test, http.serve,\n")
print(" from_json, mount, matrix, crash, sys.upgrade,\n")
print(" set, if, while, help, exit\n")
return @[]
# --- DISPATCHER ---