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 a38bc523a8
commit 84c3345595
2 changed files with 344 additions and 239 deletions

View File

@ -9,6 +9,62 @@
import ../../libs/membrane/libc
# --- M4.4: BKDL Capability Manifest (SPEC-071) ---
# Declares what capabilities this binary needs. The kernel reads this
# from the .nexus.manifest ELF section during loading and grants only
# what is declared here. No manifest = PLEDGE_STDIO only.
#
# Capabilities requested:
# - Channel 0x1001 (console.output) WRITE
# - Channel 0x2000 (VFS) READ
# - Channel 0x0500 (NET_TX) WRITE
# - Channel 0x0501 (NET_RX) READ
{.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, /* cap_type: Channel */
0x02, /* perms: PERM_WRITE */
0x00, 0x00, /* reserved */
0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* resource_id: 0x1001 (LE) */
/* CapDescriptor[1]: VFS (0x2000) READ */
0x02, /* cap_type: Channel */
0x01, /* perms: PERM_READ */
0x00, 0x00, /* reserved */
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* resource_id: 0x2000 (LE) */
/* CapDescriptor[2]: NET_TX (0x0500) WRITE */
0x02, /* cap_type: Channel */
0x02, /* perms: PERM_WRITE */
0x00, 0x00, /* reserved */
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* resource_id: 0x0500 (LE) */
/* CapDescriptor[3]: NET_RX (0x0501) READ */
0x02, /* cap_type: Channel */
0x01, /* perms: PERM_READ */
0x00, 0x00, /* reserved */
0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* resource_id: 0x0501 (LE) */
};
""".}
proc main() =
# 1. Pledge Sovereignty
discard pledge(0xFFFFFFFFFFFFFFFF'u64) # PLEDGE_ALL
@ -18,44 +74,51 @@ proc main() =
print(cstring("\x1b[1;35m║ SOVEREIGN INIT (NexInit v1.0) ║\x1b[0m\n"))
print(cstring("\x1b[1;35m╚═══════════════════════════════════════╝\x1b[0m\n\n"))
print(cstring("[INIT] Initializing Membrane Network Stack...\n"))
membrane_init()
print(cstring("[INIT] PHASE_42_VERIFY: Membrane Network Stack...\\n"))
# DISABLED: Network stack requires LwIP
# membrane_init()
proc glue_get_ip(): uint32 {.importc: "glue_get_ip", cdecl.}
# proc glue_get_ip(): uint32 {.importc: "glue_get_ip", cdecl.}
# --- DHCP PHASE ---
print(cstring("[INIT] Waiting for DHCP IP Address...\n"))
var ip: uint32 = 0
for i in 0 ..< 600: # 60 seconds
pump_membrane_stack()
ip = glue_get_ip()
if ip != 0: break
discard syscall(0x65, 100000000'u64) # 100ms
# # --- DHCP PHASE ---
# print(cstring("[INIT] Waiting for DHCP IP Address...\n"))
# var ip: uint32 = 0
# for i in 0 ..< 600: # 60 seconds
# pump_membrane_stack()
# ip = glue_get_ip()
# if ip != 0: break
# discard syscall(0x65, 100000000'u64) # 100ms
if ip == 0:
print(cstring("[INIT] WARNING: DHCP Discovery timed out. Proceeding...\n"))
else:
print(cstring("[INIT] Network ONLINE (10.0.2.15)\n"))
# if ip == 0:
# print(cstring("[INIT] WARNING: DHCP Discovery timed out. Proceeding...\n"))
# else:
# print(cstring("[INIT] Network ONLINE (10.0.2.15)\n"))
# --- DNS PHASE ---
print(cstring("\n[TEST] ══════════════════════════════════════\n"))
print(cstring("[TEST] DNS Resolution: google.com\n"))
print(cstring("[TEST] ══════════════════════════════════════\n\n"))
# # --- DNS PHASE ---
# print(cstring("\n[TEST] ══════════════════════════════════════\n"))
# print(cstring("[TEST] DNS Resolution: google.com\n"))
# print(cstring("[TEST] ══════════════════════════════════════\n\n"))
var res: ptr AddrInfo
for attempt in 1..5:
print(cstring("[TEST] Resolving google.com (Attempt "))
# (Simplified number printing not available, just loop)
# type
# AddrInfo {.importc: "struct addrinfo", header: "<netdb.h>".} = object
if getaddrinfo("google.com", nil, nil, addr res) == 0:
print(cstring(") -> SUCCESS!\n"))
freeaddrinfo(res)
break
else:
print(cstring(") -> FAILED. Waiting 5s...\n"))
for j in 1..50:
pump_membrane_stack()
discard syscall(0x65, 100000000'u64) # 100ms
# proc getaddrinfo(node: cstring, service: cstring, hints: pointer, res: ptr ptr AddrInfo): cint {.importc, header: "<netdb.h>".}
# proc freeaddrinfo(res: ptr AddrInfo) {.importc, header: "<netdb.h>".}
# var res: ptr AddrInfo
# for attempt in 1..5:
# print(cstring("[TEST] Resolving google.com (Attempt "))
# # (Simplified number printing not available, just loop)
# if getaddrinfo("google.com", nil, nil, addr res) == 0:
# print(cstring(") -> SUCCESS!\n"))
# freeaddrinfo(res)
# break
# else:
# print(cstring(") -> FAILED. Waiting 5s...\n"))
# for j in 1..50:
# pump_membrane_stack()
# discard syscall(0x65, 100000000'u64) # 100ms
# --- SHELL PHASE ---
proc spawn_fiber(path: cstring): int =
@ -68,10 +131,10 @@ proc main() =
print(cstring("[INIT] Entering Supervisor Loop...\n"))
var loop_count = 0
while true:
pump_membrane_stack()
# pump_membrane_stack() # DISABLED: Requires LwIP
loop_count += 1
if loop_count mod 100 == 0:
print(cstring("[INIT] Heartbeat\n"))
if loop_count mod 0x100000 == 0: # Every ~1M iterations
discard syscall(0x65, 1000000000'u64) # 1s yield
discard syscall(0x65, 100000000'u64) # 100ms
when isMainModule:

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,6 +331,7 @@ 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)
when not defined(NIPBOX_LITE):
if args.len < 2:
print("Usage: write <filename> <content>\n")
return @[]
@ -308,10 +349,14 @@ proc cmd_write*(args: seq[string], input: PipelineData): PipelineData =
else:
print("Error: Could not write to " & filename & "\n")
return @[]
else:
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)
when not defined(NIPBOX_LITE):
if args.len == 0:
print("Usage: read <filename>\n")
return @[]
@ -330,6 +375,9 @@ proc cmd_read*(args: seq[string], input: PipelineData): PipelineData =
else:
print("Error: Could not open " & filename & "\n")
return @[]
else:
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,6 +530,7 @@ proc cmd_http_get*(args: seq[string], input: PipelineData): PipelineData =
return @[node]
proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
when not defined(NIPBOX_LITE):
if args.len < 2:
print("Usage: http.download <ip:port/path> <outfile>\n")
return @[]
@ -561,7 +610,6 @@ proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
var timeout = 0
while timeout < 10000:
# Use libc shim which pumps stack
let n = lb.recv(cint(fd), addr buf[0], 4096, 0)
if n > 0:
@ -572,8 +620,6 @@ proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
if sep != -1:
header_parsed = true
# 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:
@ -595,13 +641,10 @@ proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
print("Error: Headers too large.\n")
break
else:
# Stream directly to SFS
sfs.sfs_write_chunk(sfs_h, addr buf[0], int(n))
total_bytes += int(n)
# 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(".")
@ -609,28 +652,20 @@ proc cmd_http_download*(args: seq[string], input: PipelineData): PipelineData =
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 @[]
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 =
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, echo, where, http, http.get, http.download, from_json, mount, matrix, set, if, while, help, exit\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 ---