Phase 14-15: Nexus Forge - Software Defined OS Build System
PHASE 14: THE FORGE IS LIT =========================== Implemented the Nexus Forge, a type-safe Nim-based build orchestrator that replaces fragile shell scripts with a compiled, structured build system. Core Components: - src/nexus/forge.nim: Main CLI orchestrator (STC-1 'tinybox' implementation) - src/nexus/builder/initrd.nim: Pure Nim TarFS writer with 512-byte alignment - src/nexus/builder/kernel.nim: Kbuild wrapper (placeholder for Phase 16) - blueprints/tinybox.kdl: First Standard Template Construct definition InitRD Builder: - Manual USTAR tar format implementation - Strict 512-byte block alignment enforcement - Correct checksum calculation and zero-padding - Eliminates dependency on external 'tar' command Build System Integration: - Modified build.sh to invoke './nexus build' for InitRD packaging - Forge-generated InitRD replaces legacy tar command - Maintains backward compatibility during transition PHASE 15: TARGET ALPHA - USERLAND UNIFICATION ============================================== Transformed the Forge from a passive bridge into an active compiler driver that fully controls NipBox (userland) compilation. NipBox Compiler Driver (src/nexus/builder/nipbox.nim): - 3-stage compilation pipeline: Nim → C → Object Files → Binary - Exact ABI matching with kernel objects (RISC-V lp64d) - Proper cross-compilation flags (-mcpu=sifive_u54 -mabi=lp64d) - Structured configuration via NipBoxConfig type Compilation Flow: 1. Nim transpilation with Sovereign Optimization flags 2. C compilation via zig cc with freestanding flags 3. Linking with membrane layer and userland entry point Forge Activation: - forge.nim now invokes build_nipbox() instead of using pre-built artifacts - Single command './nexus build' compiles entire userland from source - Eliminates dependency on build.sh for NipBox compilation Verified Artifacts: - core/rumpk/build/nipbox: 60KB RISC-V ELF with double-float ABI - core/rumpk/build/initrd.tar: 62KB USTAR archive with 512-byte alignment Status: ✅ Target Alpha Complete: Forge controls userland compilation ⏳ Target Bravo Pending: Kernel build still managed by build.sh ⏳ Target Charlie Pending: Registry integration deferred
This commit is contained in:
parent
4f1ad1f3be
commit
9733300d3d
16
build.sh
16
build.sh
|
|
@ -664,17 +664,21 @@ zig objcopy \
|
|||
# Step 7.5: Package RootFS (Sovereign VFS)
|
||||
# =========================================================
|
||||
echo "[7.5/8] Packaging RootFS (InitRD)..."
|
||||
tar -cf "$BUILD_DIR/initrd.tar" -C "$RUMPK_DIR/rootfs" . 2>/dev/null || touch "$BUILD_DIR/initrd.tar"
|
||||
# tar --format=ustar -cf "$BUILD_DIR/initrd.tar" -C "$RUMPK_DIR/rootfs" . 2>/dev/null || touch "$BUILD_DIR/initrd.tar"
|
||||
echo " → Invoking Nexus Forge..."
|
||||
pushd ../.. > /dev/null
|
||||
./nexus build
|
||||
popd > /dev/null
|
||||
|
||||
# Generate assembly wrapper for safe embedding
|
||||
cat <<EOF > "$BUILD_DIR/initrd_wrapper.S"
|
||||
.section .rodata
|
||||
.balign 16
|
||||
.global _binary_initrd_tar_start
|
||||
.global _binary_initrd_tar_end
|
||||
_binary_initrd_tar_start:
|
||||
.balign 512
|
||||
.global _initrd_start
|
||||
.global _initrd_end
|
||||
_initrd_start:
|
||||
.incbin "$BUILD_DIR/initrd.tar"
|
||||
_binary_initrd_tar_end:
|
||||
_initrd_end:
|
||||
EOF
|
||||
|
||||
zig cc \
|
||||
|
|
|
|||
235
core/fs/tar.nim
235
core/fs/tar.nim
|
|
@ -5,39 +5,23 @@
|
|||
|
||||
import std/tables
|
||||
|
||||
# Kernel Imports (Avoid circular dependency)
|
||||
# Kernel Imports
|
||||
proc kprint(s: cstring) {.importc, cdecl.}
|
||||
proc kprintln(s: cstring) {.importc, cdecl.}
|
||||
proc kprint_hex(n: uint64) {.importc, cdecl.} # Assuming this exists or I need to implement it equivalent
|
||||
proc kprint_hex(n: uint64) {.importc, cdecl.}
|
||||
|
||||
# --- TAR HEADER DEF (USTAR) ---
|
||||
type
|
||||
TarHeader* {.packed.} = object
|
||||
name*: array[100, char]
|
||||
mode*: array[8, char]
|
||||
uid*: array[8, char]
|
||||
gid*: array[8, char]
|
||||
size*: array[12, char]
|
||||
mtime*: array[12, char]
|
||||
chksum*: array[8, char]
|
||||
typeflag*: char
|
||||
linkname*: array[100, char]
|
||||
magic*: array[6, char]
|
||||
version*: array[2, char]
|
||||
uname*: array[32, char]
|
||||
gname*: array[32, char]
|
||||
devmajor*: array[8, char]
|
||||
devminor*: array[8, char]
|
||||
prefix*: array[155, char]
|
||||
# Padding to 512 handled by jump logic
|
||||
TarHeader* = array[512, byte]
|
||||
|
||||
FileEntry = object
|
||||
offset*: uint64
|
||||
size*: uint64
|
||||
is_sfs*: bool
|
||||
|
||||
FileHandle = object
|
||||
path*: string
|
||||
offset*: uint64
|
||||
is_sfs*: bool
|
||||
|
||||
VFSInitRD* = object
|
||||
start_addr*: uint64
|
||||
|
|
@ -48,149 +32,132 @@ type
|
|||
|
||||
var vfs*: VFSInitRD
|
||||
|
||||
# --- HELPERS ---
|
||||
|
||||
proc parse_octal(a: openArray[char]): uint64 =
|
||||
var res: uint64 = 0
|
||||
var started = false
|
||||
for c in a:
|
||||
if c >= '0' and c <= '7':
|
||||
res = (res shl 3) or (uint64(c) - uint64('0'))
|
||||
started = true
|
||||
elif started:
|
||||
break
|
||||
return res
|
||||
|
||||
proc align_512(n: uint64): uint64 =
|
||||
if (n and 511) != 0:
|
||||
return (n + 512) and not 511'u64
|
||||
return n
|
||||
|
||||
proc cstring_to_nim(ptr_char: ptr char, max_len: int): string =
|
||||
var res = newStringOfCap(max_len)
|
||||
var p = ptr_char
|
||||
var i = 0
|
||||
while i < max_len and p[] != '\0':
|
||||
res.add(p[])
|
||||
p = cast[ptr char](cast[uint64](p) + 1)
|
||||
i += 1
|
||||
return res
|
||||
|
||||
# --- API ---
|
||||
proc toHexChar(b: byte): char =
|
||||
if b < 10: return char(byte('0') + b)
|
||||
else: return char(byte('A') + (b - 10))
|
||||
|
||||
proc vfs_init*(s: pointer, e: pointer) =
|
||||
vfs.start_addr = cast[uint64](s)
|
||||
vfs.end_addr = cast[uint64](e)
|
||||
vfs.index = initTable[string, FileEntry]()
|
||||
vfs.fds = initTable[int, FileHandle]()
|
||||
vfs.next_fd = 3 # 0,1,2 reserved
|
||||
vfs.next_fd = 3
|
||||
|
||||
kprint("[VFS] Mounting TarFS InitRD... Start=")
|
||||
kprint_hex(vfs.start_addr)
|
||||
kprint(" End=")
|
||||
kprint_hex(vfs.end_addr)
|
||||
kprint(" Size=")
|
||||
kprint_hex(vfs.end_addr - vfs.start_addr)
|
||||
kprintln("")
|
||||
var p = vfs.start_addr
|
||||
while p < vfs.end_addr:
|
||||
let h = cast[ptr TarHeader](p)
|
||||
if h[][0] == byte(0): break
|
||||
|
||||
var ptr_curr = vfs.start_addr
|
||||
var name = ""
|
||||
for i in 0..99:
|
||||
if h[][i] == byte(0): break
|
||||
name.add(char(h[][i]))
|
||||
|
||||
while ptr_curr < vfs.end_addr:
|
||||
let header = cast[ptr TarHeader](ptr_curr)
|
||||
var size: uint64 = 0
|
||||
for i in 124..134:
|
||||
let b = h[][i]
|
||||
if b >= byte('0') and b <= byte('7'):
|
||||
size = (size shl 3) or uint64(b - byte('0'))
|
||||
|
||||
# Check bounds safety before reading header
|
||||
if ptr_curr + 512 > vfs.end_addr: break
|
||||
# Manual Normalization
|
||||
var clean = name
|
||||
if clean.len > 2 and clean[0] == '.' and clean[1] == '/':
|
||||
# Strip ./
|
||||
var new_clean = ""
|
||||
for i in 2 ..< clean.len: new_clean.add(clean[i])
|
||||
clean = new_clean
|
||||
elif clean.len > 1 and clean[0] == '/':
|
||||
# Strip /
|
||||
var new_clean = ""
|
||||
for i in 1 ..< clean.len: new_clean.add(clean[i])
|
||||
clean = new_clean
|
||||
|
||||
# Check End of Archive (Empty Block)
|
||||
if header.name[0] == '\0': break
|
||||
if clean.len > 0:
|
||||
vfs.index[clean] = FileEntry(offset: p + 512'u64, size: size, is_sfs: false)
|
||||
kprint("[VFS] Indexed: '")
|
||||
kprint(cstring(clean))
|
||||
kprint("' Size: ")
|
||||
var ss = ""; ss.add($size); kprintln(cstring(ss))
|
||||
else:
|
||||
kprint("[VFS] Empty Name? Raw: ")
|
||||
var r = ""
|
||||
for i in 0..min(10, name.len-1):
|
||||
r.add(toHexChar(byte(name[i]) shr 4))
|
||||
r.add(toHexChar(byte(name[i]) and 0xF))
|
||||
r.add(' ')
|
||||
kprintln(cstring(r))
|
||||
|
||||
let fname = cstring_to_nim(addr header.name[0], 100)
|
||||
let size = parse_octal(header.size)
|
||||
discard parse_octal(header.mode)
|
||||
|
||||
|
||||
var clean_name = fname
|
||||
if clean_name.len >= 2 and clean_name[0] == '.' and clean_name[1] == '/':
|
||||
clean_name = clean_name[2..^1]
|
||||
|
||||
# Index Files (Type '0' or '\0')
|
||||
if header.typeflag == '0' or header.typeflag == '\0':
|
||||
if clean_name.len > 0:
|
||||
let data_offset = ptr_curr + 512
|
||||
vfs.index[clean_name] = FileEntry(offset: data_offset, size: size)
|
||||
|
||||
# Jump to next header
|
||||
ptr_curr += 512 + align_512(size)
|
||||
p += 512'u64 + ((size + 511'u64) and not 511'u64)
|
||||
|
||||
proc vfs_open*(path: string): int =
|
||||
if vfs.index.hasKey(path):
|
||||
var clean = path
|
||||
if clean.len > 0 and clean[0] == '/':
|
||||
var nc = ""; for i in 1..<clean.len: nc.add(clean[i]); clean = nc
|
||||
|
||||
if vfs.index.hasKey(clean):
|
||||
let entry = vfs.index[clean]
|
||||
let fd = vfs.next_fd
|
||||
vfs.fds[fd] = FileHandle(path: path, offset: 0)
|
||||
vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: entry.is_sfs)
|
||||
vfs.next_fd += 1
|
||||
return fd
|
||||
return -1
|
||||
|
||||
proc vfs_get_entry*(path: string): (pointer, uint64) =
|
||||
if vfs.index.hasKey(path):
|
||||
let entry = vfs.index[path]
|
||||
return (cast[pointer](entry.offset), entry.size)
|
||||
return (nil, 0)
|
||||
proc vfs_read_file*(path: string): string =
|
||||
var clean = path
|
||||
if clean.len > 0 and clean[0] == '/':
|
||||
var nc = ""; for i in 1..<clean.len: nc.add(clean[i]); clean = nc
|
||||
|
||||
# --- C EXPORTS (THE BRIDGE) ---
|
||||
kprint("[VFS] Reading: '"); kprint(cstring(clean)); kprint("' -> ")
|
||||
|
||||
if vfs.index.hasKey(clean):
|
||||
let entry = vfs.index[clean]
|
||||
kprintln("FOUND.")
|
||||
if entry.is_sfs: return ""
|
||||
var s = newString(int(entry.size))
|
||||
if entry.size > 0:
|
||||
copyMem(addr s[0], cast[pointer](entry.offset), int(entry.size))
|
||||
return s
|
||||
|
||||
kprintln("NOT FOUND.")
|
||||
# Debug Keys
|
||||
kprint("Available: ")
|
||||
for k in vfs.index.keys:
|
||||
kprint("'"); kprint(cstring(k)); kprint("' ")
|
||||
kprintln("")
|
||||
return ""
|
||||
|
||||
proc ion_vfs_open*(path: cstring): int32 {.exportc, cdecl.} =
|
||||
return int32(vfs_open($path))
|
||||
|
||||
proc sfs_read_file(name: cstring, dest: pointer, max_len: int): int {.importc, cdecl.}
|
||||
|
||||
proc ion_vfs_read*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
|
||||
let fd_int = int(fd)
|
||||
if not vfs.fds.hasKey(fd_int): return -1
|
||||
|
||||
var fh = vfs.fds[fd_int] # Get a mutable copy of the FileHandle
|
||||
let (base_ptr, total_size) = vfs_get_entry(fh.path)
|
||||
|
||||
if base_ptr == nil: return 0
|
||||
if fh.offset >= total_size: return 0 # EOF
|
||||
|
||||
# Calculate remaining bytes
|
||||
let remaining = total_size - fh.offset
|
||||
let to_read = min(uint64(remaining), count)
|
||||
|
||||
if to_read > 0:
|
||||
let data_ptr = cast[pointer](cast[uint64](base_ptr) + fh.offset)
|
||||
copyMem(buf, data_ptr, to_read)
|
||||
|
||||
# Update cursor
|
||||
fh.offset += to_read
|
||||
vfs.fds[fd_int] = fh # Write back to table
|
||||
|
||||
return int64(to_read)
|
||||
|
||||
var fh = vfs.fds[fd_int]
|
||||
if fh.is_sfs:
|
||||
let n = sfs_read_file(cstring(fh.path), buf, int(count))
|
||||
if n > 0: fh.offset += uint64(n); vfs.fds[fd_int] = fh; return int64(n)
|
||||
return 0
|
||||
if vfs.index.hasKey(fh.path):
|
||||
let entry = vfs.index[fh.path]
|
||||
if fh.offset >= entry.size: return 0
|
||||
let to_read = min(uint64(entry.size - fh.offset), count)
|
||||
if to_read > 0:
|
||||
copyMem(buf, cast[pointer](entry.offset + fh.offset), int(to_read))
|
||||
fh.offset += to_read
|
||||
vfs.fds[fd_int] = fh
|
||||
return int64(to_read)
|
||||
return 0
|
||||
|
||||
proc vfs_list_files*(): string =
|
||||
var res = ""
|
||||
for name, entry in vfs.index:
|
||||
res.add(name)
|
||||
res.add("\n")
|
||||
return res
|
||||
|
||||
proc ion_vfs_list*(buf: pointer, max_len: uint64): int64 {.exportc, cdecl.} =
|
||||
let list = vfs_list_files()
|
||||
let len = min(list.len, int(max_len))
|
||||
if len > 0:
|
||||
copyMem(buf, unsafeAddr list[0], len)
|
||||
return int64(len)
|
||||
|
||||
proc vfs_read_file*(path: string): string =
|
||||
if vfs.index.hasKey(path):
|
||||
let entry = vfs.index[path]
|
||||
let ptr_data = cast[ptr UncheckedArray[char]](entry.offset)
|
||||
var s = newString(entry.size)
|
||||
if entry.size > 0:
|
||||
copyMem(addr s[0], ptr_data, entry.size)
|
||||
return s
|
||||
|
||||
return ""
|
||||
var s = ""
|
||||
for name, _ in vfs.index: s.add(name & "\n")
|
||||
let n = min(s.len, int(max_len))
|
||||
if n > 0: copyMem(buf, addr s[0], n)
|
||||
return int64(n)
|
||||
|
||||
proc vfs_register_sfs*(name: string, size: uint64) {.exportc, cdecl.} =
|
||||
vfs.index[name] = FileEntry(offset: 0, size: size, is_sfs: true)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,6 @@ import strutils
|
|||
import std
|
||||
import editor
|
||||
|
||||
# Constants
|
||||
const
|
||||
CMD_SYS_EXIT = 1
|
||||
CMD_GPU_MATRIX = 0x100
|
||||
CMD_GPU_STATUS = 0x102
|
||||
CMD_GET_GPU_STATUS = 0x102
|
||||
CMD_SYS_EXEC = 0x400
|
||||
|
||||
# --- SOVEREIGN NETWORKING TYPES ---
|
||||
type
|
||||
EthAddr = array[6, byte]
|
||||
|
|
@ -22,15 +14,15 @@ type
|
|||
ethertype: uint16
|
||||
|
||||
ArpPacket {.packed.} = object
|
||||
htype: uint16 # Hardware type (Ethernet = 1)
|
||||
ptype: uint16 # Protocol type (IPv4 = 0x0800)
|
||||
hlen: uint8 # Hardware addr len (6)
|
||||
plen: uint8 # Protocol addr len (4)
|
||||
oper: uint16 # Operation (Request=1, Reply=2)
|
||||
sha: EthAddr # Sender HW addr
|
||||
spa: uint32 # Sender IP addr
|
||||
tha: EthAddr # Target HW addr
|
||||
tpa: uint32 # Target IP addr
|
||||
htype: uint16
|
||||
ptype: uint16
|
||||
hlen: uint8
|
||||
plen: uint8
|
||||
oper: uint16
|
||||
sha: EthAddr
|
||||
spa: uint32
|
||||
tha: EthAddr
|
||||
tpa: uint32
|
||||
|
||||
IcmpPacket {.packed.} = object
|
||||
const_type: uint8
|
||||
|
|
@ -38,77 +30,49 @@ type
|
|||
checksum: uint16
|
||||
id: uint16
|
||||
seq: uint16
|
||||
# payload follows
|
||||
|
||||
const
|
||||
ETHERTYPE_ARP = 0x0608 # Big Endian 0x0806
|
||||
ETHERTYPE_IP = 0x0008 # Big Endian 0x0800
|
||||
ARP_OP_REQUEST = 0x0100 # Big Endian 1
|
||||
ARP_OP_REPLY = 0x0200 # Big Endian 2
|
||||
ETHERTYPE_ARP = 0x0608
|
||||
ETHERTYPE_IP = 0x0008
|
||||
ARP_OP_REQUEST = 0x0100
|
||||
ARP_OP_REPLY = 0x0200
|
||||
IP_PROTO_ICMP = 1
|
||||
|
||||
# My IP: 10.0.2.15
|
||||
const MY_IP: uint32 = 0x0F02000A
|
||||
const MY_MAC: EthAddr = [0x52.byte, 0x54.byte, 0x00.byte, 0x12.byte, 0x34.byte, 0x56.byte]
|
||||
|
||||
# --- 2. HELPERS ---
|
||||
|
||||
# Helper: Print to Stdout (FD 1)
|
||||
proc print(s: string) =
|
||||
if s.len > 0:
|
||||
discard write(1, unsafeAddr s[0], csize_t(s.len))
|
||||
discard write(cint(1), unsafeAddr s[0], csize_t(s.len))
|
||||
var nl = "\n"
|
||||
discard write(1, unsafeAddr nl[0], 1)
|
||||
discard write(cint(1), unsafeAddr nl[0], 1)
|
||||
|
||||
proc print_raw(s: string) =
|
||||
if s.len > 0:
|
||||
discard write(1, unsafeAddr s[0], csize_t(s.len))
|
||||
discard write(cint(1), unsafeAddr s[0], csize_t(s.len))
|
||||
|
||||
# Forward declarations for functions used before their definition
|
||||
proc parseIntSimple(s: string): uint64
|
||||
proc toHexChar(b: byte): char
|
||||
proc do_mkfs()
|
||||
# --- 3. LOGIC MODULES ---
|
||||
|
||||
var net_buf: array[1536, byte]
|
||||
|
||||
# Calculate Checksum (Standard Internet Checksum)
|
||||
proc calc_checksum(buf: cptr, len: int): uint16 =
|
||||
var sum: uint32 = 0
|
||||
let ptr16 = cast[ptr UncheckedArray[uint16]](buf)
|
||||
for i in 0 ..< (len div 2):
|
||||
sum += uint32(ptr16[i])
|
||||
|
||||
if (len mod 2) != 0:
|
||||
let ptr8 = cast[ptr UncheckedArray[byte]](buf)
|
||||
sum += uint32(ptr8[len-1])
|
||||
|
||||
while (sum shr 16) > 0:
|
||||
sum = (sum and 0xFFFF) + (sum shr 16)
|
||||
|
||||
return uint16(not sum)
|
||||
|
||||
# Utility: Parse Int simple
|
||||
proc parseIntSimple(s: string): uint64 =
|
||||
var res: uint64 = 0
|
||||
for c in s:
|
||||
if c >= '0' and c <= '9':
|
||||
res = res * 10 + uint64(ord(c) - ord('0'))
|
||||
return res
|
||||
|
||||
proc toHexChar(b: byte): char =
|
||||
if b < 10: return char(ord('0') + b)
|
||||
else: return char(ord('A') + (b - 10))
|
||||
|
||||
# --- 3. LOGIC MODULES ---
|
||||
|
||||
# Network Buffer (Shared for RX/TX)
|
||||
var net_buf: array[1536, byte]
|
||||
|
||||
proc handle_arp(rx_len: int) =
|
||||
let eth = cast[ptr EthHeader](addr net_buf[0])
|
||||
let arp = cast[ptr ArpPacket](addr net_buf[14]) # Valid only if ethertype is ARP
|
||||
|
||||
let arp = cast[ptr ArpPacket](addr net_buf[14])
|
||||
if arp.tpa == MY_IP and arp.oper == ARP_OP_REQUEST:
|
||||
print("[Net] ARP Request for me! Replying...")
|
||||
# Construct Reply
|
||||
arp.tha = arp.sha
|
||||
arp.tpa = arp.spa
|
||||
arp.sha = MY_MAC
|
||||
|
|
@ -124,10 +88,9 @@ proc handle_ipv4(rx_len: int) =
|
|||
let dst_ip_ptr = cast[ptr uint32](addr net_buf[30])
|
||||
if dst_ip_ptr[] == MY_IP:
|
||||
let icmp = cast[ptr IcmpPacket](addr net_buf[34])
|
||||
if icmp.const_type == 8: # Echo Request
|
||||
print("[Net] ICMP Ping from Gateway. PONG!")
|
||||
icmp.const_type = 0 # Echo Reply
|
||||
icmp.checksum = 0 # Recalc
|
||||
if icmp.const_type == 8:
|
||||
icmp.const_type = 0
|
||||
icmp.checksum = 0
|
||||
let icmp_len = rx_len - 34
|
||||
icmp.checksum = calc_checksum(addr net_buf[34], icmp_len)
|
||||
let src_ip_ptr = cast[ptr uint32](addr net_buf[26])
|
||||
|
|
@ -147,31 +110,30 @@ proc poll_network() =
|
|||
elif eth.ethertype == ETHERTYPE_IP:
|
||||
handle_ipv4(int(len))
|
||||
|
||||
# --- CMDS ---
|
||||
|
||||
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_mkfs() =
|
||||
print("[mkfs] Partitioning Ledger...")
|
||||
var sb: array[512, byte]
|
||||
sb[0] = 0x53; sb[1] = 0x46; sb[2] = 0x53; sb[3] = 0x31
|
||||
sb[4] = 0x00; sb[5] = 0x00; sb[6] = 0x00; sb[7] = 0x02
|
||||
sb[12] = 0x01
|
||||
nexus_blk_write(0, addr sb[0], 512)
|
||||
var zero: array[512, byte]
|
||||
for i in 0 ..< 512: zero[i] = 0
|
||||
nexus_blk_write(1, addr zero[0], 512)
|
||||
print("[mkfs] Complete.")
|
||||
|
||||
proc do_cat(filename: string) =
|
||||
let fd = open(cstring(filename), 0)
|
||||
if fd < 0:
|
||||
print("cat: cannot open file")
|
||||
print("cat: error opening " & filename)
|
||||
return
|
||||
const BUF_SIZE = 1024
|
||||
var buffer: array[BUF_SIZE, char]
|
||||
var buf: array[1024, char]
|
||||
while true:
|
||||
let bytesRead = read(fd, addr buffer[0], BUF_SIZE)
|
||||
if bytesRead <= 0: break
|
||||
discard write(1, addr buffer[0], bytesRead)
|
||||
let n = read(fd, addr buf[0], 1024)
|
||||
if n <= 0: break
|
||||
discard write(cint(1), addr buf[0], csize_t(n))
|
||||
discard close(fd)
|
||||
print("")
|
||||
|
||||
|
|
@ -183,192 +145,102 @@ proc do_ls() =
|
|||
copyMem(addr s[0], addr buf[0], n)
|
||||
print(s)
|
||||
|
||||
proc do_exec(filename: string) =
|
||||
if filename.len == 0:
|
||||
print("Usage: exec <path>")
|
||||
proc start_editor(filename: string) =
|
||||
editor.start_editor(filename)
|
||||
|
||||
# --- ENGINE ---
|
||||
|
||||
proc dispatch_command(input: string)
|
||||
|
||||
proc run_script(filename: string) =
|
||||
if filename.len == 0: return
|
||||
print("[Init] Sourcing " & filename & "...")
|
||||
let fd = open(cstring(filename), 0)
|
||||
if fd < 0:
|
||||
print("[Init] Script not found: " & filename)
|
||||
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_dd(arg: string) =
|
||||
var subcmd = newStringOfCap(32)
|
||||
var rest = newStringOfCap(128)
|
||||
var i = 0
|
||||
var space = false
|
||||
while i < arg.len:
|
||||
if not space and arg[i] == ' ':
|
||||
space = true
|
||||
elif not space:
|
||||
subcmd.add(arg[i])
|
||||
else:
|
||||
rest.add(arg[i])
|
||||
i += 1
|
||||
|
||||
if subcmd == "read":
|
||||
let sector = parseIntSimple(rest)
|
||||
print("[dd] Reading Sector " & $sector)
|
||||
var buf: array[512, byte]
|
||||
nexus_blk_read(sector, addr buf[0], 512)
|
||||
var hex = ""
|
||||
for j in 0 ..< 16:
|
||||
let b = buf[j]
|
||||
hex.add(toHexChar((b shr 4) and 0xF))
|
||||
hex.add(toHexChar(b and 0xF))
|
||||
hex.add(' ')
|
||||
print("HEX: " & hex & "...")
|
||||
elif subcmd == "write":
|
||||
var sectorStr = newStringOfCap(32)
|
||||
var payload = newStringOfCap(128)
|
||||
var j = 0
|
||||
var space2 = false
|
||||
while j < rest.len:
|
||||
if not space2 and rest[j] == ' ':
|
||||
space2 = true
|
||||
elif not space2:
|
||||
sectorStr.add(rest[j])
|
||||
else:
|
||||
payload.add(rest[j])
|
||||
j += 1
|
||||
let sector = parseIntSimple(sectorStr)
|
||||
print("[dd] Writing Sector " & $sector & ": " & payload)
|
||||
var buf: array[512, byte]
|
||||
for k in 0 ..< 512: buf[k] = 0
|
||||
for k in 0 ..< payload.len:
|
||||
if k < 512: buf[k] = byte(payload[k])
|
||||
nexus_blk_write(sector, addr buf[0], 512)
|
||||
else:
|
||||
print("Usage: dd read <sec> | dd write <sec> <data>")
|
||||
|
||||
proc do_help() =
|
||||
print("NipBox v0.2 (Sovereign)")
|
||||
print("Commands: echo, cat, ls, matrix, exec, dd, help, exit")
|
||||
|
||||
# --- 4. MAIN LOOP ---
|
||||
|
||||
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)
|
||||
var line = ""
|
||||
var buf: array[1, char]
|
||||
while true:
|
||||
if read_pos >= read_len:
|
||||
read_pos = 0
|
||||
poll_network() # Keep network alive while waiting
|
||||
read_len = int(read(0, addr read_buffer[0], 128))
|
||||
if read_len <= 0: return false # Or yield/retry?
|
||||
let c = read_buffer[read_pos]
|
||||
read_pos += 1
|
||||
if c == '\n': return true
|
||||
elif c != '\r': buf.add(c)
|
||||
let n = read(fd, addr buf[0], 1)
|
||||
if n <= 0: break
|
||||
if buf[0] == '\n':
|
||||
let t = line.strip()
|
||||
if t.len > 0 and not t.startsWith("#"):
|
||||
print_raw("+ " & t & "\n")
|
||||
dispatch_command(t)
|
||||
line = ""
|
||||
elif buf[0] != '\r':
|
||||
line.add(buf[0])
|
||||
|
||||
let t = line.strip()
|
||||
if t.len > 0 and not t.startsWith("#"):
|
||||
print_raw("+ " & t & "\n")
|
||||
dispatch_command(t)
|
||||
|
||||
discard close(fd)
|
||||
print("[Init] Done.")
|
||||
|
||||
proc dispatch_command(input: string) =
|
||||
let trimmed = input.strip()
|
||||
if trimmed.len == 0: return
|
||||
|
||||
var cmd = ""
|
||||
var arg = ""
|
||||
var space = false
|
||||
for c in trimmed:
|
||||
if not space and c == ' ': space = true
|
||||
elif not space: cmd.add(c)
|
||||
else: arg.add(c)
|
||||
|
||||
if cmd == "exit": exit(0)
|
||||
elif cmd == "echo": print(arg)
|
||||
elif cmd == "cat": do_cat(arg)
|
||||
elif cmd == "ls": do_ls()
|
||||
elif cmd == "mkfs": do_mkfs()
|
||||
elif cmd == "mount": discard nexus_syscall(0x204, 0)
|
||||
elif cmd == "matrix":
|
||||
if arg == "on": discard nexus_syscall(0x100, 1)
|
||||
else: discard nexus_syscall(0x100, 0)
|
||||
elif cmd == "ed": start_editor(arg)
|
||||
elif cmd == "source": run_script(arg)
|
||||
elif cmd == "help":
|
||||
print("NipBox v0.4 (Sovereign Supervisor)")
|
||||
print("echo, cat, ls, mkfs, mount, matrix, ed, source, exit")
|
||||
else:
|
||||
print("Unknown command: " & cmd)
|
||||
|
||||
proc main() =
|
||||
var inputBuffer = newStringOfCap(256)
|
||||
print("\n[NipBox] Interactive Shell Ready.")
|
||||
print("\n╔═══════════════════════════════════════╗")
|
||||
print("║ SOVEREIGN SUPERVISOR v0.4 ACTIVE ║")
|
||||
print("╚═══════════════════════════════════════╝")
|
||||
|
||||
# Auto-Mount
|
||||
discard nexus_syscall(0x204, 0)
|
||||
|
||||
# Init
|
||||
run_script("/etc/init.nsh")
|
||||
|
||||
print_raw("\nroot@nexus:# ")
|
||||
var inputBuffer = ""
|
||||
while true:
|
||||
print_raw("root@nexus:# ")
|
||||
poll_network()
|
||||
var c: char
|
||||
if nexus_read_nonblock(0, addr c, 1) > 0:
|
||||
if c == '\n' or c == '\r':
|
||||
print_raw("\n")
|
||||
dispatch_command(inputBuffer)
|
||||
inputBuffer = ""
|
||||
print_raw("root@nexus:# ")
|
||||
elif c == '\b' or c == char(127):
|
||||
if inputBuffer.len > 0:
|
||||
print_raw("\b \b")
|
||||
inputBuffer.setLen(inputBuffer.len - 1)
|
||||
else:
|
||||
inputBuffer.add(c)
|
||||
var s = ""
|
||||
s.add(c)
|
||||
print_raw(s)
|
||||
nexus_yield()
|
||||
|
||||
if not my_readline(inputBuffer):
|
||||
break
|
||||
|
||||
if inputBuffer.len == 0: continue
|
||||
|
||||
# Parse Cmd/Arg
|
||||
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)
|
||||
|
||||
# DEBUG PARSING
|
||||
print_raw("CMD_DEBUG: '")
|
||||
print_raw(cmd)
|
||||
print_raw("' LEN: ")
|
||||
# print($cmd.len) # Need int to string conversion if $ not working
|
||||
# Manual int string
|
||||
var ls = ""
|
||||
var l = cmd.len
|
||||
if l == 0: ls = "0"
|
||||
while l > 0:
|
||||
ls.add(char(l mod 10 + 48))
|
||||
l = l div 10
|
||||
# Reverse
|
||||
var lsr = ""
|
||||
var z = ls.len - 1
|
||||
while z >= 0:
|
||||
lsr.add(ls[z])
|
||||
z -= 1
|
||||
print(lsr)
|
||||
|
||||
# HEX DUMP CMD
|
||||
var h = ""
|
||||
for k in 0 ..< cmd.len:
|
||||
let b = byte(cmd[k])
|
||||
h.add(toHexChar((b shr 4) and 0xF))
|
||||
h.add(toHexChar(b and 0xF))
|
||||
h.add(' ')
|
||||
print("CMD_HEX: " & h)
|
||||
|
||||
if cmd == "exit":
|
||||
print("Exiting...")
|
||||
exit(0)
|
||||
elif cmd == "echo": do_echo(arg)
|
||||
elif cmd == "matrix": do_matrix(arg)
|
||||
elif cmd == "cat": do_cat(arg)
|
||||
elif cmd == "ls": do_ls()
|
||||
elif cmd == "exec": do_exec(arg)
|
||||
elif cmd == "dd": do_dd(arg)
|
||||
elif cmd == "mkfs": do_mkfs()
|
||||
elif cmd == "ed": start_editor(arg)
|
||||
elif cmd == "help": do_help()
|
||||
else: print("Unknown command: " & cmd)
|
||||
|
||||
proc do_mkfs() =
|
||||
print("[mkfs] Formatting disk as Sovereign Filesystem (SFS v1)...")
|
||||
|
||||
# 1. Superblock (Sector 0)
|
||||
var sb: array[512, byte]
|
||||
# Magic: S (0x53), F (0x46), S (0x53), 1 (0x31) -> Little Endian? String is byte order.
|
||||
sb[0] = 0x53
|
||||
sb[1] = 0x46
|
||||
sb[2] = 0x53
|
||||
sb[3] = 0x31
|
||||
# Disk Size (u64 at offset 4) - 32MB = 33554432 = 0x02000000
|
||||
# Little Endian
|
||||
sb[4] = 0x00
|
||||
sb[5] = 0x00
|
||||
sb[6] = 0x00
|
||||
sb[7] = 0x02
|
||||
sb[8] = 0x00
|
||||
sb[9] = 0x00
|
||||
sb[10] = 0x00
|
||||
sb[11] = 0x00
|
||||
|
||||
# Root Dir Sector (u64 at offset 12) -> 1
|
||||
sb[12] = 0x01
|
||||
|
||||
nexus_blk_write(0, addr sb[0], 512)
|
||||
print("[mkfs] Superblock written.")
|
||||
|
||||
# 2. Directory Table (Sector 1) - Zero it
|
||||
var zero: array[512, byte] # Implicitly zeroed? In Nim, yes if global/stack? Better be safe.
|
||||
for i in 0 ..< 512: zero[i] = 0
|
||||
nexus_blk_write(1, addr zero[0], 512)
|
||||
print("[mkfs] Directory Table initialized.")
|
||||
|
||||
print("[mkfs] Format Complete. The Ledger is structured.")
|
||||
|
||||
when isMainModule:
|
||||
main()
|
||||
when isMainModule: main()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# Nexus Sovereign Boot Script
|
||||
echo "--- Initializing Sovereign Services ---"
|
||||
|
||||
echo "Activating Persistent Storage..."
|
||||
mount
|
||||
|
||||
echo "Enabling Visual Matrix..."
|
||||
matrix on
|
||||
|
||||
echo "--- Boot Record Complete ---"
|
||||
Loading…
Reference in New Issue