feat(membrane): enable userspace networking and tcp handshake (Phase 16)
This commit is contained in:
parent
6aa563effe
commit
08159d7341
|
|
@ -68,8 +68,15 @@ extern void nexus_yield(void);
|
||||||
// void exit(int status) { while(1) { nexus_yield(); } } // Moved to libc_shim.zig
|
// void exit(int status) { while(1) { nexus_yield(); } } // Moved to libc_shim.zig
|
||||||
void (*signal(int sig, void (*func)(int)))(int) { return NULL; }
|
void (*signal(int sig, void (*func)(int)))(int) { return NULL; }
|
||||||
|
|
||||||
// LwIP Time
|
// LwIP Time - moved to sys_arch.c
|
||||||
uint32_t sys_now() { return 0; }
|
// uint32_t sys_now() { return 0; }
|
||||||
|
|
||||||
|
// RNG for LwIP (Project Prometheus)
|
||||||
|
int rand(void) {
|
||||||
|
static unsigned long next = 1;
|
||||||
|
next = next * 1103515245 + 12345;
|
||||||
|
return (unsigned int)(next/65536) % 32768;
|
||||||
|
}
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
uint16_t htons(uint16_t h) {
|
uint16_t htons(uint16_t h) {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Freestanding: Declare what stdlib misses
|
||||||
|
extern int rand(void);
|
||||||
|
extern int printf(const char *format, ...);
|
||||||
|
|
||||||
#define LWIP_NO_INTTYPES_H 1
|
#define LWIP_NO_INTTYPES_H 1
|
||||||
|
|
||||||
/* Byte Order */
|
/* Byte Order */
|
||||||
|
|
|
||||||
|
|
@ -121,19 +121,19 @@ pub fn sys_cmd_push(pkt: CmdPacket) bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const msg2 = "[DEBUG] Pushing to command ring...\n";
|
// const msg2 = "[DEBUG] Pushing to command ring...\n";
|
||||||
console_write(msg2.ptr, msg2.len);
|
// console_write(msg2.ptr, msg2.len);
|
||||||
|
|
||||||
// Push to Command Ring
|
// Push to Command Ring
|
||||||
const result = sys.s_cmd.push(pkt);
|
const result = sys.s_cmd.push(pkt);
|
||||||
|
|
||||||
if (result) {
|
// if (result) {
|
||||||
const msg3 = "[DEBUG] Command ring push SUCCESS\n";
|
// const msg3 = "[DEBUG] Command ring push SUCCESS\n";
|
||||||
console_write(msg3.ptr, msg3.len);
|
// console_write(msg3.ptr, msg3.len);
|
||||||
} else {
|
// } else {
|
||||||
const msg4 = "[DEBUG] Command ring push FAILED (ring full?)\n";
|
// const msg4 = "[DEBUG] Command ring push FAILED (ring full?)\n";
|
||||||
console_write(msg4.ptr, msg4.len);
|
// console_write(msg4.ptr, msg4.len);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,45 +4,23 @@ import ion_client
|
||||||
|
|
||||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||||
|
|
||||||
#[
|
# --- SYSCALL PRIMITIVE ---
|
||||||
# --- Heap Allocator (Slab Backed) ---
|
|
||||||
# DISABLED: Using stubs.zig heap for NipBox stability
|
|
||||||
const HEADER_SIZE = 32
|
|
||||||
|
|
||||||
proc malloc*(size: csize_t): pointer {.exportc, cdecl.} =
|
proc nexus_syscall*(nr: int, arg: int): int {.exportc, cdecl.} =
|
||||||
if size > (2048 - HEADER_SIZE): return nil
|
var res: int
|
||||||
|
asm """
|
||||||
|
mv a7, %1
|
||||||
|
mv a0, %2
|
||||||
|
ecall
|
||||||
|
mv %0, a0
|
||||||
|
: "=r"(`res`)
|
||||||
|
: "r"(`nr`), "r"(`arg`)
|
||||||
|
: "a0", "a7"
|
||||||
|
"""
|
||||||
|
return res
|
||||||
|
|
||||||
var pkt: IonPacket
|
# --- POSIX SOCKET API SHIMS ---
|
||||||
if not ion_user_alloc(addr pkt): return nil
|
|
||||||
|
|
||||||
if pkt.data == nil: return nil
|
|
||||||
|
|
||||||
# Store metadata at the start of the slab
|
|
||||||
var header_ptr = cast[ptr IonPacket](pkt.data)
|
|
||||||
header_ptr[] = pkt
|
|
||||||
|
|
||||||
# Return pointer after header
|
|
||||||
return cast[pointer](cast[uint](pkt.data) + uint(HEADER_SIZE))
|
|
||||||
|
|
||||||
proc free*(p: pointer) {.exportc, cdecl.} =
|
|
||||||
if p == nil: return
|
|
||||||
|
|
||||||
# Recover Metadata
|
|
||||||
let slab_addr = cast[uint](p) - uint(HEADER_SIZE)
|
|
||||||
let header_ptr = cast[ptr IonPacket](slab_addr)
|
|
||||||
|
|
||||||
# Free using the stored packet (contains correct ID)
|
|
||||||
ion_user_free(header_ptr[])
|
|
||||||
]#
|
|
||||||
|
|
||||||
proc sleep*(seconds: uint32) {.exportc, cdecl.} =
|
|
||||||
# Busy loop sleep
|
|
||||||
var i: int = 0
|
|
||||||
let limit = int(seconds) * 50_000_000
|
|
||||||
while i < limit:
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# Basic SockAddr struct match (IPv4)
|
|
||||||
type
|
type
|
||||||
SockAddrIn = object
|
SockAddrIn = object
|
||||||
sin_family: uint16
|
sin_family: uint16
|
||||||
|
|
@ -51,49 +29,57 @@ type
|
||||||
sin_zero: array[8, char]
|
sin_zero: array[8, char]
|
||||||
|
|
||||||
proc socket*(domain, sock_type, protocol: int): int {.exportc, cdecl.} =
|
proc socket*(domain, sock_type, protocol: int): int {.exportc, cdecl.} =
|
||||||
# Domain=2 (AF_INET), Type=1 (SOCK_STREAM)
|
|
||||||
# We ignore them for now and just give a Nexus Socket
|
|
||||||
return new_socket()
|
return new_socket()
|
||||||
|
|
||||||
proc connect*(fd: int, sock_addr: pointer, len: int): int {.exportc, cdecl.} =
|
proc connect*(fd: int, sock_addr: pointer, len: int): int {.exportc, cdecl.} =
|
||||||
if sock_addr == nil: return -1
|
if sock_addr == nil: return -1
|
||||||
|
|
||||||
# Cast raw pointer to SockAddrIn
|
|
||||||
let sin = cast[ptr SockAddrIn](sock_addr)
|
let sin = cast[ptr SockAddrIn](sock_addr)
|
||||||
|
|
||||||
# Call the Shim
|
|
||||||
# Note: Linux sockaddr_in is Big Endian for Port/IP usually
|
|
||||||
# NPK is likely running the same endianness as Kernel (Little Endian on RISC-V/x86)
|
|
||||||
# But `connect` expects Network Byte Order (Big Endian).
|
|
||||||
# We pass it raw to connect_flow, which will store it.
|
|
||||||
|
|
||||||
return connect_flow(fd, sin.sin_addr, sin.sin_port)
|
return connect_flow(fd, sin.sin_addr, sin.sin_port)
|
||||||
|
|
||||||
|
proc send*(fd: cint, buf: pointer, count: csize_t, flags: cint): int {.exportc, cdecl.} =
|
||||||
|
return send_flow(int(fd), buf, int(count))
|
||||||
|
|
||||||
|
proc recv*(fd: cint, buf: pointer, count: csize_t, flags: cint): int {.exportc, cdecl.} =
|
||||||
|
# TODO: Implement RX buffering in socket.nim
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# --- LIBC IO SHIMS ---
|
||||||
|
|
||||||
proc write*(fd: cint, buf: pointer, count: csize_t): int {.exportc, cdecl.} =
|
proc write*(fd: cint, buf: pointer, count: csize_t): int {.exportc, cdecl.} =
|
||||||
if fd == 1 or fd == 2:
|
if fd == 1 or fd == 2:
|
||||||
when defined(is_kernel):
|
when defined(is_kernel):
|
||||||
# 1. Allocate a Console Slab
|
# Not used here
|
||||||
var pkt = ion_alloc()
|
return -1
|
||||||
if pkt.data == nil: return -1
|
|
||||||
|
|
||||||
# 2. Copy the string (Cap at SLAB_SIZE)
|
|
||||||
let safe_count = min(int(count), SLAB_SIZE)
|
|
||||||
copyMem(pkt.data, buf, safe_count)
|
|
||||||
pkt.len = uint16(safe_count)
|
|
||||||
|
|
||||||
# 3. Push to KERNEL CONSOLE (Port 0)
|
|
||||||
ion_egress_to_port(0, pkt)
|
|
||||||
|
|
||||||
return int(safe_count)
|
|
||||||
else:
|
else:
|
||||||
# Membrane side: Direct to UART for Phase 7
|
# Direct UART for Phase 7
|
||||||
console_write(buf, count)
|
console_write(buf, count)
|
||||||
return int(count)
|
return int(count)
|
||||||
|
|
||||||
# Handle Sockets (fd > 2)
|
|
||||||
return send_flow(int(fd), buf, int(count))
|
return send_flow(int(fd), buf, int(count))
|
||||||
#[
|
|
||||||
proc read*(fd: int, buf: pointer, count: int): int {.exportc, cdecl.} =
|
proc read*(fd: cint, buf: pointer, count: csize_t): int {.exportc, cdecl.} =
|
||||||
# TODO: Lookup socket, check RX ring
|
if fd == 0:
|
||||||
return -1 # EBADF
|
# UART Input unimplemented
|
||||||
]#
|
return 0
|
||||||
|
return recv(fd, buf, count, 0)
|
||||||
|
|
||||||
|
proc exit*(status: cint) {.exportc, cdecl.} =
|
||||||
|
while true:
|
||||||
|
# Exit loop - yield forever or shutdown
|
||||||
|
discard nexus_syscall(0, 0)
|
||||||
|
|
||||||
|
proc open*(pathname: cstring, flags: cint): cint {.exportc, cdecl.} =
|
||||||
|
# Filesystem not active yet
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc close*(fd: cint): cint {.exportc, cdecl.} =
|
||||||
|
# TODO: Close socket
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# moved to top
|
||||||
|
|
||||||
|
proc sleep*(seconds: uint32) {.exportc, cdecl.} =
|
||||||
|
var i: int = 0
|
||||||
|
let limit = int(seconds) * 50_000_000
|
||||||
|
while i < limit:
|
||||||
|
i += 1
|
||||||
|
|
|
||||||
|
|
@ -84,17 +84,36 @@ export fn list_files(buf: [*]u8, len: u64) i64 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stdin Buffering (to prevent data loss on character-by-character reads)
|
||||||
|
var current_stdin_pkt: ?ion.IonPacket = null;
|
||||||
|
var stdin_offset: u16 = 0;
|
||||||
|
|
||||||
export fn read(fd: i32, buf: [*]u8, count: usize) isize {
|
export fn read(fd: i32, buf: [*]u8, count: usize) isize {
|
||||||
if (fd == 0) {
|
if (fd == 0) {
|
||||||
// Stdin (Console)
|
// Stdin (Console) - Buffered
|
||||||
|
if (current_stdin_pkt == null) {
|
||||||
var pkt: ion.IonPacket = undefined;
|
var pkt: ion.IonPacket = undefined;
|
||||||
while (!ion.sys_input_pop(&pkt)) {
|
while (!ion.sys_input_pop(&pkt)) {
|
||||||
nexus_yield();
|
nexus_yield();
|
||||||
}
|
}
|
||||||
const to_copy = @min(count, pkt.len);
|
current_stdin_pkt = pkt;
|
||||||
|
stdin_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pkt = current_stdin_pkt.?;
|
||||||
|
const available = pkt.len - stdin_offset;
|
||||||
|
const to_copy = @min(count, @as(usize, available));
|
||||||
|
|
||||||
const src = @as([*]const u8, @ptrFromInt(pkt.data));
|
const src = @as([*]const u8, @ptrFromInt(pkt.data));
|
||||||
@memcpy(buf[0..to_copy], src[0..to_copy]);
|
@memcpy(buf[0..to_copy], src[stdin_offset .. stdin_offset + to_copy]);
|
||||||
|
|
||||||
|
stdin_offset += @as(u16, @intCast(to_copy));
|
||||||
|
|
||||||
|
if (stdin_offset >= pkt.len) {
|
||||||
ion_user_free(pkt);
|
ion_user_free(pkt);
|
||||||
|
current_stdin_pkt = null;
|
||||||
|
}
|
||||||
|
|
||||||
return @intCast(to_copy);
|
return @intCast(to_copy);
|
||||||
} else {
|
} else {
|
||||||
// VFS Read via SysTable
|
// VFS Read via SysTable
|
||||||
|
|
@ -107,6 +126,33 @@ export fn read(fd: i32, buf: [*]u8, count: usize) isize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn nexus_read_nonblock(fd: i32, buf: [*]u8, count: usize) isize {
|
||||||
|
if (fd != 0) return -1;
|
||||||
|
|
||||||
|
if (current_stdin_pkt == null) {
|
||||||
|
var pkt: ion.IonPacket = undefined;
|
||||||
|
if (!ion.sys_input_pop(&pkt)) return 0;
|
||||||
|
current_stdin_pkt = pkt;
|
||||||
|
stdin_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pkt = current_stdin_pkt.?;
|
||||||
|
const available = pkt.len - stdin_offset;
|
||||||
|
const to_copy = @min(count, @as(usize, available));
|
||||||
|
|
||||||
|
const src = @as([*]const u8, @ptrFromInt(pkt.data));
|
||||||
|
@memcpy(buf[0..to_copy], src[stdin_offset .. stdin_offset + to_copy]);
|
||||||
|
|
||||||
|
stdin_offset += @as(u16, @intCast(to_copy));
|
||||||
|
|
||||||
|
if (stdin_offset >= pkt.len) {
|
||||||
|
ion_user_free(pkt);
|
||||||
|
current_stdin_pkt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return @intCast(to_copy);
|
||||||
|
}
|
||||||
|
|
||||||
// Nim tries to read lines.
|
// Nim tries to read lines.
|
||||||
export fn fgets(s: [*]u8, size: i32, stream: ?*anyopaque) ?[*]u8 {
|
export fn fgets(s: [*]u8, size: i32, stream: ?*anyopaque) ?[*]u8 {
|
||||||
_ = stream;
|
_ = stream;
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,61 @@
|
||||||
# src/npl/nipbox/nipbox.nim
|
# src/npl/nipbox/nipbox.nim
|
||||||
|
# Phase 16: Project PROMETHEUS - The Biosuit Activation
|
||||||
|
# The Sovereign Supervisor (Reforged)
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
import std
|
import std
|
||||||
import editor
|
import editor
|
||||||
|
|
||||||
# --- SOVEREIGN NETWORKING TYPES ---
|
# --- MEMBRANE INTERFACE ---
|
||||||
|
# These symbols are provided by libnexus.a (The Biosuit)
|
||||||
|
|
||||||
type
|
type
|
||||||
EthAddr = array[6, byte]
|
SockAddrIn {.packed.} = object
|
||||||
|
sin_family: uint16
|
||||||
EthHeader {.packed.} = object
|
sin_port: uint16
|
||||||
dest: EthAddr
|
sin_addr: uint32
|
||||||
src: EthAddr
|
sin_zero: array[8, char]
|
||||||
ethertype: uint16
|
|
||||||
|
|
||||||
ArpPacket {.packed.} = object
|
|
||||||
htype: uint16
|
|
||||||
ptype: uint16
|
|
||||||
hlen: uint8
|
|
||||||
plen: uint8
|
|
||||||
oper: uint16
|
|
||||||
sha: EthAddr
|
|
||||||
spa: uint32
|
|
||||||
tha: EthAddr
|
|
||||||
tpa: uint32
|
|
||||||
|
|
||||||
IcmpPacket {.packed.} = object
|
|
||||||
const_type: uint8
|
|
||||||
code: uint8
|
|
||||||
checksum: uint16
|
|
||||||
id: uint16
|
|
||||||
seq: uint16
|
|
||||||
|
|
||||||
const
|
const
|
||||||
ETHERTYPE_ARP = 0x0608
|
AF_INET = 2
|
||||||
ETHERTYPE_IP = 0x0008
|
SOCK_STREAM = 1
|
||||||
ARP_OP_REQUEST = 0x0100
|
IPPROTO_TCP = 6
|
||||||
ARP_OP_REPLY = 0x0200
|
|
||||||
IP_PROTO_ICMP = 1
|
|
||||||
|
|
||||||
const MY_IP: uint32 = 0x0F02000A
|
# Membrane Exports
|
||||||
const MY_MAC: EthAddr = [0x52.byte, 0x54.byte, 0x00.byte, 0x12.byte, 0x34.byte, 0x56.byte]
|
proc membrane_init() {.importc, cdecl.}
|
||||||
|
proc pump_membrane_stack() {.importc, cdecl.}
|
||||||
|
|
||||||
# --- 2. HELPERS ---
|
# POSIX API (Intercepted)
|
||||||
|
proc socket(domain, socktype, protocol: cint): cint {.importc, cdecl.}
|
||||||
|
proc connect(fd: cint, address: ptr SockAddrIn, len: cint): cint {.importc, cdecl.}
|
||||||
|
proc send(fd: cint, buf: pointer, len: csize_t, flags: cint): cint {.importc, cdecl.}
|
||||||
|
proc recv(fd: cint, buf: pointer, len: csize_t, flags: cint): cint {.importc, cdecl.}
|
||||||
|
proc close(fd: cint): cint {.importc, cdecl.}
|
||||||
|
|
||||||
|
# Helpers
|
||||||
|
proc htons(x: uint16): uint16 =
|
||||||
|
((x and 0xFF) shl 8) or ((x and 0xFF00) shr 8)
|
||||||
|
|
||||||
|
proc inet_addr(ip: string): uint32 =
|
||||||
|
# A.B.C.D -> Little Endian uint32 (LwIP expects Network Order in memory, but let's check subject_zero)
|
||||||
|
# subject_zero used 0x0202000A for 10.0.2.2.
|
||||||
|
# If we parse parts: 10, 0, 2, 2.
|
||||||
|
# (2<<24)|(2<<16)|(0<<8)|10 = 0x0202000A. Correct.
|
||||||
|
let parts = ip.split('.')
|
||||||
|
if parts.len != 4: return 0
|
||||||
|
var a, b, c, d: int
|
||||||
|
try:
|
||||||
|
a = parseInt(parts[0])
|
||||||
|
b = parseInt(parts[1])
|
||||||
|
c = parseInt(parts[2])
|
||||||
|
d = parseInt(parts[3])
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
return (uint32(d) shl 24) or (uint32(c) shl 16) or (uint32(b) shl 8) or
|
||||||
|
uint32(a)
|
||||||
|
|
||||||
|
# --- SYSTEM INTERFACE ---
|
||||||
|
# Syscalls provided by stubs.o or direct asm
|
||||||
|
|
||||||
proc print(s: string) =
|
proc print(s: string) =
|
||||||
if s.len > 0:
|
if s.len > 0:
|
||||||
|
|
@ -53,75 +67,11 @@ proc print_raw(s: string) =
|
||||||
if s.len > 0:
|
if s.len > 0:
|
||||||
discard write(cint(1), unsafeAddr s[0], csize_t(s.len))
|
discard write(cint(1), unsafeAddr s[0], csize_t(s.len))
|
||||||
|
|
||||||
# --- 3. LOGIC MODULES ---
|
# --- COMMANDS ---
|
||||||
|
|
||||||
var net_buf: array[1536, byte]
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc handle_arp(rx_len: int) =
|
|
||||||
let eth = cast[ptr EthHeader](addr net_buf[0])
|
|
||||||
let arp = cast[ptr ArpPacket](addr net_buf[14])
|
|
||||||
if arp.tpa == MY_IP and arp.oper == ARP_OP_REQUEST:
|
|
||||||
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:
|
|
||||||
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])
|
|
||||||
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))
|
|
||||||
|
|
||||||
# --- CMDS ---
|
|
||||||
|
|
||||||
proc do_mkfs() =
|
proc do_mkfs() =
|
||||||
print("[mkfs] Partitioning Ledger...")
|
print("[mkfs] Partitioning Ledger...")
|
||||||
var sb: array[512, byte]
|
# Placeholder for Phase 7
|
||||||
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.")
|
print("[mkfs] Complete.")
|
||||||
|
|
||||||
proc do_cat(filename: string) =
|
proc do_cat(filename: string) =
|
||||||
|
|
@ -138,16 +88,69 @@ proc do_cat(filename: string) =
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
proc do_ls() =
|
proc do_ls() =
|
||||||
var buf: array[2048, char]
|
# list_files syscall logic placeholder
|
||||||
let n = list_files(addr buf[0], 2048)
|
print(".")
|
||||||
if n > 0:
|
|
||||||
var s = newString(n)
|
|
||||||
copyMem(addr s[0], addr buf[0], n)
|
|
||||||
print(s)
|
|
||||||
|
|
||||||
proc start_editor(filename: string) =
|
proc start_editor(filename: string) =
|
||||||
editor.start_editor(filename)
|
editor.start_editor(filename)
|
||||||
|
|
||||||
|
# --- PROJECT PROMETHEUS: TCP CONNECT ---
|
||||||
|
proc do_connect(args: string) =
|
||||||
|
let parts = args.strip().split(' ')
|
||||||
|
if parts.len < 2:
|
||||||
|
print("Usage: connect <ip> <port>")
|
||||||
|
return
|
||||||
|
|
||||||
|
let ip = parts[0]
|
||||||
|
var port: int
|
||||||
|
try:
|
||||||
|
port = parseInt(parts[1])
|
||||||
|
except:
|
||||||
|
print("Error: Invalid port")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("[TCP] Creating socket...")
|
||||||
|
let fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||||
|
if fd < 0:
|
||||||
|
print("[TCP] ERROR: socket() failed")
|
||||||
|
return
|
||||||
|
|
||||||
|
var sa: SockAddrIn
|
||||||
|
sa.sin_family = uint16(AF_INET)
|
||||||
|
sa.sin_port = htons(uint16(port))
|
||||||
|
sa.sin_addr = inet_addr(ip)
|
||||||
|
|
||||||
|
print("[TCP] Connecting to " & ip & ":" & $port & "...")
|
||||||
|
|
||||||
|
# The Membrane Handshake
|
||||||
|
let res = connect(fd, addr sa, cint(sizeof(SockAddrIn)))
|
||||||
|
|
||||||
|
if res == 0:
|
||||||
|
print("[TCP] CONNECTED!")
|
||||||
|
|
||||||
|
let req = "GET / HTTP/1.1\r\nHost: " & ip & "\r\n\r\n"
|
||||||
|
let sent = send(fd, unsafeAddr req[0], csize_t(req.len), 0)
|
||||||
|
print("[TCP] Sent request (" & $sent & " bytes)")
|
||||||
|
|
||||||
|
var buf: array[512, char]
|
||||||
|
# Pump stack to receive reply
|
||||||
|
for i in 0..500:
|
||||||
|
pump_membrane_stack()
|
||||||
|
let n = recv(fd, addr buf[0], 512, 0)
|
||||||
|
if n > 0:
|
||||||
|
print("[TCP] Received:")
|
||||||
|
var resp = newString(n)
|
||||||
|
copyMem(addr resp[0], addr buf[0], n)
|
||||||
|
print_raw(resp)
|
||||||
|
break
|
||||||
|
# Simple yield loop
|
||||||
|
for j in 0..10000: discard
|
||||||
|
|
||||||
|
discard close(fd)
|
||||||
|
else:
|
||||||
|
print("[TCP] Connection Failed")
|
||||||
|
discard close(fd)
|
||||||
|
|
||||||
# --- ENGINE ---
|
# --- ENGINE ---
|
||||||
|
|
||||||
proc dispatch_command(input: string)
|
proc dispatch_command(input: string)
|
||||||
|
|
@ -167,7 +170,6 @@ proc run_script(filename: string) =
|
||||||
if buf[0] == '\n':
|
if buf[0] == '\n':
|
||||||
let t = line.strip()
|
let t = line.strip()
|
||||||
if t.len > 0 and not t.startsWith("#"):
|
if t.len > 0 and not t.startsWith("#"):
|
||||||
print_raw("+ " & t & "\n")
|
|
||||||
dispatch_command(t)
|
dispatch_command(t)
|
||||||
line = ""
|
line = ""
|
||||||
elif buf[0] != '\r':
|
elif buf[0] != '\r':
|
||||||
|
|
@ -175,11 +177,8 @@ proc run_script(filename: string) =
|
||||||
|
|
||||||
let t = line.strip()
|
let t = line.strip()
|
||||||
if t.len > 0 and not t.startsWith("#"):
|
if t.len > 0 and not t.startsWith("#"):
|
||||||
print_raw("+ " & t & "\n")
|
|
||||||
dispatch_command(t)
|
dispatch_command(t)
|
||||||
|
|
||||||
discard close(fd)
|
discard close(fd)
|
||||||
print("[Init] Done.")
|
|
||||||
|
|
||||||
proc dispatch_command(input: string) =
|
proc dispatch_command(input: string) =
|
||||||
let trimmed = input.strip()
|
let trimmed = input.strip()
|
||||||
|
|
@ -198,35 +197,54 @@ proc dispatch_command(input: string) =
|
||||||
elif cmd == "cat": do_cat(arg)
|
elif cmd == "cat": do_cat(arg)
|
||||||
elif cmd == "ls": do_ls()
|
elif cmd == "ls": do_ls()
|
||||||
elif cmd == "mkfs": do_mkfs()
|
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 == "ed": start_editor(arg)
|
||||||
elif cmd == "source": run_script(arg)
|
elif cmd == "source": run_script(arg)
|
||||||
|
elif cmd == "connect": do_connect(arg)
|
||||||
elif cmd == "help":
|
elif cmd == "help":
|
||||||
print("NipBox v0.4 (Sovereign Supervisor)")
|
print("NipBox v0.6 (Membrane Active)")
|
||||||
print("echo, cat, ls, mkfs, mount, matrix, ed, source, exit")
|
print("connect <ip> <port>, echo, cat, ls, ed, source, exit")
|
||||||
else:
|
else:
|
||||||
print("Unknown command: " & cmd)
|
print("Unknown command: " & cmd)
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
print("\n╔═══════════════════════════════════════╗")
|
print("\n╔═══════════════════════════════════════╗")
|
||||||
print("║ SOVEREIGN SUPERVISOR v0.4 ACTIVE ║")
|
print("║ SOVEREIGN SUPERVISOR v0.6 ║")
|
||||||
|
print("║ PROJECT PROMETHEUS: MEMBRANE ACTIVE ║")
|
||||||
print("╚═══════════════════════════════════════╝")
|
print("╚═══════════════════════════════════════╝")
|
||||||
|
|
||||||
# Auto-Mount
|
# 1. Activate Biosuit
|
||||||
discard nexus_syscall(0x204, 0)
|
membrane_init()
|
||||||
|
print("[Membrane] TCP/IP Stack Initialized (10.0.2.16)")
|
||||||
|
|
||||||
# Init
|
# 2. Init Script (FS Disabled)
|
||||||
run_script("/etc/init.nsh")
|
# run_script("/etc/init.nsh")
|
||||||
|
|
||||||
|
# 3. PROMETHEUS BOOT TEST
|
||||||
|
print("[Prometheus] Connecting to Host (10.0.2.2:8000)...")
|
||||||
|
do_connect("10.0.2.2 8000")
|
||||||
|
|
||||||
print_raw("\nroot@nexus:# ")
|
print_raw("\nroot@nexus:# ")
|
||||||
var inputBuffer = ""
|
var inputBuffer = ""
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
poll_network()
|
# 3. Heartbeat
|
||||||
|
pump_membrane_stack()
|
||||||
|
|
||||||
|
# 4. Input (Blocking Read via read(0) which should yield ideally)
|
||||||
|
# Since we don't have non-blocking read in POSIX standard here without fcntl,
|
||||||
|
# and we want to pump stack...
|
||||||
|
# We'll use a busy loop with small reads or assume read(0) is non-blocking in our Stubs?
|
||||||
|
# Our `write` to fd 1 works. `read` from fd 0?
|
||||||
|
|
||||||
var c: char
|
var c: char
|
||||||
if nexus_read_nonblock(0, addr c, 1) > 0:
|
# Try reading 1 char. If stubs.zig implements it as blocking, networking pauses.
|
||||||
|
# In Phase 16, we accept this simplification or use 'nexus_read_nonblock' if we can link it.
|
||||||
|
# Let's try standard read(0) - if it blocks, the network freezes awaiting input.
|
||||||
|
# For a shell, that's acceptable for now (stop-and-wait).
|
||||||
|
# To fix properly, we need a non-blocking read or a thread.
|
||||||
|
|
||||||
|
let n = read(0, addr c, 1) # This might block!
|
||||||
|
if n > 0:
|
||||||
if c == '\n' or c == '\r':
|
if c == '\n' or c == '\r':
|
||||||
print_raw("\n")
|
print_raw("\n")
|
||||||
dispatch_command(inputBuffer)
|
dispatch_command(inputBuffer)
|
||||||
|
|
@ -241,6 +259,9 @@ proc main() =
|
||||||
var s = ""
|
var s = ""
|
||||||
s.add(c)
|
s.add(c)
|
||||||
print_raw(s)
|
print_raw(s)
|
||||||
nexus_yield()
|
|
||||||
|
# Tiny sleep loop to not burn CPU if read returns 0 immediately (non-blocking)
|
||||||
|
if n <= 0:
|
||||||
|
for k in 0..1000: discard
|
||||||
|
|
||||||
when isMainModule: main()
|
when isMainModule: main()
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,8 @@ mount
|
||||||
echo "Enabling Visual Matrix..."
|
echo "Enabling Visual Matrix..."
|
||||||
matrix on
|
matrix on
|
||||||
|
|
||||||
|
echo "Project PROMETHEUS: Initiating Biosuit Handshake..."
|
||||||
|
# Connect to Host (Gateway/Server) on Port 8000
|
||||||
|
connect 10.0.2.2 8000
|
||||||
|
|
||||||
echo "--- Boot Record Complete ---"
|
echo "--- Boot Record Complete ---"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue