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
ccaa10c509
commit
4e0e9ed467
195
core/kernel.nim
195
core/kernel.nim
|
|
@ -13,6 +13,42 @@ var ion_paused*: bool = false
|
|||
var pause_start*: uint64 = 0
|
||||
var matrix_enabled*: bool = false
|
||||
|
||||
# --- CORE LOGGING ---
|
||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
proc kwrite*(p: pointer, len: csize_t) {.exportc, cdecl.} =
|
||||
if p != nil and len > 0:
|
||||
console_write(p, len)
|
||||
|
||||
proc kprint*(s: cstring) {.exportc, cdecl.} =
|
||||
if s != nil:
|
||||
let length = len(s)
|
||||
if length > 0:
|
||||
kwrite(cast[pointer](s), csize_t(length))
|
||||
|
||||
proc kprint_hex*(n: uint64) {.exportc, cdecl.} =
|
||||
const hex_chars = "0123456789ABCDEF"
|
||||
var buf: array[18, char]
|
||||
buf[0] = '0'
|
||||
buf[1] = 'x'
|
||||
for i in 0..15:
|
||||
let nibble = (n shr (60 - (i * 4))) and 0xF
|
||||
buf[i+2] = hex_chars[nibble]
|
||||
console_write(addr buf[0], 18)
|
||||
|
||||
proc kprintln*(s: cstring) {.exportc, cdecl.} =
|
||||
kprint(s); kprint("\n")
|
||||
|
||||
proc write*(fd: cint, p: pointer, len: csize_t): csize_t {.exportc, cdecl.} =
|
||||
console_write(p, len)
|
||||
return len
|
||||
|
||||
|
||||
# Wrapper for VFS write to handle stdout/stderr
|
||||
proc wrapper_vfs_write(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.} =
|
||||
if fd == 1 or fd == 2:
|
||||
console_write(buf, csize_t(count))
|
||||
return int64(count)
|
||||
return ion_vfs_write(fd, buf, count)
|
||||
|
||||
# =========================================================
|
||||
# Fiber Management (Forward Declared)
|
||||
|
|
@ -36,13 +72,19 @@ var subject_loading_path: string = "bin/nipbox"
|
|||
proc subject_fiber_entry() {.cdecl.} =
|
||||
## The Sovereign Container for Userland Consciousness.
|
||||
## This loop persists across program reloads.
|
||||
kprintln("[Subject] Fiber Entry reached.")
|
||||
while true:
|
||||
kprint("[Subject] Attempting to load: ")
|
||||
kprintln(cstring(subject_loading_path))
|
||||
let entry = kload(subject_loading_path)
|
||||
if entry != 0:
|
||||
kprintln("[Subject] Consciousness Transferred.")
|
||||
rumpk_enter_userland(entry)
|
||||
else:
|
||||
kprint("[Subject] Failed to load: ")
|
||||
kprintln(cstring(subject_loading_path))
|
||||
|
||||
kprintln("[Subject] Failed to load or returned. Pausing for Rebirth.")
|
||||
kprintln("[Subject] Pausing for Rebirth.")
|
||||
fiber_yield()
|
||||
|
||||
# --- STACK ALLOCATIONS ---
|
||||
|
|
@ -52,35 +94,7 @@ var stack_ui {.align: 16.}: array[32768, uint8]
|
|||
var stack_subject {.align: 16.}: array[32768, uint8]
|
||||
var stack_watchdog {.align: 16.}: array[4096, uint8]
|
||||
|
||||
# Exports for Zig NPLs
|
||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
proc write*(fd: cint, p: pointer, len: csize_t): csize_t {.exportc, cdecl.} =
|
||||
console_write(p, len)
|
||||
return len
|
||||
|
||||
# Utility for Logic Core
|
||||
proc kwrite*(p: pointer, len: csize_t) {.exportc, cdecl.} =
|
||||
if p != nil and len > 0:
|
||||
console_write(p, len)
|
||||
|
||||
proc kprint*(s: cstring) {.exportc, cdecl.} =
|
||||
if s != nil:
|
||||
let length = len(s)
|
||||
if length > 0:
|
||||
kwrite(cast[pointer](s), csize_t(length))
|
||||
|
||||
proc kprint_hex*(n: uint64) {.exportc, cdecl.} =
|
||||
const hex_chars = "0123456789ABCDEF"
|
||||
var buf: array[18, char]
|
||||
buf[0] = '0'
|
||||
buf[1] = 'x'
|
||||
for i in 0..15:
|
||||
let nibble = (n shr (60 - (i * 4))) and 0xF
|
||||
buf[i+2] = hex_chars[nibble]
|
||||
console_write(addr buf[0], 18)
|
||||
|
||||
proc kprintln*(s: cstring) {.exportc, cdecl.} =
|
||||
kprint(s); kprint("\n")
|
||||
|
||||
# Phase 31: Memory Manager (The Glass Cage)
|
||||
proc mm_init() {.importc, cdecl.}
|
||||
|
|
@ -113,9 +127,6 @@ var chan_cmd*: SovereignChannel[CmdPacket]
|
|||
# chan_input is now imported from ion.nim!
|
||||
|
||||
proc ion_push_stdin*(p: pointer, len: csize_t) {.exportc, cdecl.} =
|
||||
## Push raw console data into the Userland Input Ring
|
||||
|
||||
# [FIX] Safety Guard
|
||||
if chan_input.ring == nil:
|
||||
return
|
||||
|
||||
|
|
@ -163,15 +174,15 @@ proc rumpk_yield_internal() {.cdecl, exportc.} =
|
|||
let load = get_ion_load()
|
||||
let now = get_now_ns()
|
||||
|
||||
# 🏛️ ADAPTIVE GOVERNOR (Phase 3: FLOOD CONTROL)
|
||||
if load > 200:
|
||||
if current_fiber != addr fiber_ion:
|
||||
switch(addr fiber_ion)
|
||||
return
|
||||
elif load > 0:
|
||||
if current_fiber == addr fiber_subject:
|
||||
switch(addr fiber_ion)
|
||||
return
|
||||
# 🏛️ ADAPTIVE GOVERNOR (Phase 3: FLOOD CONTROL) - Temporarily disabled for debugging starvation
|
||||
# if load > 200:
|
||||
# if current_fiber != addr fiber_ion:
|
||||
# switch(addr fiber_ion)
|
||||
# return
|
||||
# elif load > 0:
|
||||
# if current_fiber == addr fiber_subject:
|
||||
# switch(addr fiber_ion)
|
||||
# return
|
||||
|
||||
# Normal Round Robin logic with Sleep Check
|
||||
var next_fiber: Fiber = nil
|
||||
|
|
@ -179,8 +190,7 @@ proc rumpk_yield_internal() {.cdecl, exportc.} =
|
|||
if current_fiber == addr fiber_ion:
|
||||
next_fiber = addr fiber_nexshell
|
||||
elif current_fiber == addr fiber_nexshell:
|
||||
next_fiber = addr fiber_ui
|
||||
elif current_fiber == addr fiber_ui:
|
||||
# Phase 33 Debug: Skip UI fiber if problematic
|
||||
next_fiber = addr fiber_subject
|
||||
elif current_fiber == addr fiber_subject:
|
||||
next_fiber = addr fiber_watchdog
|
||||
|
|
@ -196,21 +206,27 @@ proc rumpk_yield_internal() {.cdecl, exportc.} =
|
|||
|
||||
# Move to next in sequence
|
||||
if next_fiber == addr fiber_ion: next_fiber = addr fiber_nexshell
|
||||
elif next_fiber == addr fiber_nexshell: next_fiber = addr fiber_ui
|
||||
elif next_fiber == addr fiber_ui: next_fiber = addr fiber_subject
|
||||
elif next_fiber == addr fiber_nexshell: next_fiber = addr fiber_subject
|
||||
elif next_fiber == addr fiber_subject: next_fiber = addr fiber_watchdog
|
||||
else: next_fiber = addr fiber_ion
|
||||
|
||||
# Force found = true for now
|
||||
found = true
|
||||
|
||||
if found and next_fiber != current_fiber:
|
||||
# Idle loop
|
||||
# kprint(".")
|
||||
switch(next_fiber)
|
||||
elif not found:
|
||||
asm "csrsi sstatus, 2"
|
||||
asm "wfi"
|
||||
|
||||
# =========================================================
|
||||
# ION Intelligence Fiber (Core System Supervisor)
|
||||
# =========================================================
|
||||
|
||||
proc ion_fiber_entry() {.cdecl.} =
|
||||
# kprintln("[ION] Alive")
|
||||
hal_io_init()
|
||||
kprintln("[ION] Fiber 1 Reporting for Duty.")
|
||||
while true:
|
||||
|
|
@ -428,6 +444,23 @@ proc k_pledge(promises: uint64): int32 {.exportc, cdecl.} =
|
|||
kprintln("")
|
||||
|
||||
return 0
|
||||
proc k_handle_exception*(scause, sepc, stval: uint) {.exportc, cdecl.} =
|
||||
kprint("\n[SECURITY] EXCEPTION! scause=")
|
||||
kprint_hex(uint64(scause))
|
||||
kprint(" sepc=")
|
||||
kprint_hex(uint64(sepc))
|
||||
kprint(" stval=")
|
||||
kprint_hex(uint64(stval))
|
||||
kprintln("\n")
|
||||
|
||||
if current_fiber != nil:
|
||||
kprint("[SECURITY] Faulting Fiber: ")
|
||||
if current_fiber.name != nil: kprint(current_fiber.name)
|
||||
else: kprint_hex(current_fiber.id)
|
||||
kprintln("")
|
||||
|
||||
# Non-recoverable for now: Stay in loop
|
||||
while true: discard
|
||||
|
||||
proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
||||
case nr:
|
||||
|
|
@ -455,13 +488,38 @@ proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
|||
return cast[uint](-1)
|
||||
return uint(ion_vfs_list(cast[pointer](a0), uint64(a1)))
|
||||
of 0x203: # READ
|
||||
# Phase 28: Enforce RPATH
|
||||
# Phase 28: Enforce RPATH/STDIO
|
||||
if a0 == 0:
|
||||
if (current_fiber.promises and PLEDGE_STDIO) == 0:
|
||||
kprintln("[SECURITY] PLEDGE VIOLATION: STDIO required for read(0)")
|
||||
return cast[uint](-1)
|
||||
|
||||
var pkt: IonPacket
|
||||
kprintln("[Kernel] sys_read(0)")
|
||||
if chan_input.recv(pkt):
|
||||
let n = if uint64(pkt.len) < a2: uint64(pkt.len) else: a2
|
||||
if n > 0:
|
||||
copyMem(cast[pointer](a1), cast[pointer](pkt.data), int(n))
|
||||
ion_free_raw(pkt.id)
|
||||
return n
|
||||
else:
|
||||
# No data from NexShell, yield to let it run
|
||||
fiber_yield()
|
||||
return 0
|
||||
|
||||
if (current_fiber.promises and PLEDGE_RPATH) == 0:
|
||||
kprintln("[SECURITY] PLEDGE VIOLATION: RPATH required for read")
|
||||
return cast[uint](-1)
|
||||
return uint(ion_vfs_read(int32(a0), cast[pointer](a1), uint64(a2)))
|
||||
of 0x204: # WRITE
|
||||
# Phase 28: Enforce WPATH
|
||||
# Phase 28: Enforce WPATH/STDIO
|
||||
if a0 == 1 or a0 == 2:
|
||||
if (current_fiber.promises and PLEDGE_STDIO) == 0:
|
||||
kprintln("[SECURITY] PLEDGE VIOLATION: STDIO required for write(1/2)")
|
||||
return cast[uint](-1)
|
||||
console_write(cast[pointer](a1), csize_t(a2))
|
||||
return a2
|
||||
|
||||
if (current_fiber.promises and PLEDGE_WPATH) == 0:
|
||||
kprintln("[SECURITY] PLEDGE VIOLATION: WPATH required for write")
|
||||
return cast[uint](-1)
|
||||
|
|
@ -492,12 +550,12 @@ proc kmain() {.exportc, cdecl.} =
|
|||
# [FIX] Input Channel Init BEFORE Drivers
|
||||
ion_init_input()
|
||||
|
||||
# Phase 31: The Identity Switch (THE CROSSING)
|
||||
kprintln("[MM] Building Sv39 Page Tables...")
|
||||
mm_init()
|
||||
kprintln("[MM] Activating Identity Map...")
|
||||
mm_enable_kernel_paging()
|
||||
kprintln("[MM] ✓ Virtual Memory Active. Reality is Virtual.")
|
||||
# Phase 31: The Identity Switch (THE CROSSING) - Temporarily disabled
|
||||
# kprintln("[MM] Building Sv39 Page Tables...")
|
||||
# mm_init()
|
||||
# kprintln("[MM] Activating Identity Map...")
|
||||
# mm_enable_kernel_paging()
|
||||
# kprintln("[MM] ✓ Virtual Memory Active. Reality is Virtual.")
|
||||
|
||||
hal_io_init()
|
||||
|
||||
|
|
@ -513,10 +571,11 @@ proc kmain() {.exportc, cdecl.} =
|
|||
sys.fn_vfs_open = ion_vfs_open
|
||||
sys.fn_vfs_read = ion_vfs_read
|
||||
sys.fn_vfs_list = ion_vfs_list
|
||||
sys.fn_vfs_write = ion_vfs_write
|
||||
sys.fn_vfs_write = wrapper_vfs_write
|
||||
sys.fn_vfs_close = ion_vfs_close
|
||||
sys.fn_log = cast[pointer](kwrite)
|
||||
sys.fn_pledge = k_pledge # Phase 28: Pledge
|
||||
sys.fn_yield = cast[proc() {.cdecl.}](kernel.fiber_yield)
|
||||
|
||||
# 1.5 The Retina (VirtIO-GPU)
|
||||
proc virtio_gpu_init(base: uint64) {.importc, cdecl.}
|
||||
|
|
@ -559,7 +618,8 @@ proc kmain() {.exportc, cdecl.} =
|
|||
sys_table.s_event = addr guest_event_hal
|
||||
sys_table.s_cmd = addr guest_cmd_hal
|
||||
sys_table.s_input = chan_input.ring # From global
|
||||
|
||||
|
||||
|
||||
# Framebuffer info (Phase 26: Visual Cortex)
|
||||
sys_table.fb_addr = fb_kern_get_addr()
|
||||
sys_table.fb_width = 800 # From framebuffer.zig
|
||||
|
|
@ -574,29 +634,26 @@ proc kmain() {.exportc, cdecl.} =
|
|||
|
||||
# 4. Deployment
|
||||
kprintln("[Kernel] Spawning System Fibers...")
|
||||
|
||||
# Phase 28: Initialize all fibers with full capabilities
|
||||
fiber_ion.promises = PLEDGE_ALL
|
||||
fiber_nexshell.promises = PLEDGE_ALL
|
||||
fiber_ui.promises = PLEDGE_ALL
|
||||
fiber_subject.promises = PLEDGE_ALL
|
||||
fiber_watchdog.promises = PLEDGE_ALL
|
||||
|
||||
# 1. ION FIBER (The Valve)
|
||||
kprintln(" → fiber_ion")
|
||||
fiber_ion.name = "ion"
|
||||
init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion))
|
||||
|
||||
# 2. NEXSHELL FIBER (The Brain)
|
||||
kprintln(" → fiber_nexshell")
|
||||
fiber_nexshell.name = "nexshell"
|
||||
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0],
|
||||
sizeof(stack_nexshell))
|
||||
|
||||
# 3. UI FIBER (The Face)
|
||||
init_fiber(addr fiber_ui, ui_fiber_entry, addr stack_ui[0], sizeof(stack_ui))
|
||||
# 3. UI FIBER (The Face) - Temporarily disabled to debug boot hang
|
||||
# fiber_ui.name = "ui"
|
||||
# init_fiber(addr fiber_ui, ui_fiber_entry, addr stack_ui[0], sizeof(stack_ui))
|
||||
|
||||
# 4. SUBJECT FIBER (The Payload)
|
||||
kprintln(" → fiber_subject")
|
||||
fiber_subject.name = "subject"
|
||||
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0],
|
||||
sizeof(stack_subject))
|
||||
|
||||
# 5. WATCHDOG FIBER (The Immune System)
|
||||
kprintln(" → fiber_watchdog")
|
||||
fiber_watchdog.name = "watchdog"
|
||||
init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog))
|
||||
|
||||
# [FIX] GLOBAL INTERRUPT ENABLE
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ export fn trap_entry() callconv(.naked) void {
|
|||
// L1 Kernel Logic
|
||||
extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;
|
||||
|
||||
extern fn k_handle_exception(scause: usize, sepc: usize, stval: usize) void;
|
||||
|
||||
export fn rss_trap_handler(frame: *TrapFrame) void {
|
||||
const scause = frame.scause;
|
||||
|
||||
|
|
@ -193,17 +195,12 @@ export fn rss_trap_handler(frame: *TrapFrame) void {
|
|||
return;
|
||||
}
|
||||
|
||||
uart.print("\n\n!!! SOVEREIGN TRAP !!!\n");
|
||||
uart.print("SCAUSE: 0x");
|
||||
uart.print_hex(scause);
|
||||
uart.print("\n");
|
||||
uart.print("SEPC: 0x");
|
||||
uart.print_hex(frame.sepc);
|
||||
uart.print("\n");
|
||||
uart.print("STVAL: 0x");
|
||||
uart.print_hex(frame.stval);
|
||||
uart.print("\n");
|
||||
uart.print("SYSTEM HALTED.\n");
|
||||
// Delegate all other exceptions to the Kernel Immune System
|
||||
// It will decide whether to segregate (worker) or halt (system)
|
||||
// Note: k_handle_exception handles flow control (yield/halt) and does not return
|
||||
k_handle_exception(scause, frame.sepc, frame.stval);
|
||||
|
||||
// Safety halt if kernel returns (should be unreachable)
|
||||
while (true) {}
|
||||
}
|
||||
|
||||
|
|
@ -237,6 +234,7 @@ export fn console_read() c_int {
|
|||
const virtio_block = @import("virtio_block.zig");
|
||||
|
||||
export fn hal_io_init() void {
|
||||
uart.init();
|
||||
virtio_net.init();
|
||||
virtio_block.init();
|
||||
}
|
||||
|
|
|
|||
24
hal/uart.zig
24
hal/uart.zig
|
|
@ -18,7 +18,10 @@ const NS16550A_LSR: usize = 0x05; // Line Status Register
|
|||
const NS16550A_THRE: u8 = 1 << 5; // Transmitter Holding Register Empty
|
||||
|
||||
pub fn init() void {
|
||||
// QEMU devices are usually pre-initialized by firmware (EDK2/OpenSBI)
|
||||
switch (builtin.cpu.arch) {
|
||||
.riscv64 => init_riscv(),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
const NS16550A_IER: usize = 0x01; // Interrupt Enable Register
|
||||
|
|
@ -27,6 +30,13 @@ pub fn init_riscv() void {
|
|||
// Disable Interrupts to rely on Polling (prevents Interrupt Storms if Handler is missing)
|
||||
const ier: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_IER);
|
||||
ier.* = 0x00;
|
||||
|
||||
// Drain FIFO
|
||||
const lsr: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_LSR);
|
||||
const rbr: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_THR);
|
||||
while ((lsr.* & 0x01) != 0) {
|
||||
_ = rbr.*;
|
||||
}
|
||||
}
|
||||
|
||||
fn write_char_arm64(c: u8) void {
|
||||
|
|
@ -75,8 +85,16 @@ pub fn read_byte() ?u8 {
|
|||
.riscv64 => {
|
||||
const thr: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_THR);
|
||||
const lsr: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_LSR);
|
||||
if ((lsr.* & 0x01) != 0) { // Data Ready
|
||||
return thr.*;
|
||||
|
||||
const lsr_val = lsr.*;
|
||||
|
||||
// DIAGNOSTIC: Periodic LSR dump removed
|
||||
|
||||
if ((lsr_val & 0x01) != 0) { // Data Ready
|
||||
const b = thr.*;
|
||||
// Signal reception
|
||||
// Signal reception removed
|
||||
return b;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
|
|
|
|||
|
|
@ -168,6 +168,13 @@ proc pledge*(promises: uint64): int {.exportc, cdecl.} =
|
|||
return int(sys.fn_pledge(promises))
|
||||
return -1
|
||||
|
||||
return -1
|
||||
|
||||
proc upgrade*(target_fid: uint64, path: cstring): int {.exportc, cdecl.} =
|
||||
## Live Upgrade System (The Phoenix)
|
||||
## Returns: 0 on success, -error on failure
|
||||
return syscall(0x502, int(target_fid), cast[int](path))
|
||||
|
||||
# --- HIGH LEVEL HELPERS ---
|
||||
import strutils, sequtils
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,22 @@ proc membrane_init*() {.exportc, cdecl.} =
|
|||
when not defined(is_membrane):
|
||||
ion_pool_init()
|
||||
ion_user_init()
|
||||
|
||||
# EMERGENCY PHASE 34.3: Address Verify (Userland Side)
|
||||
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
||||
if sys != nil and sys.fn_vfs_write != nil:
|
||||
var msg = "[Membrane] Input Ring Ptr @ 0x"
|
||||
discard sys.fn_vfs_write(1, unsafeAddr msg[0], uint64(msg.len))
|
||||
# Print hex address
|
||||
let ring_addr = cast[uint64](membrane_input_ring_ptr)
|
||||
for i in countdown(15, 0):
|
||||
let nibble = (ring_addr shr (i * 4)) and 0xF
|
||||
let hex_char = if nibble < 10: char(nibble + ord('0')) else: char(nibble -
|
||||
10 + ord('A'))
|
||||
discard sys.fn_vfs_write(1, unsafeAddr hex_char, 1)
|
||||
let newline = "\n"
|
||||
discard sys.fn_vfs_write(1, unsafeAddr newline[0], 1)
|
||||
|
||||
lwip_init()
|
||||
|
||||
# Set up Virtual Interface for Subject (10.0.2.16)
|
||||
|
|
@ -230,7 +246,12 @@ proc pump_membrane_stack*() {.exportc, cdecl.} =
|
|||
ion_user_free(pkt)
|
||||
|
||||
# 2. Check Timers
|
||||
# console_write(cstring("P"), 1)
|
||||
sys_check_timeouts()
|
||||
# Phase 33: Explicit yield if we aren't calling sys_read
|
||||
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
||||
if sys.fn_yield != nil:
|
||||
sys.fn_yield()
|
||||
|
||||
proc tcp_write*(pcb: ptr TcpPcb; dataptr: pointer; len: uint16;
|
||||
apiflags: uint8): ErrT {.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
# Nexus Sovereign Boot Script
|
||||
echo "--- Initializing Sovereign Services ---"
|
||||
|
||||
echo "Activating Persistent Storage..."
|
||||
mount
|
||||
|
||||
echo "Phase 20: Testing Object Pipeline..."
|
||||
ls | where size > 0
|
||||
|
||||
echo "Phase 21: The Teleporter (Template)..."
|
||||
# http.get 10.0.2.2:8000 | from_json | where status == 200
|
||||
|
||||
echo "Phase 22: Sovereign Write Test..."
|
||||
echo "Sovereign Architecture" > /tmp/nexus.kdl
|
||||
cat /tmp/nexus.kdl
|
||||
|
||||
echo "Phase 23: Persistence Check..."
|
||||
cat persistence.txt
|
||||
echo "Systems Modified" > persistence.txt
|
||||
|
||||
echo "--- Boot Record Complete ---"
|
||||
|
|
@ -27,6 +27,7 @@ fn RingBuffer(comptime T: type) type {
|
|||
|
||||
const SysTable = extern struct {
|
||||
magic: u32,
|
||||
reserved: u32,
|
||||
s_rx: *RingBuffer(IonPacket),
|
||||
s_tx: *RingBuffer(IonPacket),
|
||||
s_event: *RingBuffer(IonPacket),
|
||||
|
|
@ -54,7 +55,22 @@ export fn nexshell_main() void {
|
|||
var input_buffer: [64]u8 = undefined;
|
||||
var input_idx: usize = 0;
|
||||
|
||||
var loop_count: usize = 0;
|
||||
var poll_pulse: usize = 0;
|
||||
while (true) {
|
||||
loop_count += 1;
|
||||
poll_pulse += 1;
|
||||
|
||||
// Heartbeat every 100 iterations
|
||||
if (loop_count % 100 == 0) {
|
||||
// Heartbeat removed
|
||||
}
|
||||
|
||||
// Polling pulse every 10k to show activity
|
||||
if (poll_pulse >= 10000) {
|
||||
// print("P");
|
||||
poll_pulse = 0;
|
||||
}
|
||||
// 1. Process Telemetry Events
|
||||
const head = @atomicLoad(u32, &event_ring.head, .acquire);
|
||||
const tail = @atomicLoad(u32, &event_ring.tail, .monotonic);
|
||||
|
|
@ -74,6 +90,10 @@ export fn nexshell_main() void {
|
|||
const c = console_read();
|
||||
if (c != -1) {
|
||||
const byte = @as(u8, @intCast(c));
|
||||
// print("[NexShell] Got char: '");
|
||||
// const char_buf = [1]u8{byte};
|
||||
// print(&char_buf);
|
||||
// print("'\n");
|
||||
|
||||
if (forward_mode) {
|
||||
// Check for escape: Ctrl+K (11)
|
||||
|
|
|
|||
Loading…
Reference in New Issue