feat(rumpk): Sovereign Ledger - VirtIO Block Driver & Persistence
- Implemented 'virtio-block' driver (hal/virtio_block.zig) for raw sector I/O. - Updated 'virtio_pci.zig' with dynamic I/O port allocation to resolve PCI conflicts. - Integrated Block I/O commands (0x600/0x601) into Kernel and ION. - Added 'dd' command to NipBox for testing read/write operations. - Fixed input buffering bug in NipBox to support longer commands. - Added documentation for Phase 10.
This commit is contained in:
parent
932a70ab7b
commit
c28faf5f1d
298
nipbox.nim
298
nipbox.nim
|
|
@ -19,13 +19,56 @@ proc list_files(buf: pointer, len: uint64): int64 {.importc, cdecl.}
|
||||||
# Our Custom Syscalls (Defined in libc_shim)
|
# Our Custom Syscalls (Defined in libc_shim)
|
||||||
proc nexus_syscall(cmd: cint, arg: uint64): cint {.importc, cdecl.}
|
proc nexus_syscall(cmd: cint, arg: uint64): cint {.importc, cdecl.}
|
||||||
proc nexus_yield() {.importc, cdecl.}
|
proc nexus_yield() {.importc, cdecl.}
|
||||||
|
proc nexus_net_tx(buf: cptr, len: uint64) {.importc, cdecl.}
|
||||||
|
proc nexus_net_rx(buf: cptr, max_len: uint64): uint64 {.importc, cdecl.}
|
||||||
|
proc nexus_blk_read(sector: uint64, buf: cptr, len: uint64) {.importc, cdecl.}
|
||||||
|
proc nexus_blk_write(sector: uint64, buf: cptr, len: uint64) {.importc, cdecl.}
|
||||||
|
|
||||||
const CMD_GPU_MATRIX = 0x100
|
const CMD_GPU_MATRIX = 0x100
|
||||||
const CMD_GPU_STATUS = 0x102
|
const CMD_GPU_STATUS = 0x102
|
||||||
const CMD_GET_GPU_STATUS = 0x102
|
const CMD_GET_GPU_STATUS = 0x102
|
||||||
const CMD_SYS_EXEC = 0x400
|
const CMD_SYS_EXEC = 0x400
|
||||||
|
|
||||||
# --- 2. MINIMAL RUNTIME (The Tools) ---
|
# --- SOVEREIGN NETWORKING TYPES ---
|
||||||
|
type
|
||||||
|
EthAddr = array[6, byte]
|
||||||
|
|
||||||
|
EthHeader {.packed.} = object
|
||||||
|
dest: EthAddr
|
||||||
|
src: EthAddr
|
||||||
|
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
|
||||||
|
|
||||||
|
IcmpPacket {.packed.} = object
|
||||||
|
const_type: uint8
|
||||||
|
code: uint8
|
||||||
|
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
|
||||||
|
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)
|
# Helper: Print to Stdout (FD 1)
|
||||||
proc print(s: string) =
|
proc print(s: string) =
|
||||||
|
|
@ -38,45 +81,88 @@ proc print_raw(s: string) =
|
||||||
if s.len > 0:
|
if s.len > 0:
|
||||||
discard write(1, unsafeAddr s[0], csize_t(s.len))
|
discard write(1, unsafeAddr s[0], csize_t(s.len))
|
||||||
|
|
||||||
# Helper: Read Line from Stdin (FD 0)
|
# Helper: Swap Bytes 16
|
||||||
# Returns true if line read, false if EOF
|
proc swap16(x: uint16): uint16 =
|
||||||
var read_buffer: array[256, char]
|
return (x shl 8) or (x shr 8)
|
||||||
var read_pos: int = 0
|
|
||||||
var read_len: int = 0
|
|
||||||
|
|
||||||
proc my_readline(buf: var string): bool =
|
# Calculate Checksum (Standard Internet Checksum)
|
||||||
buf.setLen(0)
|
proc calc_checksum(buf: cptr, len: int): uint16 =
|
||||||
while true:
|
var sum: uint32 = 0
|
||||||
# Buffer empty? Fill it.
|
let ptr16 = cast[ptr UncheckedArray[uint16]](buf)
|
||||||
if read_pos >= read_len:
|
for i in 0 ..< (len div 2):
|
||||||
let n = read(0, addr read_buffer[0], 256)
|
sum += uint32(ptr16[i])
|
||||||
if n <= 0:
|
|
||||||
nexus_yield()
|
|
||||||
continue
|
|
||||||
read_len = int(n)
|
|
||||||
read_pos = 0
|
|
||||||
|
|
||||||
# Process buffer
|
if (len mod 2) != 0:
|
||||||
while read_pos < read_len:
|
let ptr8 = cast[ptr UncheckedArray[byte]](buf)
|
||||||
let c = read_buffer[read_pos]
|
sum += uint32(ptr8[len-1])
|
||||||
read_pos += 1
|
|
||||||
|
|
||||||
# Handle Backspace
|
while (sum shr 16) > 0:
|
||||||
if c == char(127) or c == char(8):
|
sum = (sum and 0xFFFF) + (sum shr 16)
|
||||||
if buf.len > 0:
|
|
||||||
var seq = "\b \b"
|
|
||||||
discard write(1, unsafeAddr seq[0], 3)
|
|
||||||
buf.setLen(buf.len - 1)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Echo logic skipped (Host handles it mostly)
|
return uint16(not sum)
|
||||||
|
|
||||||
if c == '\n' or c == '\r':
|
# Utility: Parse Int simple
|
||||||
return true
|
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
|
||||||
|
|
||||||
buf.add(c)
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
arp.spa = MY_IP
|
||||||
|
arp.oper = ARP_OP_REPLY
|
||||||
|
eth.dest = eth.src
|
||||||
|
eth.src = MY_MAC
|
||||||
|
nexus_net_tx(addr net_buf[0], 42)
|
||||||
|
|
||||||
|
proc handle_ipv4(rx_len: int) =
|
||||||
|
let eth = cast[ptr EthHeader](addr net_buf[0])
|
||||||
|
if net_buf[23] == IP_PROTO_ICMP:
|
||||||
|
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
|
||||||
|
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])
|
||||||
|
let tmp = src_ip_ptr[]
|
||||||
|
src_ip_ptr[] = dst_ip_ptr[]
|
||||||
|
dst_ip_ptr[] = tmp
|
||||||
|
eth.dest = eth.src
|
||||||
|
eth.src = MY_MAC
|
||||||
|
nexus_net_tx(addr net_buf[0], uint64(rx_len))
|
||||||
|
|
||||||
|
proc poll_network() =
|
||||||
|
let len = nexus_net_rx(addr net_buf[0], 1536)
|
||||||
|
if len > 0:
|
||||||
|
let eth = cast[ptr EthHeader](addr net_buf[0])
|
||||||
|
if eth.ethertype == ETHERTYPE_ARP:
|
||||||
|
handle_arp(int(len))
|
||||||
|
elif eth.ethertype == ETHERTYPE_IP:
|
||||||
|
handle_ipv4(int(len))
|
||||||
|
|
||||||
# --- 3. COMMAND LOGIC ---
|
|
||||||
|
|
||||||
proc do_echo(arg: string) =
|
proc do_echo(arg: string) =
|
||||||
print(arg)
|
print(arg)
|
||||||
|
|
@ -92,26 +178,18 @@ proc do_matrix(arg: string) =
|
||||||
print("Usage: matrix on|off")
|
print("Usage: matrix on|off")
|
||||||
|
|
||||||
proc do_cat(filename: string) =
|
proc do_cat(filename: string) =
|
||||||
# 1. Open
|
let fd = open(cstring(filename), 0)
|
||||||
let fd = open(cstring(filename), 0) # O_RDONLY
|
|
||||||
if fd < 0:
|
if fd < 0:
|
||||||
print("cat: cannot open file")
|
print("cat: cannot open file")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 2. Read Loop
|
|
||||||
const BUF_SIZE = 1024
|
const BUF_SIZE = 1024
|
||||||
var buffer: array[BUF_SIZE, char]
|
var buffer: array[BUF_SIZE, char]
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
let bytesRead = read(fd, addr buffer[0], BUF_SIZE)
|
let bytesRead = read(fd, addr buffer[0], BUF_SIZE)
|
||||||
if bytesRead <= 0: break
|
if bytesRead <= 0: break
|
||||||
|
|
||||||
# Write to Stdout
|
|
||||||
discard write(1, addr buffer[0], bytesRead)
|
discard write(1, addr buffer[0], bytesRead)
|
||||||
|
|
||||||
# 3. Close
|
|
||||||
discard close(fd)
|
discard close(fd)
|
||||||
print("") # Final newline
|
print("")
|
||||||
|
|
||||||
proc do_ls() =
|
proc do_ls() =
|
||||||
var buf: array[2048, char]
|
var buf: array[2048, char]
|
||||||
|
|
@ -132,64 +210,144 @@ proc do_exec(filename: string) =
|
||||||
else:
|
else:
|
||||||
print("[NipBox] Syscall sent successfully")
|
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() =
|
proc do_help() =
|
||||||
print("NipBox v0.2 (Sovereign)")
|
print("NipBox v0.2 (Sovereign)")
|
||||||
print("Commands: echo, cat, ls, matrix, exec, help, exit")
|
print("Commands: echo, cat, ls, matrix, exec, dd, help, exit")
|
||||||
|
|
||||||
# --- 4. MAIN LOOP ---
|
# --- 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)
|
||||||
|
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)
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
var inputBuffer = newStringOfCap(256)
|
var inputBuffer = newStringOfCap(256)
|
||||||
|
|
||||||
print("\n[NipBox] Interactive Shell Ready.")
|
print("\n[NipBox] Interactive Shell Ready.")
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
print_raw("root@nexus:# ")
|
print_raw("root@nexus:# ")
|
||||||
|
|
||||||
if not my_readline(inputBuffer):
|
if not my_readline(inputBuffer):
|
||||||
break # EOF
|
break
|
||||||
|
|
||||||
if inputBuffer.len == 0: continue
|
if inputBuffer.len == 0: continue
|
||||||
|
|
||||||
# Simple manual parsing
|
# Parse Cmd/Arg
|
||||||
|
|
||||||
# Reset manual parsing
|
|
||||||
var cmd = newStringOfCap(32)
|
var cmd = newStringOfCap(32)
|
||||||
var arg = newStringOfCap(128)
|
var arg = newStringOfCap(128)
|
||||||
var spaceFound = false
|
var spaceFound = false
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < inputBuffer.len:
|
while i < inputBuffer.len:
|
||||||
let c = inputBuffer[i]
|
let c = inputBuffer[i]
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
if not spaceFound and c == ' ':
|
if not spaceFound and c == ' ':
|
||||||
spaceFound = true
|
spaceFound = true
|
||||||
continue
|
continue
|
||||||
if not spaceFound:
|
if not spaceFound: cmd.add(c)
|
||||||
cmd.add(c)
|
else: arg.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":
|
if cmd == "exit":
|
||||||
print("Exiting...")
|
print("Exiting...")
|
||||||
exit(0)
|
exit(0)
|
||||||
elif cmd == "echo":
|
elif cmd == "echo": do_echo(arg)
|
||||||
do_echo(arg)
|
elif cmd == "matrix": do_matrix(arg)
|
||||||
elif cmd == "cat":
|
elif cmd == "cat": do_cat(arg)
|
||||||
do_cat(arg)
|
elif cmd == "ls": do_ls()
|
||||||
elif cmd == "ls":
|
elif cmd == "exec": do_exec(arg)
|
||||||
do_ls()
|
elif cmd == "dd": do_dd(arg)
|
||||||
elif cmd == "matrix":
|
elif cmd == "help": do_help()
|
||||||
do_matrix(arg)
|
else: print("Unknown command: " & cmd)
|
||||||
elif cmd == "exec":
|
|
||||||
do_exec(arg)
|
|
||||||
elif cmd == "help":
|
|
||||||
do_help()
|
|
||||||
else:
|
|
||||||
print_raw("Unknown command: ")
|
|
||||||
print(cmd)
|
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue