feat(rumpk): Phase 2 Complete - The Entropy Purge & Sovereign Alignment
- Rumpk Core: Complete exorcism of LwIP/NET ghosts. Transitioned to ION nomenclature. - ABI Sync: Synchronized Zig HAL and Nim Logic Ring Buffer layouts (u32 head/tail/mask). - Invariant Shield: Hardened HAL pipes with handle-based validation and power-of-2 sync. - Immune System: Verified Blink Recovery (Self-Healing) with updated ION Control Plane. - NexShell: Major refactor of Command Plane for Sovereign Ring access. - Architecture: Updated SPEC files and Doctrines (Silence, Hexagonal Sovereignty). - Purge: Removed legacy rumk and nip artifacts for a clean substrate. - Web: Updated landing page vision to match Rumpk v1.1 milestones.
This commit is contained in:
parent
061a2ff56b
commit
b3d9c2a49d
|
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "subject_rust"
|
||||
version = "0.1.0"
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "subject_rust"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# No dependencies yet. We are raw.
|
||||
|
||||
[profile.release]
|
||||
panic = "abort" # We will handle it
|
||||
lto = true
|
||||
opt-level = "z" # Optimize for size
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
path = "src/lib.rs"
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::string::String;
|
||||
use alloc::format;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 1. The Nervous System (FFI to Membrane)
|
||||
// ----------------------------------------------------------------------------
|
||||
extern "C" {
|
||||
fn socket(domain: i32, type_: i32, protocol: i32) -> i32;
|
||||
fn connect(fd: i32, addr: *const u8, len: i32) -> i32;
|
||||
fn write(fd: i32, buf: *const u8, count: usize) -> isize;
|
||||
fn sleep(seconds: u32);
|
||||
// We also need the allocator from libnexus (clib.c or libc.nim exports)
|
||||
fn malloc(size: usize) -> *mut u8;
|
||||
fn free(ptr: *mut u8);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 2. The Stomach (Global Allocator)
|
||||
// ----------------------------------------------------------------------------
|
||||
struct NexusAllocator;
|
||||
|
||||
unsafe impl core::alloc::GlobalAlloc for NexusAllocator {
|
||||
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
|
||||
malloc(layout.size())
|
||||
}
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: core::alloc::Layout) {
|
||||
free(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: NexusAllocator = NexusAllocator;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error(_layout: core::alloc::Layout) -> ! {
|
||||
panic!("OOM");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 3. The Voice (Panic Handler)
|
||||
// ----------------------------------------------------------------------------
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
let msg = "RUST PANIC!\n";
|
||||
unsafe { write(1, msg.as_ptr(), msg.len()); }
|
||||
loop {}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 4. The Astronaut (Main Logic)
|
||||
// ----------------------------------------------------------------------------
|
||||
// We need struct layouts for sockaddr if we want to be precise,
|
||||
// but for this test, we can use the raw bytes or simple C structs.
|
||||
#[repr(C)]
|
||||
struct SockAddrIn {
|
||||
sin_family: u16,
|
||||
sin_port: u16,
|
||||
sin_addr: u32, // 10.0.2.2 = 0x0202000A (Little Endian)
|
||||
zero: [u8; 8],
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn main() -> i32 {
|
||||
let msg = String::from("[Rust] Booting sequence...\n");
|
||||
unsafe { write(1, msg.as_ptr(), msg.len()); }
|
||||
|
||||
let fd = unsafe { socket(2, 1, 0) }; // AF_INET, SOCK_STREAM
|
||||
if fd < 0 {
|
||||
let err = "[Rust] Socket failed\n";
|
||||
unsafe { write(1, err.as_ptr(), err.len()); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 10.0.2.2 = 0x0202000A
|
||||
// 8080 = 0x1F90 (Big Endian)
|
||||
let port_be: u16 = 8080u16.to_be();
|
||||
|
||||
let addr_fixed = SockAddrIn {
|
||||
sin_family: 2,
|
||||
sin_port: port_be,
|
||||
sin_addr: 0x0202000A,
|
||||
zero: [0; 8],
|
||||
};
|
||||
|
||||
let hello = format!("[Rust] Hello from the Iron Lung! FD={}\n", fd);
|
||||
|
||||
unsafe {
|
||||
let res = connect(fd, &addr_fixed as *const _ as *const u8, 16);
|
||||
if res < 0 {
|
||||
let fail = "[Rust] Connection Failed\n";
|
||||
write(1, fail.as_ptr(), fail.len());
|
||||
} else {
|
||||
write(fd, hello.as_ptr(), hello.len());
|
||||
let success = "[Rust] Payload Sent.\n";
|
||||
write(1, success.as_ptr(), success.len());
|
||||
}
|
||||
}
|
||||
|
||||
loop { unsafe { sleep(1); } }
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"rustc_fingerprint":12492699077941185025,"outputs":{"11828851594938707206":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.a\n/usr\noff\n___\ndebug_assertions\npanic=\"abort\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"riscv64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_feature=\"a\"\ntarget_feature=\"c\"\ntarget_feature=\"m\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"none\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\n","stderr":"warning: dropping unsupported crate type `dylib` for target `riscv64gc-unknown-none-elf`\n\nwarning: dropping unsupported crate type `cdylib` for target `riscv64gc-unknown-none-elf`\n\nwarning: dropping unsupported crate type `proc-macro` for target `riscv64gc-unknown-none-elf`\n\nwarning: 3 warnings emitted\n\n"},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.92.0 (ded5c06cf 2025-12-08) (Arch Linux rust 1:1.92.0-1)\nbinary: rustc\ncommit-hash: ded5c06cf21d2b93bffd5d884aa6e96934ee4234\ncommit-date: 2025-12-08\nhost: x86_64-unknown-linux-gnu\nrelease: 1.92.0\nLLVM version: 21.1.6\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"1973728902973864382":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\noff\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"riscv64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"a\"\ntarget_feature=\"c\"\ntarget_feature=\"m\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
|
|
@ -0,0 +1 @@
|
|||
This file has an mtime of when this was started.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{"$message_type":"diagnostic","message":"can't find crate for `core`","code":{"code":"E0463","explanation":"A crate was declared but cannot be found.\n\nErroneous code example:\n\n```compile_fail,E0463\nextern crate foo; // error: can't find crate\n```\n\nYou need to link your code to the relevant crate in order to be able to use it\n(through Cargo or the `-L` option of rustc, for example).\n\n## Common causes\n\n- The crate is not present at all. If using Cargo, add it to `[dependencies]`\n in Cargo.toml.\n- The crate is present, but under a different name. If using Cargo, look for\n `package = ` under `[dependencies]` in Cargo.toml.\n\n## Common causes for missing `std` or `core`\n\n- You are cross-compiling for a target which doesn't have `std` prepackaged.\n Consider one of the following:\n + Adding a pre-compiled version of std with `rustup target add`\n + Building std from source with `cargo build -Z build-std`\n + Using `#![no_std]` at the crate root, so you won't need `std` in the first\n place.\n- You are developing the compiler itself and haven't built libstd from source.\n You can usually build it with `x.py build library/std`. More information\n about x.py is available in the [rustc-dev-guide].\n\n[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#building-the-compiler\n"},"level":"error","spans":[{"file_name":"src/lib.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":"can't find crate","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the `riscv64gc-unknown-linux-gnu` target may not be installed","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider downloading the target with `rustup target add riscv64gc-unknown-linux-gnu`","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":"\u001b[1m\u001b[91merror[E0463]\u001b[0m\u001b[1m: can't find crate for `core`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: the `riscv64gc-unknown-linux-gnu` target may not be installed\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mhelp\u001b[0m: consider downloading the target with `rustup target add riscv64gc-unknown-linux-gnu`\n\n"}
|
||||
{"$message_type":"diagnostic","message":"aborting due to 1 previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[1m\u001b[91merror\u001b[0m\u001b[1m: aborting due to 1 previous error\u001b[0m\n\n"}
|
||||
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0463`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"\u001b[1mFor more information about this error, try `rustc --explain E0463`.\u001b[0m\n"}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
|
|
@ -0,0 +1 @@
|
|||
This file has an mtime of when this was started.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{"$message_type":"diagnostic","message":"can't find crate for `core`","code":{"code":"E0463","explanation":"A crate was declared but cannot be found.\n\nErroneous code example:\n\n```compile_fail,E0463\nextern crate foo; // error: can't find crate\n```\n\nYou need to link your code to the relevant crate in order to be able to use it\n(through Cargo or the `-L` option of rustc, for example).\n\n## Common causes\n\n- The crate is not present at all. If using Cargo, add it to `[dependencies]`\n in Cargo.toml.\n- The crate is present, but under a different name. If using Cargo, look for\n `package = ` under `[dependencies]` in Cargo.toml.\n\n## Common causes for missing `std` or `core`\n\n- You are cross-compiling for a target which doesn't have `std` prepackaged.\n Consider one of the following:\n + Adding a pre-compiled version of std with `rustup target add`\n + Building std from source with `cargo build -Z build-std`\n + Using `#![no_std]` at the crate root, so you won't need `std` in the first\n place.\n- You are developing the compiler itself and haven't built libstd from source.\n You can usually build it with `x.py build library/std`. More information\n about x.py is available in the [rustc-dev-guide].\n\n[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#building-the-compiler\n"},"level":"error","spans":[{"file_name":"src/main.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":"can't find crate","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the `riscv64gc-unknown-none-elf` target may not be installed","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider downloading the target with `rustup target add riscv64gc-unknown-none-elf`","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":"\u001b[1m\u001b[91merror[E0463]\u001b[0m\u001b[1m: can't find crate for `core`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: the `riscv64gc-unknown-none-elf` target may not be installed\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mhelp\u001b[0m: consider downloading the target with `rustup target add riscv64gc-unknown-none-elf`\n\n"}
|
||||
{"$message_type":"diagnostic","message":"aborting due to 1 previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[1m\u001b[91merror\u001b[0m\u001b[1m: aborting due to 1 previous error\u001b[0m\n\n"}
|
||||
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0463`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"\u001b[1mFor more information about this error, try `rustc --explain E0463`.\u001b[0m\n"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
This file has an mtime of when this was started.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{"$message_type":"diagnostic","message":"can't find crate for `core`","code":{"code":"E0463","explanation":"A crate was declared but cannot be found.\n\nErroneous code example:\n\n```compile_fail,E0463\nextern crate foo; // error: can't find crate\n```\n\nYou need to link your code to the relevant crate in order to be able to use it\n(through Cargo or the `-L` option of rustc, for example).\n\n## Common causes\n\n- The crate is not present at all. If using Cargo, add it to `[dependencies]`\n in Cargo.toml.\n- The crate is present, but under a different name. If using Cargo, look for\n `package = ` under `[dependencies]` in Cargo.toml.\n\n## Common causes for missing `std` or `core`\n\n- You are cross-compiling for a target which doesn't have `std` prepackaged.\n Consider one of the following:\n + Adding a pre-compiled version of std with `rustup target add`\n + Building std from source with `cargo build -Z build-std`\n + Using `#![no_std]` at the crate root, so you won't need `std` in the first\n place.\n- You are developing the compiler itself and haven't built libstd from source.\n You can usually build it with `x.py build library/std`. More information\n about x.py is available in the [rustc-dev-guide].\n\n[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#building-the-compiler\n"},"level":"error","spans":[{"file_name":"src/main.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":"can't find crate","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the `riscv64gc-unknown-none-elf` target may not be installed","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider downloading the target with `rustup target add riscv64gc-unknown-none-elf`","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":"\u001b[1m\u001b[91merror[E0463]\u001b[0m\u001b[1m: can't find crate for `core`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: the `riscv64gc-unknown-none-elf` target may not be installed\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mhelp\u001b[0m: consider downloading the target with `rustup target add riscv64gc-unknown-none-elf`\n\n"}
|
||||
{"$message_type":"diagnostic","message":"aborting due to 1 previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[1m\u001b[91merror\u001b[0m\u001b[1m: aborting due to 1 previous error\u001b[0m\n\n"}
|
||||
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0463`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"\u001b[1mFor more information about this error, try `rustc --explain E0463`.\u001b[0m\n"}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
const std = @import("std");
|
||||
|
||||
// 1. The SysTable Contract (Must match Kernel!)
|
||||
const ION_BASE = 0x83000000;
|
||||
|
||||
// The Physical Token representing a packet
|
||||
const IonPacket = extern struct {
|
||||
data: u64, // Virtual Addr (ptr)
|
||||
phys: u64, // Physical Addr
|
||||
len: u16,
|
||||
id: u16,
|
||||
};
|
||||
|
||||
const RingBuffer = extern struct {
|
||||
// Nim Kernel RingBuffer Layout:
|
||||
// data: array[N, T]
|
||||
// head: Cursor (Atomic[int64], padded to 64 bytes)
|
||||
// tail: Cursor (Atomic[int64], padded to 64 bytes)
|
||||
|
||||
data: [256]IonPacket,
|
||||
|
||||
// Head Cursor
|
||||
head_val: i64,
|
||||
head_pad: [56]u8,
|
||||
|
||||
// Tail Cursor
|
||||
tail_val: i64,
|
||||
tail_pad: [56]u8,
|
||||
};
|
||||
|
||||
const SysTable = extern struct {
|
||||
magic: u32,
|
||||
s_rx: *RingBuffer, // Kernel writes, We read
|
||||
s_tx: *RingBuffer, // We write (Network Data)
|
||||
s_event: *RingBuffer, // We write (Telemetry/Events)
|
||||
};
|
||||
|
||||
// 2. The Direct Accessor
|
||||
fn get_systable() *SysTable {
|
||||
return @ptrFromInt(ION_BASE);
|
||||
}
|
||||
|
||||
// 3. The Entry Point
|
||||
export fn main() c_int {
|
||||
// A. Announce presence
|
||||
print("[ZIG] ION Raw Test: Engaging...\n");
|
||||
|
||||
const sys = get_systable();
|
||||
|
||||
// B. Verify Magic (Sanity Check)
|
||||
print("[ZIG] Checking SysTable at 0x83000000...\n");
|
||||
if (sys.magic == 0x4E585553) {
|
||||
print("[ZIG] MAGIC VERIFIED: 0x4E585553 ('NXUS')\n");
|
||||
} else {
|
||||
print("[ZIG] MAGIC FAIL: 0x");
|
||||
print("Unknown\n");
|
||||
}
|
||||
|
||||
// C. ALLOCATE (Simulated for Raw Test)
|
||||
const pkt = IonPacket{
|
||||
.data = 0xDEADBEEF,
|
||||
.phys = 0xCAFEBABE,
|
||||
.len = 42,
|
||||
.id = 1,
|
||||
};
|
||||
|
||||
// D. PUSH to TX Ring (Network Sim)
|
||||
{
|
||||
const tx = sys.s_tx;
|
||||
const head = @atomicLoad(i64, &tx.head_val, .monotonic);
|
||||
const head_u64: u64 = @bitCast(head);
|
||||
const head_idx: u32 = @truncate(head_u64);
|
||||
tx.data[head_idx % 256] = pkt;
|
||||
@atomicStore(i64, &tx.head_val, head + 1, .release);
|
||||
print("[ZIG] Network Packet pushed to TX Ring.\n");
|
||||
}
|
||||
|
||||
// E. PUSH to EVENT Ring (Telemetry Sim)
|
||||
{
|
||||
const ev = sys.s_event;
|
||||
const head = @atomicLoad(i64, &ev.head_val, .monotonic);
|
||||
const head_u64: u64 = @bitCast(head);
|
||||
const head_idx: u32 = @truncate(head_u64);
|
||||
|
||||
const event = IonPacket{
|
||||
.data = 0,
|
||||
.phys = 0,
|
||||
.len = 0,
|
||||
.id = 777, // Event Type: 777 (Test Event)
|
||||
};
|
||||
|
||||
ev.data[head_idx % 256] = event;
|
||||
@atomicStore(i64, &ev.head_val, head + 1, .release);
|
||||
print("[ZIG] Telemetry Event pushed to EVENT Ring.\n");
|
||||
}
|
||||
|
||||
// F. YIELD / PUMP (Let Kernel Process)
|
||||
print("[ZIG] Yielding to Kernel...\n");
|
||||
|
||||
fiber_yield();
|
||||
|
||||
print("[ZIG] Control returned. Test Complete.\n");
|
||||
|
||||
while (true) {
|
||||
fiber_yield();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Minimal Shims
|
||||
extern fn write(fd: c_int, buf: [*]const u8, count: usize) isize;
|
||||
extern fn fiber_yield() void;
|
||||
|
||||
fn print(text: []const u8) void {
|
||||
_ = write(1, text.ptr, text.len);
|
||||
}
|
||||
|
||||
pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
|
||||
_ = error_return_trace;
|
||||
_ = ret_addr;
|
||||
print("\n[Zig] PANIC: ");
|
||||
print(msg);
|
||||
print("\n");
|
||||
while (true) {}
|
||||
}
|
||||
6
build.sh
6
build.sh
|
|
@ -220,7 +220,7 @@ nim c \
|
|||
--mm:arc \
|
||||
--noMain:on \
|
||||
--cc:clang \
|
||||
--passC:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -ffreestanding -fno-stack-protector -fno-builtin $ARCH_FLAGS -I$RUMPK_DIR/core/include -I$RUMPK_DIR/core/net -I$RUMPK_DIR/vendor/lwip/src/include" \
|
||||
--passC:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -ffreestanding -fno-stack-protector -fno-builtin $ARCH_FLAGS -I$RUMPK_DIR/core/include" \
|
||||
--define:useMalloc \
|
||||
--define:nimNoLibc \
|
||||
--define:noSignalHandler \
|
||||
|
|
@ -261,8 +261,6 @@ for cfile in "$BUILD_DIR/nimcache"/*.c; do
|
|||
-I"$RUMPK_DIR/core/include" \
|
||||
-I/usr/lib/nim \
|
||||
-I"$RUMPK_DIR/core" \
|
||||
-I"$RUMPK_DIR/core/net" \
|
||||
-I"$RUMPK_DIR/vendor/lwip/src/include" \
|
||||
-c "$cfile" \
|
||||
-o "$ofile"
|
||||
NIM_OBJS="$NIM_OBJS $ofile"
|
||||
|
|
@ -312,7 +310,6 @@ zig cc \
|
|||
-fno-builtin \
|
||||
-O2 \
|
||||
-I"$RUMPK_DIR/core/include" \
|
||||
-I"$RUMPK_DIR/core/net" \
|
||||
-I"$RUMPK_DIR/libs/membrane/include" \
|
||||
-I"$RUMPK_DIR/vendor/lwip/src/include" \
|
||||
-c "$RUMPK_DIR/libs/membrane/sys_arch.c" \
|
||||
|
|
@ -351,7 +348,6 @@ for cfile in "$BUILD_DIR/membrane_nimcache"/*.c; do
|
|||
-I/usr/lib/nim \
|
||||
-I"$RUMPK_DIR/core" \
|
||||
-I"$RUMPK_DIR/libs/membrane" \
|
||||
-I"$RUMPK_DIR/core/net" \
|
||||
-I"$RUMPK_DIR/libs/membrane/include" \
|
||||
-I"$RUMPK_DIR/vendor/lwip/src/include" \
|
||||
-c "$cfile" \
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `kernel.nim` | Main entry point (`kmain`), fiber test |
|
||||
| `kernel.nim` | Main Orchestrator (`kmain`) |
|
||||
| `ion.nim` | ION Control Plane & Channel API |
|
||||
| `fiber.nim` | Cooperative fiber abstraction |
|
||||
| `ring.nim` | Lock-free Disruptor ring buffer |
|
||||
| `panicoverride.nim` | Nim panic handler for freestanding |
|
||||
| `watchdog.nim` | Autonomous Immune System (Healer) |
|
||||
| `ring.nim` | Lock-free Sovereign ring buffers |
|
||||
| `panicoverride.nim` | Freestanding panic handler |
|
||||
|
||||
## Architecture Independence
|
||||
|
||||
|
|
|
|||
31
core/bus.nim
31
core/bus.nim
|
|
@ -1,31 +0,0 @@
|
|||
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||
# RUMPK CORE // BUS
|
||||
# The Global Message Bus for Nexus Channels.
|
||||
#
|
||||
# This registry allows Fibers to discover Channels by SipHash ID.
|
||||
|
||||
{.push stackTrace: off, lineTrace: off.}
|
||||
|
||||
import channel
|
||||
|
||||
const MAX_CHANNELS = 32
|
||||
|
||||
type
|
||||
Bus* = object
|
||||
channels*: array[MAX_CHANNELS, ptr Channel[64]] # Fixed size for now
|
||||
count*: int
|
||||
|
||||
var global_bus*: Bus
|
||||
|
||||
proc register*(chan: ptr Channel[64]) =
|
||||
if global_bus.count < MAX_CHANNELS:
|
||||
global_bus.channels[global_bus.count] = chan
|
||||
inc global_bus.count
|
||||
|
||||
proc findChannel*(id: ChannelID): ptr Channel[64] =
|
||||
for i in 0..<global_bus.count:
|
||||
if global_bus.channels[i].id == id:
|
||||
return global_bus.channels[i]
|
||||
return nil
|
||||
|
||||
{.pop.}
|
||||
|
|
@ -25,7 +25,7 @@ type
|
|||
size*: uint64
|
||||
|
||||
Channel*[N: static[int]] = object
|
||||
## A named pipe carrying Typed Messages
|
||||
## A typed channel carrying Messages
|
||||
id*: ChannelID
|
||||
name*: cstring
|
||||
buffer*: RingBuffer[Message, N]
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
# Markus Maiwald (Architect) | Voxis Forge (AI)
|
||||
# RUMPK CORE // CRYPTO
|
||||
# Wrapper for Monocypher
|
||||
|
||||
{.push stackTrace: off, lineTrace: off.}
|
||||
|
||||
# Monocypher ABI
|
||||
# int crypto_eddsa_check(const uint8_t sig[64], const uint8_t pub_key[32], const uint8_t *msg, size_t msg_size);
|
||||
# Returns 0 on success, -1 on failure.
|
||||
proc crypto_eddsa_check(sig: ptr uint8,
|
||||
pub_key: ptr uint8,
|
||||
msg: pointer,
|
||||
msg_size: csize_t): cint
|
||||
{.importc: "crypto_eddsa_check", header: "monocypher.h".}
|
||||
|
||||
# The Root of Trust (Hardcoded Public Key for now)
|
||||
# Enforce 16-byte alignment because Monocypher v4 uses SIMD ldp/stp (Q registers)
|
||||
# Using 'let' to ensure it resides in initialized data section.
|
||||
let ROOT_PUB_KEY* {.align: 16.}: array[32, uint8] = [
|
||||
0x19'u8, 0xD3, 0xD9, 0x19, 0x47, 0x5D, 0xEE, 0xD4,
|
||||
0x69, 0x6B, 0x5D, 0x13, 0x01, 0x81, 0x51, 0xD1,
|
||||
0xAF, 0x88, 0xB2, 0xBD, 0x3B, 0xCF, 0xF0, 0x48,
|
||||
0xB4, 0x50, 0x31, 0xC1, 0xF3, 0x6D, 0x18, 0x58
|
||||
]
|
||||
|
||||
proc verify_npl_signature*(sig: array[64, uint8], body_ptr: pointer,
|
||||
body_len: uint64): bool =
|
||||
# signature 'sig' is passed by value (copied on stack)
|
||||
# AArch64 stack is 16-byte aligned, so sig should be fine if we ensure it.
|
||||
var sig_aligned {.align: 16.} = sig
|
||||
|
||||
let s_ptr = unsafeAddr sig_aligned[0]
|
||||
let p_ptr = unsafeAddr ROOT_PUB_KEY[0]
|
||||
|
||||
let check_res = crypto_eddsa_check(s_ptr, p_ptr, body_ptr, cast[csize_t](body_len))
|
||||
|
||||
return check_res == 0
|
||||
|
||||
{.pop.}
|
||||
|
|
@ -183,11 +183,5 @@ int atoi(const char *nptr) {
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int errno = 0;
|
||||
|
||||
/* LwIP sys_now implementation */
|
||||
extern unsigned int get_ticks(void);
|
||||
unsigned int sys_now(void) {
|
||||
return get_ticks();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ export memory
|
|||
type
|
||||
CmdType* = enum
|
||||
CMD_NONE = 0
|
||||
CMD_NET_STOP = 1
|
||||
CMD_NET_START = 2
|
||||
CMD_ION_STOP = 1
|
||||
CMD_ION_START = 2
|
||||
CMD_DROP_ALL = 3
|
||||
|
||||
CmdPacket* = object
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
# ION Soft-Switch
|
||||
# Sovereign Dispatch Logic
|
||||
|
||||
import memory
|
||||
import ../ring
|
||||
import ../net # For LwIP fallback
|
||||
|
||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
|
||||
type
|
||||
FlowType* = enum
|
||||
FLOW_LWIP # The Unix Path
|
||||
FLOW_DIRECT # The ION Path
|
||||
|
||||
# A Subscription to the Bus
|
||||
NetFlow* = object
|
||||
port*: uint16
|
||||
ring*: ptr RingBuffer[IonPacket, 256] # Direct injection ring
|
||||
fType*: FlowType
|
||||
|
||||
var
|
||||
# The Lookup Table (Simple Array for Phase 7)
|
||||
# Index = Port Number.
|
||||
flow_table: array[65536, ptr NetFlow]
|
||||
|
||||
proc ion_register*(port: uint16, flow: ptr NetFlow) =
|
||||
flow_table[port] = flow
|
||||
|
||||
proc parse_dest_port(data: ptr UncheckedArray[byte]): uint16 =
|
||||
# Ethernet Type at 12. IP Protocol at 23. Dest Port at 36.
|
||||
if data[12] == 0x08 and data[13] == 0x00:
|
||||
# IPv4
|
||||
let proto = data[23]
|
||||
if proto == 17: # UDP
|
||||
let dport = (uint16(data[36]) shl 8) or uint16(data[37])
|
||||
return dport
|
||||
return 0
|
||||
|
||||
proc dispatch_packet(data: ptr UncheckedArray[byte], len: int, id: uint16) =
|
||||
let dest_port = parse_dest_port(data)
|
||||
let flow = if dest_port != 0: flow_table[dest_port] else: nil
|
||||
|
||||
if dest_port == 8080:
|
||||
var msg = "[ION SW] 8080 Hit! RingPtr="
|
||||
console_write(addr msg[0], csize_t(msg.len))
|
||||
# Simple address check (first 8 bytes of ptr)
|
||||
if flow != nil:
|
||||
var hex_str = "ADR\n"
|
||||
console_write(addr hex_str[0], 4)
|
||||
|
||||
var pkt: IonPacket
|
||||
pkt.id = id
|
||||
pkt.len = uint16(len)
|
||||
pkt.data = data
|
||||
|
||||
if flow != nil and flow.fType == FLOW_DIRECT:
|
||||
if flow.ring[].push(pkt):
|
||||
var msg = "[ION SW] Pushed to Ring!\n"
|
||||
console_write(addr msg[0], csize_t(msg.len))
|
||||
else:
|
||||
var msg = "[ION SW] Ring FULL!\n"
|
||||
console_write(addr msg[0], csize_t(msg.len))
|
||||
ion_free_raw(id)
|
||||
else:
|
||||
discard net_ingest_packet(cast[ptr byte](pkt.data), int(pkt.len))
|
||||
ion_free_raw(id)
|
||||
|
||||
proc ion_ingress*(id: uint16, len: uint16) {.exportc.} =
|
||||
## The Hot Path. Called by VirtIO Interrupt/Poller.
|
||||
## Takes a Slab ID that has been filled by NIC or local TX.
|
||||
|
||||
const VIRTIO_NET_HDR_SIZE = 10
|
||||
let slab_base = ion_get_virt(id)
|
||||
|
||||
if len <= VIRTIO_NET_HDR_SIZE:
|
||||
# Packet too small (just header or less)
|
||||
ion_free_raw(id)
|
||||
return
|
||||
|
||||
# Adjust for Headroom (Zero-Copy Pointer Math)
|
||||
# eth_frame points to the Ethernet Header, skipping VirtIO Header
|
||||
let eth_frame = cast[ptr UncheckedArray[byte]](cast[uint](slab_base) + VIRTIO_NET_HDR_SIZE)
|
||||
let eth_len = int(len) - VIRTIO_NET_HDR_SIZE
|
||||
|
||||
# DEBUG: Print RX packet info (Full Eth Header)
|
||||
var prefix = "[ION] RX: "
|
||||
console_write(addr prefix[0], csize_t(prefix.len))
|
||||
|
||||
const hexDigits = "0123456789ABCDEF"
|
||||
for i in 0..<14:
|
||||
let b = eth_frame[i]
|
||||
var hex: array[3, char]
|
||||
hex[0] = hexDigits[int(b shr 4)]
|
||||
hex[1] = hexDigits[int(b and 0xF)]
|
||||
hex[2] = if i == 5 or i == 11: '|' else: ' '
|
||||
if i == 13: hex[2] = '\n'
|
||||
console_write(addr hex[0], 3)
|
||||
|
||||
dispatch_packet(eth_frame, eth_len, id)
|
||||
|
||||
proc ion_egress*(pkt: IonPacket) {.exportc.} =
|
||||
## The Fast Path TX (Standard Interface)
|
||||
if not ion_tx_push(pkt):
|
||||
# Backpressure / Ring Full -> Drop
|
||||
var msg = "[ION SW] TX Ring FULL! Dropping.\n"
|
||||
console_write(addr msg[0], csize_t(msg.len))
|
||||
ion_free(pkt)
|
||||
|
||||
proc ion_egress_to_port*(port: uint16, pkt: IonPacket) {.exportc.} =
|
||||
## Route a packet to a specific ION Port.
|
||||
## Port 0 is reserved for Kernel Console.
|
||||
if port == 0:
|
||||
when defined(is_kernel):
|
||||
console_write(pkt.data, csize_t(pkt.len))
|
||||
ion_free(pkt)
|
||||
else:
|
||||
# In the Membrane, Port 0 egresses to the Bus
|
||||
ion_egress(pkt)
|
||||
else:
|
||||
# Future: Internal routing via flow_table
|
||||
ion_egress(pkt)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# ION Memory Manager
|
||||
# The "Slab Allocator" for Zero-Copy Networking
|
||||
# The "Slab Allocator" for Zero-Copy IO
|
||||
|
||||
import ../ring
|
||||
|
||||
|
|
@ -33,6 +33,7 @@ var global_pool: PacketPool
|
|||
|
||||
proc ion_pool_init*() {.exportc.} =
|
||||
## Initialize the DMA Pool with REAL Physical Address
|
||||
dbg("[ION] Initializing Pool...")
|
||||
|
||||
# 1. Get the VIRTUAL address of the static buffer
|
||||
let virt_addr = cast[uint64](addr global_pool.buffer[0])
|
||||
|
|
@ -40,18 +41,17 @@ proc ion_pool_init*() {.exportc.} =
|
|||
# 2. Translate to PHYSICAL (Identity Mapped for Phase 7)
|
||||
global_pool.base_phys = virt_addr
|
||||
|
||||
dbg("[ION] Pool Phys Base: " & $global_pool.base_phys) # Basic int print, need hex for full confirmation but this proves non-zero
|
||||
|
||||
dbg("[ION] Ring Init...")
|
||||
global_pool.free_ring.init()
|
||||
|
||||
# Fill the free ring with all indices [0..1023]
|
||||
# Fill the free ring with all indices [0..1023]
|
||||
dbg("[ION] Filling Slabs...")
|
||||
var count = 0
|
||||
for i in 0 ..< POOL_COUNT:
|
||||
if global_pool.free_ring.push(uint16(i)):
|
||||
inc count
|
||||
|
||||
dbg("[ION] Pushed " & $count & " slabs to ring.")
|
||||
dbg("[ION] Pool Ready.")
|
||||
|
||||
proc ion_alloc*(): IonPacket {.exportc.} =
|
||||
## O(1) Allocation. Returns an empty packet struct.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import fiber
|
|||
import ion
|
||||
|
||||
|
||||
var net_paused*: bool = false
|
||||
var ion_paused*: bool = false
|
||||
var pause_start*: uint64 = 0
|
||||
|
||||
|
||||
|
|
@ -15,12 +15,12 @@ var pause_start*: uint64 = 0
|
|||
# Fiber Management (Forward Declared)
|
||||
# =========================================================
|
||||
|
||||
var fiber_net: FiberObject
|
||||
var fiber_ion: FiberObject
|
||||
var fiber_nexshell: FiberObject
|
||||
var fiber_subject: FiberObject
|
||||
var fiber_watchdog: FiberObject
|
||||
|
||||
# POSIX-like exports for Zig NPLs
|
||||
# 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)
|
||||
|
|
@ -37,14 +37,14 @@ proc kprintln*(s: cstring) {.exportc, cdecl.} =
|
|||
kprint(s); kprint("\n")
|
||||
|
||||
proc rumpk_yield_internal() {.cdecl, exportc.} =
|
||||
if current_fiber == addr fiber_net:
|
||||
if current_fiber == addr fiber_ion:
|
||||
switch(addr fiber_nexshell)
|
||||
elif current_fiber == addr fiber_nexshell:
|
||||
switch(addr fiber_subject)
|
||||
elif current_fiber == addr fiber_subject:
|
||||
switch(addr fiber_watchdog)
|
||||
else:
|
||||
switch(addr fiber_net)
|
||||
switch(addr fiber_ion)
|
||||
|
||||
proc fiber_yield*() {.exportc, cdecl.} =
|
||||
rumpk_yield_internal()
|
||||
|
|
@ -74,7 +74,7 @@ var chan_cmd*: SovereignChannel[CmdPacket]
|
|||
|
||||
# HAL/NPL Entry points
|
||||
proc rumpk_halt() {.importc, cdecl, noreturn.}
|
||||
proc virtio_net_init() {.importc, cdecl.}
|
||||
proc hal_io_init() {.importc, cdecl.}
|
||||
proc nexshell_main() {.importc, cdecl.}
|
||||
proc launch_subject() {.importc, cdecl.}
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} =
|
|||
# Fiber Entries
|
||||
# =========================================================
|
||||
|
||||
var stack_net: array[32768, uint8]
|
||||
var stack_ion: array[32768, uint8]
|
||||
var stack_nexshell: array[32768, uint8]
|
||||
var stack_subject: array[65536, uint8]
|
||||
var stack_watchdog: array[4096, uint8]
|
||||
|
|
@ -105,9 +105,9 @@ proc subject_fiber_entry() {.cdecl.} =
|
|||
# Include Watchdog Logic (Access to Kernel Globals)
|
||||
include watchdog
|
||||
|
||||
proc net_fiber_entry() {.cdecl.} =
|
||||
kprint("[Net] Fiber 1 Reporting for Duty.")
|
||||
if net_paused: kprintln(" (PAUSED)") else: kprintln("")
|
||||
proc ion_fiber_entry() {.cdecl.} =
|
||||
kprint("[ION] Fiber 1 Reporting for Duty.")
|
||||
if ion_paused: kprintln(" (PAUSED)") else: kprintln("")
|
||||
|
||||
var pkt: IonPacket
|
||||
var cmd: CmdPacket
|
||||
|
|
@ -115,21 +115,21 @@ proc net_fiber_entry() {.cdecl.} =
|
|||
while true:
|
||||
# 1. Process Commands
|
||||
if chan_cmd.recv(cmd):
|
||||
if cmd.kind == uint32(CMD_NET_STOP):
|
||||
kprintln("[Net] STOP received. Suspending IO.")
|
||||
net_paused = true
|
||||
if cmd.kind == uint32(CMD_ION_STOP):
|
||||
kprintln("[ION] STOP received. Suspending IO.")
|
||||
ion_paused = true
|
||||
pause_start = cpu_ticks()
|
||||
elif cmd.kind == uint32(CMD_NET_START):
|
||||
kprintln("[Net] START received. Resuming IO.")
|
||||
net_paused = false
|
||||
elif cmd.kind == uint32(CMD_ION_START):
|
||||
kprintln("[ION] START received. Resuming IO.")
|
||||
ion_paused = false
|
||||
|
||||
# 2. Process Data (if not paused)
|
||||
if not net_paused:
|
||||
if not ion_paused:
|
||||
if chan_tx.recv(pkt):
|
||||
kprintln("[Net] Packet intercepted. Generating Telemetry...")
|
||||
kprintln("[ION] Packet intercepted. Generating Telemetry...")
|
||||
var alert = IonPacket(id: 777, len: 42)
|
||||
chan_event.send(alert)
|
||||
kprintln("[Net] Event dispatched.")
|
||||
kprintln("[ION] Event dispatched.")
|
||||
|
||||
fiber_yield()
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ proc kmain() {.exportc, cdecl.} =
|
|||
# 1. Hardware & Memory
|
||||
kprintln("[Kernel] Initializing Memory Substrate...")
|
||||
ion_pool_init()
|
||||
virtio_net_init()
|
||||
hal_io_init()
|
||||
|
||||
# 2. Channel Infrastructure
|
||||
kprintln("[Kernel] Mapping Sovereign Channels...")
|
||||
|
|
@ -183,8 +183,8 @@ proc kmain() {.exportc, cdecl.} =
|
|||
# 4. Deployment
|
||||
kprintln("[Kernel] Spawning System Fibers...")
|
||||
|
||||
# 1. NETWORK FIBER (The Valve)
|
||||
init_fiber(addr fiber_net, net_fiber_entry, addr stack_net[0], sizeof(stack_net))
|
||||
# 1. ION FIBER (The Valve)
|
||||
init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion))
|
||||
|
||||
# 2. NEXSHELL FIBER (The Brain)
|
||||
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell))
|
||||
|
|
@ -199,6 +199,6 @@ proc kmain() {.exportc, cdecl.} =
|
|||
kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.")
|
||||
|
||||
# Handover to Scheduler (The Heartbeat)
|
||||
switch(addr fiber_net)
|
||||
switch(addr fiber_ion)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
225
core/net.nim
225
core/net.nim
|
|
@ -1,225 +0,0 @@
|
|||
# Rumpk LwIP Bridge
|
||||
# FFI wrapper for LwIP static library
|
||||
|
||||
import ring
|
||||
|
||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
|
||||
const
|
||||
MAX_PACKET_SIZE = 1536
|
||||
RING_SIZE = 256
|
||||
|
||||
type
|
||||
LwipErr* = int8
|
||||
|
||||
const
|
||||
ERR_OK* = 0
|
||||
ERR_MEM* = -1
|
||||
ERR_BUF* = -2
|
||||
ERR_TIMEOUT* = -3
|
||||
ERR_RTE* = -4
|
||||
ERR_INPROGRESS* = -5
|
||||
ERR_VAL* = -6
|
||||
ERR_WOULDBLOCK* = -7
|
||||
ERR_USE* = -8
|
||||
ERR_ALREADY* = -9
|
||||
ERR_ISCONN* = -10
|
||||
ERR_CONN* = -11
|
||||
ERR_IF* = -12
|
||||
ERR_ABRT* = -13
|
||||
ERR_RST* = -14
|
||||
ERR_CLSD* = -15
|
||||
ERR_ARG* = -16
|
||||
|
||||
type
|
||||
PbufLayer* = cint
|
||||
PbufType* = cint
|
||||
|
||||
Pbuf* {.importc: "struct pbuf", header: "lwip/pbuf.h",
|
||||
incompleteStruct.} = object
|
||||
next*: ptr Pbuf
|
||||
payload*: pointer
|
||||
tot_len*: uint16
|
||||
len*: uint16
|
||||
|
||||
IpAddr* {.importc: "ip4_addr_t", header: "lwip/ip_addr.h".} = object
|
||||
addr_val* {.importc: "addr".}: uint32
|
||||
|
||||
NetIf* {.importc: "struct netif", header: "lwip/netif.h",
|
||||
incompleteStruct.} = object
|
||||
next*: ptr NetIf
|
||||
ip_addr*, netmask*, gw*: IpAddr
|
||||
|
||||
var
|
||||
PBUF_RAW* {.importc: "PBUF_RAW", header: "lwip/pbuf.h", nodecl.}: cint
|
||||
PBUF_RAM* {.importc: "PBUF_RAM", header: "lwip/pbuf.h", nodecl.}: cint
|
||||
PBUF_POOL* {.importc: "PBUF_POOL", header: "lwip/pbuf.h", nodecl.}: cint
|
||||
|
||||
type
|
||||
NetPacket* = object
|
||||
len*: int
|
||||
data*: array[MAX_PACKET_SIZE, byte]
|
||||
|
||||
var netRing*: RingBuffer[NetPacket, RING_SIZE]
|
||||
var rumpk_netif*: NetIf
|
||||
var ip, mask, gw: IpAddr
|
||||
|
||||
# FFI Procedures
|
||||
proc lwip_init*() {.importc: "lwip_init", header: "lwip/init.h".}
|
||||
|
||||
proc netif_add*(netif: ptr NetIf; ipaddr, netmask, gw: ptr IpAddr; state: pointer;
|
||||
init: proc(netif: ptr NetIf): LwipErr {.cdecl.};
|
||||
input: proc(p: ptr Pbuf; netif: ptr NetIf): LwipErr {.cdecl.}): ptr NetIf {.importc: "netif_add",
|
||||
header: "lwip/netif.h".}
|
||||
|
||||
proc netif_set_up*(netif: ptr NetIf) {.importc: "netif_set_up",
|
||||
header: "lwip/netif.h".}
|
||||
proc netif_set_link_up*(netif: ptr NetIf) {.importc: "netif_set_link_up",
|
||||
header: "lwip/netif.h".}
|
||||
proc netif_set_default*(netif: ptr NetIf) {.importc: "netif_set_default",
|
||||
header: "lwip/netif.h".}
|
||||
proc sys_check_timeouts() {.importc: "sys_check_timeouts",
|
||||
header: "lwip/timeouts.h".}
|
||||
|
||||
proc pbuf_alloc*(layer: PbufLayer; length: uint16;
|
||||
ptype: PbufType): ptr Pbuf {.importc: "pbuf_alloc", header: "lwip/pbuf.h".}
|
||||
proc pbuf_free*(p: ptr Pbuf): uint8 {.importc: "pbuf_free",
|
||||
header: "lwip/pbuf.h".}
|
||||
|
||||
proc ethernet_input*(p: ptr Pbuf; netif: ptr NetIf): LwipErr {.importc: "ethernet_input",
|
||||
header: "netif/ethernet.h".}
|
||||
|
||||
# Sovereign Integration (HAL)
|
||||
proc virtio_net_poll() {.importc: "virtio_net_poll", cdecl.}
|
||||
proc virtio_net_send(data: pointer; len: csize_t) {.importc: "virtio_net_send", cdecl.}
|
||||
|
||||
# Architecture Agnostic IP Packing
|
||||
func htonl(x: uint32): uint32 =
|
||||
when cpuEndian == littleEndian:
|
||||
(x shr 24) or ((x shr 8) and 0xff00) or ((x shl 8) and 0xff0000) or (x shl 24)
|
||||
else: x
|
||||
|
||||
func packIp(a, b, c, d: uint8): uint32 =
|
||||
uint32(a) shl 24 or uint32(b) shl 16 or uint32(c) shl 8 or uint32(d)
|
||||
|
||||
proc link_output(netif: ptr NetIf; p: ptr Pbuf): LwipErr {.cdecl.} =
|
||||
## Callback from LwIP when a packet needs to be sent
|
||||
if p != nil:
|
||||
# Phase 7: We send the whole packet in one go.
|
||||
virtio_net_send(p.payload, csize_t(p.tot_len))
|
||||
return ERR_OK
|
||||
return ERR_VAL
|
||||
|
||||
proc net_driver_init*(netif: ptr NetIf): LwipErr {.cdecl.} =
|
||||
# Driver initialization hook
|
||||
{.emit: """
|
||||
((struct netif*)`netif`)->mtu = 1500;
|
||||
((struct netif*)`netif`)->hwaddr_len = 6;
|
||||
((struct netif*)`netif`)->hwaddr[0] = 0x52;
|
||||
((struct netif*)`netif`)->hwaddr[1] = 0x54;
|
||||
((struct netif*)`netif`)->hwaddr[2] = 0x00;
|
||||
((struct netif*)`netif`)->hwaddr[3] = 0x12;
|
||||
((struct netif*)`netif`)->hwaddr[4] = 0x34;
|
||||
((struct netif*)`netif`)->hwaddr[5] = 0x56;
|
||||
|
||||
// NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_ETHERNET
|
||||
((struct netif*)`netif`)->flags = 0x02 | 0x08 | 0x10 | 0x40;
|
||||
|
||||
// Wire Tx output
|
||||
((struct netif*)`netif`)->linkoutput = `link_output`;
|
||||
""".}
|
||||
return ERR_OK
|
||||
|
||||
proc net_init*() =
|
||||
## Initialize the networking subsystem
|
||||
netRing.init()
|
||||
lwip_init()
|
||||
|
||||
# QEMU User Networking Defaults (10.0.2.15)
|
||||
ip.addr_val = htonl(packIp(10, 0, 2, 15))
|
||||
mask.addr_val = htonl(packIp(255, 255, 255, 0))
|
||||
gw.addr_val = htonl(packIp(10, 0, 2, 2))
|
||||
|
||||
# Register the Interface
|
||||
discard netif_add(addr rumpk_netif, addr ip, addr mask, addr gw,
|
||||
nil, net_driver_init,
|
||||
cast[proc(p: ptr Pbuf;
|
||||
netif: ptr NetIf): LwipErr {.cdecl.}](ethernet_input))
|
||||
|
||||
# Bring it UP
|
||||
netif_set_up(addr rumpk_netif)
|
||||
netif_set_link_up(addr rumpk_netif)
|
||||
netif_set_default(addr rumpk_netif)
|
||||
|
||||
# Force Gratuitous ARP to announce our MAC to the network/SLIRP
|
||||
proc etharp_gratuitous(netif: ptr NetIf) {.importc: "etharp_gratuitous",
|
||||
header: "netif/etharp.h".}
|
||||
etharp_gratuitous(addr rumpk_netif)
|
||||
|
||||
proc net_ingest_packet*(data: ptr byte; len: int): bool {.exportc.} =
|
||||
## Ingest a raw ethernet frame from the hardware
|
||||
var pkt: NetPacket
|
||||
if len > MAX_PACKET_SIZE: return false
|
||||
|
||||
pkt.len = len
|
||||
copyMem(addr pkt.data[0], data, len)
|
||||
return netRing.push(pkt)
|
||||
|
||||
proc fiber_yield() =
|
||||
# Don't use WFI - it blocks without interrupts configured
|
||||
# Use simple spin-loop for now
|
||||
for i in 0..100:
|
||||
{.emit: "asm volatile(\"nop\");".}
|
||||
|
||||
proc net_loop_cycle*(netif: ptr NetIf) =
|
||||
## One cycle of the networking logic (Poll + Drain + LwIP)
|
||||
|
||||
# 1. Poll Hardware
|
||||
virtio_net_poll()
|
||||
|
||||
# 2. Drain the Ring
|
||||
var work_done = false
|
||||
while not netRing.isEmpty:
|
||||
let (ok, pkt) = netRing.pop()
|
||||
if ok:
|
||||
work_done = true
|
||||
let p = pbuf_alloc(PBUF_RAW, uint16(pkt.len), PBUF_POOL)
|
||||
if p != nil:
|
||||
copyMem(p.payload, unsafeAddr pkt.data[0], pkt.len)
|
||||
let err = ethernet_input(p, netif)
|
||||
if err != ERR_OK:
|
||||
var msg = "[Net] ethernet_input failed\n"
|
||||
console_write(addr msg[0], csize_t(msg.len))
|
||||
discard pbuf_free(p)
|
||||
else:
|
||||
var msg = "[Net] pbuf_alloc FAILED (OOM?)\n"
|
||||
console_write(addr msg[0], csize_t(msg.len))
|
||||
|
||||
# 3. LwIP Maintenance
|
||||
sys_check_timeouts()
|
||||
|
||||
# 4. Periodic Activity (Every 5000 loops)
|
||||
const PERIOD = 5000
|
||||
var counter {.global.} = 0
|
||||
counter += 1
|
||||
if counter >= PERIOD:
|
||||
counter = 0
|
||||
# Send UDP Heartbeat to Gateway
|
||||
var frame: array[64, byte]
|
||||
# (Simplified frame construction for clarity)
|
||||
for i in 0..63: frame[i] = 0
|
||||
frame[0] = 0x52; frame[1] = 0x55; frame[2] = 0x0A; frame[3] = 0x00; frame[
|
||||
4] = 0x02; frame[5] = 0x02 # Dst
|
||||
frame[6] = 0x52; frame[7] = 0x54; frame[8] = 0x00; frame[9] = 0x12; frame[
|
||||
10] = 0x34; frame[11] = 0x56 # Src
|
||||
frame[12] = 0x08; frame[13] = 0x00 # IPv4
|
||||
frame[14] = 0x45; frame[23] = 17 # UDP
|
||||
frame[26] = 10; frame[27] = 0; frame[28] = 2; frame[29] = 15 # Src IP
|
||||
frame[30] = 10; frame[31] = 0; frame[32] = 2; frame[33] = 2 # Dst IP
|
||||
frame[34] = 0x1F; frame[35] = 0x90; frame[36] = 0x1F; frame[37] = 0x90 # Ports 8080
|
||||
frame[42] = ord('H').byte; frame[43] = ord('I').byte
|
||||
virtio_net_send(addr frame[0], 64)
|
||||
|
||||
# 5. Yield / Governor
|
||||
if not work_done:
|
||||
fiber_yield()
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#ifndef LWIP_HDR_CC_H
|
||||
#define LWIP_HDR_CC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// 1. Basic Types
|
||||
typedef uint8_t u8_t;
|
||||
typedef int8_t s8_t;
|
||||
typedef uint16_t u16_t;
|
||||
typedef int16_t s16_t;
|
||||
typedef uint32_t u32_t;
|
||||
typedef int32_t s32_t;
|
||||
typedef uintptr_t mem_ptr_t;
|
||||
typedef int sys_prot_t;
|
||||
|
||||
// 2. Format specifiers
|
||||
#define U16_F "hu"
|
||||
#define S16_F "hd"
|
||||
#define X16_F "hx"
|
||||
#define U32_F "u"
|
||||
#define S32_F "d"
|
||||
#define X32_F "x"
|
||||
#define X8_F "02x"
|
||||
#define SZT_F "zu"
|
||||
|
||||
// 3. Byte order
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
// 4. Compiler hints
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_STRUCT __attribute__((packed))
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
// 5. Diagnostics
|
||||
void printf(const char *format, ...);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#ifndef LWIP_HDR_PERF_H
|
||||
#define LWIP_HDR_PERF_H
|
||||
#define LWIP_PERF_START
|
||||
#define LWIP_PERF_STOP(x)
|
||||
#endif
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef LWIP_HDR_LWIPOPTS_H
|
||||
#define LWIP_HDR_LWIPOPTS_H
|
||||
|
||||
// 1. The Unikernel Mode (No OS threads)
|
||||
#define NO_SYS 1
|
||||
#define LWIP_TIMERS 1 // We must call sys_check_timeouts() manually
|
||||
|
||||
// 1.1 Disable Sequential/Socket APIs
|
||||
#define LWIP_NETCONN 0
|
||||
#define LWIP_SOCKET 0
|
||||
#define LWIP_STATS 0
|
||||
#define SYS_LIGHTWEIGHT_PROT 0
|
||||
#define LWIP_ETHERNET 1
|
||||
|
||||
// 2. Memory Strategy (Static Slabs - No Heap)
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
#define MEMP_MEM_MALLOC 0
|
||||
#define MEM_ALIGNMENT 64 // Cache Line Alignment (Critical for Disruptor)
|
||||
|
||||
// 3. Performance Tuning (Sovereign Scale)
|
||||
#define TCP_MSS 1460
|
||||
#define TCP_WND (8 * TCP_MSS)
|
||||
#define LWIP_TCP_KEEPALIVE 1
|
||||
|
||||
// 4. Checksum Offload (Let Hardware do it if VirtIO supports it)
|
||||
// For now, software checksums to be safe on QEMU
|
||||
#define CHECKSUM_GEN_IP 1
|
||||
#define CHECKSUM_GEN_TCP 1
|
||||
|
||||
// 6. Freestanding overrides
|
||||
#define LWIP_NO_INTTYPES_H 1
|
||||
|
||||
// 5. Debugging (The HUD Needs Logs)
|
||||
#define LWIP_DEBUG 1
|
||||
#define LWIP_PLATFORM_DIAG(x) do { printf x; } while(0)
|
||||
#define LWIP_PLATFORM_ASSERT(x) do { printf("ASSERT: %s\n", x); } while(0)
|
||||
|
||||
#endif
|
||||
123
core/npl.nim
123
core/npl.nim
|
|
@ -1,123 +0,0 @@
|
|||
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||
# RUMPK CORE // NPL FORMAT
|
||||
# The Contract of Execution.
|
||||
|
||||
{.push stackTrace: off, lineTrace: off.}
|
||||
|
||||
import crypto
|
||||
|
||||
# =========================================================
|
||||
# Constants
|
||||
# =========================================================
|
||||
|
||||
const NPL_MAGIC*: array[4, uint8] = [0x7F'u8, 0x4E'u8, 0x50'u8, 0x4C'u8]
|
||||
const NPL_VERSION* = 1'u8
|
||||
const ARCH_ARM64* = 0xAA'u8
|
||||
const ARCH_X86_64* = 0xEE'u8
|
||||
const ARCH_RISCV64* = 0x55'u8
|
||||
const NPL_HEADER_SIZE* = 128
|
||||
|
||||
# =========================================================
|
||||
# Types
|
||||
# =========================================================
|
||||
|
||||
type
|
||||
NPLHeader* {.packed.} = object
|
||||
magic*: array[4, uint8]
|
||||
version*: uint8
|
||||
arch*: uint8
|
||||
flags*: uint16
|
||||
reserved0*: array[8, uint8] # Alignment padding for signature
|
||||
signature*: array[64, uint8]
|
||||
body_size*: uint64
|
||||
reserved1*: array[40, uint8] # Remaining padding
|
||||
|
||||
PayloadEntry* = proc() {.cdecl.}
|
||||
|
||||
# Global last error (avoids struct return issues)
|
||||
var nplLastError*: cstring = nil
|
||||
|
||||
# =========================================================
|
||||
# Architecture Detection
|
||||
# =========================================================
|
||||
|
||||
proc currentArch*(): uint8 =
|
||||
when defined(arm64) or defined(aarch64):
|
||||
return ARCH_ARM64
|
||||
elif defined(amd64) or defined(x86_64):
|
||||
return ARCH_X86_64
|
||||
elif defined(riscv64):
|
||||
return ARCH_RISCV64
|
||||
else:
|
||||
return 0x00'u8
|
||||
|
||||
# =========================================================
|
||||
# NPL Loader (returns nil on failure, sets nplLastError)
|
||||
# =========================================================
|
||||
|
||||
proc loadNpl*(rawPtr: pointer, maxLen: uint64): PayloadEntry =
|
||||
nplLastError = nil
|
||||
|
||||
if rawPtr == nil:
|
||||
nplLastError = "null pointer"
|
||||
return nil
|
||||
|
||||
let header = cast[ptr NPLHeader](rawPtr)
|
||||
|
||||
# Check Magic
|
||||
if header.magic[0] != NPL_MAGIC[0] or
|
||||
header.magic[1] != NPL_MAGIC[1] or
|
||||
header.magic[2] != NPL_MAGIC[2] or
|
||||
header.magic[3] != NPL_MAGIC[3]:
|
||||
nplLastError = "bad magic"
|
||||
return nil
|
||||
|
||||
# Check Version
|
||||
if header.version != NPL_VERSION:
|
||||
nplLastError = "bad version"
|
||||
return nil
|
||||
|
||||
# Check Architecture
|
||||
if header.arch != currentArch():
|
||||
nplLastError = "bad arch"
|
||||
return nil
|
||||
|
||||
# Check Bounds
|
||||
let totalSize = NPL_HEADER_SIZE.uint64 + header.body_size
|
||||
if totalSize > maxLen:
|
||||
nplLastError = "truncated"
|
||||
return nil
|
||||
|
||||
# Get body pointer
|
||||
let bodyPtr = cast[pointer](cast[uint64](rawPtr) + NPL_HEADER_SIZE.uint64)
|
||||
|
||||
# Verify Signature (REAL CRYPTO)
|
||||
if not verify_npl_signature(header.signature, bodyPtr, header.body_size):
|
||||
nplLastError = "signature fail"
|
||||
return nil
|
||||
|
||||
# Cast body to function pointer
|
||||
return cast[PayloadEntry](bodyPtr)
|
||||
|
||||
# =========================================================
|
||||
# Helper: Build Test Payload
|
||||
# =========================================================
|
||||
|
||||
proc buildTestPayload*(buffer: ptr array[256, uint8], arch: uint8,
|
||||
codeBytes: openArray[uint8]) =
|
||||
# Clear buffer
|
||||
for i in 0..<256:
|
||||
buffer[i] = 0
|
||||
|
||||
let header = cast[ptr NPLHeader](buffer)
|
||||
header.magic = NPL_MAGIC
|
||||
header.version = NPL_VERSION
|
||||
header.arch = arch
|
||||
header.flags = 1
|
||||
header.body_size = codeBytes.len.uint64
|
||||
|
||||
# Copy code to body
|
||||
for i, b in codeBytes:
|
||||
buffer[NPL_HEADER_SIZE + i] = b
|
||||
|
||||
{.pop.}
|
||||
|
|
@ -12,21 +12,20 @@ proc watchdog_loop() {.cdecl.} =
|
|||
kprintln("[Watchdog] Immune System Online.")
|
||||
|
||||
while true:
|
||||
# Check if network is stuck in PAUSE state
|
||||
if net_paused:
|
||||
# Check if IO is stuck in PAUSE state
|
||||
if ion_paused:
|
||||
let now = cpu_ticks()
|
||||
|
||||
# If paused and time exceeds threshold
|
||||
# Note: pause_start needs to be set when pausing!
|
||||
if (pause_start > 0) and (now > pause_start) and (now - pause_start >
|
||||
MAX_PAUSE_TICKS):
|
||||
# HEAL
|
||||
kprint("[IMMUNE] Network paused too long. Forcing RESUME.\n")
|
||||
net_paused = false
|
||||
kprint("[IMMUNE] IO paused too long. Forcing RESUME.\n")
|
||||
ion_paused = false
|
||||
pause_start = 0
|
||||
|
||||
# Send CMD_NET_START to the Control Loop
|
||||
var cmd = CmdPacket(kind: uint32(ion.CmdType.CMD_NET_START), arg: 0)
|
||||
# Send CMD_ION_START to the Control Loop
|
||||
var cmd = CmdPacket(kind: uint32(ion.CmdType.CMD_ION_START), arg: 0)
|
||||
chan_cmd.send(cmd)
|
||||
|
||||
# Cooperative Multitasking: Must yield!
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// HAL ABI - The Contract between L0 (Zig) and L1 (Nim)
|
||||
// This struct is the "socket" for future language integration
|
||||
// This struct is the "contract" for future language integration
|
||||
|
||||
pub const HAL = extern struct {
|
||||
/// Write to console/serial
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ SECTIONS
|
|||
}
|
||||
|
||||
.data : {
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__global_pointer$ = . + 0x800);
|
||||
*(.data .data.*)
|
||||
*(.sdata .sdata.*)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
/* MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||
RUMPK HAL // RISC-V 64 CONTEXT SWITCH
|
||||
RUMPK HAL // RISC-V 64 CONTEXT SWITCH (Boundaries Protected)
|
||||
|
||||
RISC-V LP64 ABI Callee-Saved:
|
||||
RISC-V LP64 ABI Saved Registers + Bounds:
|
||||
- ra (return address)
|
||||
- gp (global pointer)
|
||||
- tp (thread pointer)
|
||||
- s0-s11 (12 saved registers)
|
||||
- fp (frame pointer, alias for s0)
|
||||
|
||||
Frame: 14 regs * 8 = 112 bytes (16-byte aligned)
|
||||
Frame: 16 regs * 8 = 128 bytes (16-byte aligned)
|
||||
*/
|
||||
|
||||
.global cpu_switch_to
|
||||
|
|
@ -17,24 +18,25 @@
|
|||
# a1 = next_sp
|
||||
|
||||
cpu_switch_to:
|
||||
# 1. Allocate Stack (112 bytes)
|
||||
addi sp, sp, -112
|
||||
# 1. Allocate Stack (128 bytes)
|
||||
addi sp, sp, -128
|
||||
|
||||
# 2. Save Context (ra, s0-s11, fp)
|
||||
# 2. Save Context
|
||||
sd ra, 0(sp)
|
||||
sd s0, 8(sp)
|
||||
sd s1, 16(sp)
|
||||
sd s2, 24(sp)
|
||||
sd s3, 32(sp)
|
||||
sd s4, 40(sp)
|
||||
sd s5, 48(sp)
|
||||
sd s6, 56(sp)
|
||||
sd s7, 64(sp)
|
||||
sd s8, 72(sp)
|
||||
sd s9, 80(sp)
|
||||
sd s10, 88(sp)
|
||||
sd s11, 96(sp)
|
||||
# fp is alias for s0, already saved
|
||||
sd gp, 8(sp)
|
||||
sd tp, 16(sp)
|
||||
sd s0, 24(sp)
|
||||
sd s1, 32(sp)
|
||||
sd s2, 40(sp)
|
||||
sd s3, 48(sp)
|
||||
sd s4, 56(sp)
|
||||
sd s5, 64(sp)
|
||||
sd s6, 72(sp)
|
||||
sd s7, 80(sp)
|
||||
sd s8, 88(sp)
|
||||
sd s9, 96(sp)
|
||||
sd s10, 104(sp)
|
||||
sd s11, 112(sp)
|
||||
|
||||
# 3. Save Old SP
|
||||
sd sp, 0(a0)
|
||||
|
|
@ -44,18 +46,49 @@ cpu_switch_to:
|
|||
|
||||
# 5. Restore Context
|
||||
ld ra, 0(sp)
|
||||
ld s0, 8(sp)
|
||||
ld s1, 16(sp)
|
||||
ld s2, 24(sp)
|
||||
ld s3, 32(sp)
|
||||
ld s4, 40(sp)
|
||||
ld s5, 48(sp)
|
||||
ld s6, 56(sp)
|
||||
ld s7, 64(sp)
|
||||
ld s8, 72(sp)
|
||||
ld s9, 80(sp)
|
||||
ld s10, 88(sp)
|
||||
ld s11, 96(sp)
|
||||
ld gp, 8(sp)
|
||||
ld tp, 16(sp)
|
||||
ld s0, 24(sp)
|
||||
ld s1, 32(sp)
|
||||
ld s2, 40(sp)
|
||||
ld s3, 48(sp)
|
||||
ld s4, 56(sp)
|
||||
ld s5, 64(sp)
|
||||
ld s6, 72(sp)
|
||||
ld s7, 80(sp)
|
||||
ld s8, 88(sp)
|
||||
ld s9, 96(sp)
|
||||
ld s10, 104(sp)
|
||||
ld s11, 112(sp)
|
||||
|
||||
addi sp, sp, 112
|
||||
addi sp, sp, 128
|
||||
ret
|
||||
|
||||
/*
|
||||
THE YIELD GUARD
|
||||
Protects Kernel GP during subject-to-kernel yield calls.
|
||||
*/
|
||||
.global rumpk_yield_guard
|
||||
.type rumpk_yield_guard, @function
|
||||
|
||||
rumpk_yield_guard:
|
||||
# 1. Save Subject State
|
||||
addi sp, sp, -16
|
||||
sd gp, 0(sp)
|
||||
sd ra, 8(sp)
|
||||
|
||||
# 2. Restore Kernel Global Pointer (Static Relocation)
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
# 3. Call Nim Internal Logic
|
||||
# (rumpk_yield_internal is a Nim cdecl proc)
|
||||
call rumpk_yield_internal
|
||||
|
||||
# 4. Restore Subject State
|
||||
ld gp, 0(sp)
|
||||
ld ra, 8(sp)
|
||||
addi sp, sp, 16
|
||||
ret
|
||||
|
|
|
|||
21
hal/uart.zig
21
hal/uart.zig
|
|
@ -59,6 +59,27 @@ pub fn write_bytes(bytes: []const u8) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_byte() ?u8 {
|
||||
switch (builtin.cpu.arch) {
|
||||
.aarch64 => {
|
||||
const dr: *volatile u32 = @ptrFromInt(PL011_BASE + PL011_DR);
|
||||
const fr: *volatile u32 = @ptrFromInt(PL011_BASE + PL011_FR);
|
||||
if ((fr.* & (1 << 4)) == 0) { // RXFE (Receive FIFO Empty) is bit 4, so if 0, it's NOT empty
|
||||
return @truncate(dr.*);
|
||||
}
|
||||
},
|
||||
.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.*;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn puts(s: []const u8) void {
|
||||
write_bytes(s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export fn virtio_net_send(data: [*]const u8, len: usize) void {
|
|||
}
|
||||
}
|
||||
|
||||
export fn virtio_net_init() void {
|
||||
export fn hal_io_init() void {
|
||||
if (VirtioNetDriver.probe()) |*driver| {
|
||||
var d = driver.*;
|
||||
if (d.init_device()) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,48 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Basic memory stubs (Very dangerous, just for canary)
|
||||
static uint8_t app_heap[64 * 1024];
|
||||
static size_t heap_ptr = 0;
|
||||
// Basic memory stubs
|
||||
extern void* malloc(size_t size);
|
||||
extern void free(void* ptr);
|
||||
|
||||
void* malloc(size_t size) {
|
||||
if (heap_ptr + size > sizeof(app_heap)) return NULL;
|
||||
void* p = &app_heap[heap_ptr];
|
||||
heap_ptr += (size + 7) & ~7; // Align 8
|
||||
// Forward declare memset (defined below)
|
||||
void* memset(void* s, int c, size_t n);
|
||||
|
||||
void* realloc(void* ptr, size_t size) {
|
||||
// naive realloc: alloc new, no copy (dangerous if used), return new
|
||||
// For Phase 8 we assume simple allocs.
|
||||
// If we want real realloc, we need copy.
|
||||
void* new_ptr = malloc(size);
|
||||
// copy? we don't know old size using standard malloc API without tracking.
|
||||
// ION slab is 2048.
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void* calloc(size_t nmemb, size_t size) {
|
||||
void* p = malloc(nmemb * size);
|
||||
if (p) memset(p, 0, nmemb * size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void free(void* ptr) { (void)ptr; }
|
||||
void* realloc(void* ptr, size_t size) { return malloc(size); }
|
||||
void* calloc(size_t nmemb, size_t size) { return malloc(nmemb * size); }
|
||||
// LwIP Panic Handler (for Membrane stack)
|
||||
extern void console_write(const void* p, size_t len);
|
||||
|
||||
void nexus_lwip_panic(const char* msg) {
|
||||
const char* prefix = "\n[LwIP/Membrane] ASSERT FAIL: ";
|
||||
console_write(prefix, 30);
|
||||
|
||||
// Print the message (assuming null-terminated)
|
||||
const char* p = msg;
|
||||
size_t len = 0;
|
||||
while (p[len]) len++;
|
||||
console_write(msg, len);
|
||||
|
||||
const char* suffix = "\n";
|
||||
console_write(suffix, 1);
|
||||
|
||||
// Halt
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
// String stubs
|
||||
size_t strlen(const char* s) {
|
||||
|
|
|
|||
|
|
@ -2,21 +2,20 @@ import ../../core/ion/memory
|
|||
import ../../core/ring
|
||||
|
||||
# Fixed address for the SysTable (provided by Carrier)
|
||||
const SYS_TABLE_ADDR = 0x801FFF00'u64
|
||||
const SYS_TABLE_ADDR = 0x83000000'u64
|
||||
|
||||
type
|
||||
SysTable = object
|
||||
s_yield*: pointer
|
||||
s_alloc*: proc(): IonPacket {.cdecl.}
|
||||
s_free*: proc(pkt: IonPacket) {.cdecl.}
|
||||
s_tx*: proc(pkt: IonPacket): bool {.cdecl.}
|
||||
magic*: uint32
|
||||
s_rx*: pointer
|
||||
s_tx*: pointer
|
||||
s_event*: pointer
|
||||
|
||||
# The Ring where the Kernel (Switch) pushes packets for this app
|
||||
var membrane_rx_ring_static: RingBuffer[IonPacket, 256]
|
||||
var membrane_rx_ring_ptr*: ptr RingBuffer[IonPacket, 256]
|
||||
|
||||
proc ion_user_init*() =
|
||||
proc ion_user_init*() {.exportc.} =
|
||||
when defined(is_membrane):
|
||||
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
||||
membrane_rx_ring_ptr = cast[ptr RingBuffer[IonPacket, 256]](sys.s_rx)
|
||||
|
|
@ -24,14 +23,11 @@ proc ion_user_init*() =
|
|||
membrane_rx_ring_static.init()
|
||||
membrane_rx_ring_ptr = addr membrane_rx_ring_static
|
||||
|
||||
proc ion_user_alloc*(out_pkt: ptr IonPacket): bool =
|
||||
proc ion_user_alloc*(out_pkt: ptr IonPacket): bool {.exportc.} =
|
||||
## Allocate a slab for the application to write into.
|
||||
when defined(is_membrane):
|
||||
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
||||
let pkt = sys.s_alloc()
|
||||
if pkt.data == nil: return false
|
||||
out_pkt[] = pkt
|
||||
return true
|
||||
# TODO: Implement allocation via Command Ring or shared pool
|
||||
return false
|
||||
else:
|
||||
var pkt = ion_alloc()
|
||||
if pkt.data == nil:
|
||||
|
|
@ -39,23 +35,24 @@ proc ion_user_alloc*(out_pkt: ptr IonPacket): bool =
|
|||
out_pkt[] = pkt
|
||||
return true
|
||||
|
||||
proc ion_user_free*(pkt: IonPacket) =
|
||||
proc ion_user_free*(pkt: IonPacket) {.exportc.} =
|
||||
## Return a slab to the pool.
|
||||
when defined(is_membrane):
|
||||
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
||||
sys.s_free(pkt)
|
||||
# TODO: Implement free via Command Ring
|
||||
discard
|
||||
else:
|
||||
ion_free(pkt)
|
||||
|
||||
proc ion_user_tx*(pkt: IonPacket): bool =
|
||||
proc ion_user_tx*(pkt: IonPacket): bool {.exportc.} =
|
||||
## Push a packet to the Transmission Ring.
|
||||
when defined(is_membrane):
|
||||
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
||||
return sys.s_tx(pkt)
|
||||
let tx = cast[ptr RingBuffer[IonPacket, 256]](sys.s_tx)
|
||||
return tx[].push(pkt)
|
||||
else:
|
||||
return ion_tx_push(pkt)
|
||||
|
||||
proc ion_user_rx*(out_pkt: ptr IonPacket): bool =
|
||||
proc ion_user_rx*(out_pkt: ptr IonPacket): bool {.exportc.} =
|
||||
## Pop a packet from the Application's RX Ring.
|
||||
if membrane_rx_ring_ptr == nil: return false
|
||||
if membrane_rx_ring_ptr[].isEmpty: return false
|
||||
|
|
|
|||
|
|
@ -1,7 +1,44 @@
|
|||
import socket
|
||||
import ../../core/ion/memory
|
||||
import ion_client
|
||||
|
||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
|
||||
# --- Heap Allocator (Slab Backed) ---
|
||||
const HEADER_SIZE = 32
|
||||
|
||||
proc malloc*(size: csize_t): pointer {.exportc, cdecl.} =
|
||||
if size > (2048 - HEADER_SIZE): return nil
|
||||
|
||||
var pkt: IonPacket
|
||||
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
|
||||
SockAddrIn = object
|
||||
|
|
|
|||
|
|
@ -206,3 +206,14 @@ proc glue_connect*(sock: ptr NexusSock; ip: ptr IpAddr; port: uint16): int =
|
|||
sock.state = SYN_SENT
|
||||
return 0
|
||||
return -1
|
||||
|
||||
# The Yield Mechanism (Cooperative Multitasking)
|
||||
proc fiber_yield*() {.exportc, cdecl.} =
|
||||
## Yield control back to the Kernel's networking fiber.
|
||||
## This allows VirtIO polling and packet processing to occur.
|
||||
when defined(is_membrane):
|
||||
# Use the Kernel-provided yield function pointer
|
||||
type YieldFunc = proc() {.cdecl.}
|
||||
let yield_ptr = cast[YieldFunc](0x83000FF0'u64)
|
||||
if yield_ptr != nil:
|
||||
yield_ptr()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ var socket_table: array[MAX_SOCKETS, ptr NexusSock]
|
|||
|
||||
proc new_socket*(): int =
|
||||
## Allocate a new NexusSocket and return a fake FD.
|
||||
for i in 0 ..< MAX_SOCKETS:
|
||||
## Reserve FDs 0, 1, 2 for stdio compatibility.
|
||||
for i in 3 ..< MAX_SOCKETS:
|
||||
if socket_table[i] == nil:
|
||||
var s = create(NexusSock)
|
||||
s.fd = i
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
#include "lwip/opt.h"
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
// External references to console
|
||||
extern void console_write(const void* p, unsigned long len);
|
||||
|
||||
// Simple counter for monotonic time
|
||||
static volatile u32_t lwip_ticks_ms = 0;
|
||||
|
||||
// 1. Initialization (Membrane version - minimal)
|
||||
void sys_init(void) {
|
||||
// Silent init for Membrane
|
||||
}
|
||||
|
||||
// 2. The Time Source
|
||||
u32_t sys_now(void) {
|
||||
lwip_ticks_ms++;
|
||||
return lwip_ticks_ms;
|
||||
}
|
||||
|
||||
// 3. Panic handler is in clib.c (nexus_lwip_panic)
|
||||
|
||||
// 4. Critical Sections (Stubbed)
|
||||
#if SYS_LIGHTWEIGHT_PROT
|
||||
sys_prot_t sys_arch_protect(void) { return 0; }
|
||||
void sys_arch_unprotect(sys_prot_t pval) { (void)pval; }
|
||||
#endif
|
||||
|
|
@ -60,13 +60,13 @@ export fn main() c_int {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// 1. Send CMD_NET_STOP (Poison)
|
||||
print("[SABOTEUR] Injecting POISON (CMD_NET_STOP)...\n");
|
||||
// 1. Send CMD_ION_STOP (Poison)
|
||||
print("[SABOTEUR] Injecting POISON (CMD_ION_STOP)...\n");
|
||||
{
|
||||
const cmd_ring = sys.s_cmd;
|
||||
const head = @atomicLoad(u32, &cmd_ring.head, .monotonic);
|
||||
|
||||
// CMD_NET_STOP = 1
|
||||
// CMD_ION_STOP = 1
|
||||
const pkt = CmdPacket{ .kind = 1, .arg = 0 };
|
||||
|
||||
cmd_ring.data[head & cmd_ring.mask] = pkt;
|
||||
|
|
@ -74,7 +74,7 @@ export fn main() c_int {
|
|||
print("[SABOTEUR] POISON injected.\n");
|
||||
}
|
||||
|
||||
print("[SABOTEUR] Network poisoned. Entering infinite loop to block CPU.\n");
|
||||
print("[SABOTEUR] IO poisoned. Entering infinite loop to block CPU.\n");
|
||||
print("[SABOTEUR] (This simulates a stuck NPL preventing yields)\n");
|
||||
|
||||
// 2. Hang
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
const std = @import("std");
|
||||
|
||||
// NEXUS IMMUNE SYSTEM (NPL) - THE VOICE & COMMAND PLANE
|
||||
// Markus Maiwald (Architect) | Voxis Forge (AI)
|
||||
|
||||
const ION_BASE = 0x83000000;
|
||||
|
||||
const IonPacket = extern struct {
|
||||
data: u64,
|
||||
phys: u64,
|
||||
len: u16,
|
||||
id: u16,
|
||||
};
|
||||
|
||||
const CmdPacket = extern struct {
|
||||
kind: u32,
|
||||
arg: u32,
|
||||
};
|
||||
|
||||
fn RingBuffer(comptime T: type) type {
|
||||
return extern struct {
|
||||
head: u32,
|
||||
tail: u32,
|
||||
mask: u32,
|
||||
data: [256]T,
|
||||
};
|
||||
}
|
||||
|
||||
const SysTable = extern struct {
|
||||
magic: u32,
|
||||
s_rx: *RingBuffer(IonPacket),
|
||||
s_tx: *RingBuffer(IonPacket),
|
||||
s_event: *RingBuffer(IonPacket),
|
||||
s_cmd: *RingBuffer(CmdPacket),
|
||||
};
|
||||
|
||||
const CMD_ION_STOP = 1;
|
||||
const CMD_ION_START = 2;
|
||||
|
||||
// The Main Loop for the NexShell Fiber
|
||||
export fn nexshell_main() void {
|
||||
const sys = @as(*SysTable, @ptrFromInt(ION_BASE));
|
||||
|
||||
print("\n╔═══════════════════════════════════════╗\n");
|
||||
print("║ NEXSHELL IMMUNE SYSTEM ACTIVE ║\n");
|
||||
print("║ Command Plane: READY ║\n");
|
||||
print("╚═══════════════════════════════════════╝\n");
|
||||
|
||||
const event_ring = sys.s_event;
|
||||
const cmd_ring = sys.s_cmd;
|
||||
|
||||
var input_buffer: [64]u8 = undefined;
|
||||
var input_idx: usize = 0;
|
||||
|
||||
while (true) {
|
||||
// 1. Process Telemetry Events
|
||||
const head = @atomicLoad(u32, &event_ring.head, .acquire);
|
||||
const tail = @atomicLoad(u32, &event_ring.tail, .monotonic);
|
||||
|
||||
if (head != tail) {
|
||||
const pkt = event_ring.data[tail & event_ring.mask];
|
||||
print("\n[NexShell] ALERT | EventID: ");
|
||||
if (pkt.id == 777) {
|
||||
print("777 (SECURITY_HEARTBEAT)\n");
|
||||
} else {
|
||||
print("GENERIC\n");
|
||||
}
|
||||
@atomicStore(u32, &event_ring.tail, tail + 1, .release);
|
||||
}
|
||||
|
||||
// 2. Process User Input (Non-blocking)
|
||||
const c = console_read();
|
||||
if (c != -1) {
|
||||
const byte = @as(u8, @intCast(c));
|
||||
if (byte == '\r' or byte == '\n') {
|
||||
print("\n");
|
||||
process_command(input_buffer[0..input_idx], cmd_ring);
|
||||
input_idx = 0;
|
||||
} else if (byte == 0x7F or byte == 0x08) {
|
||||
if (input_idx > 0) {
|
||||
input_idx -= 1;
|
||||
print("\x08 \x08"); // Backspace
|
||||
}
|
||||
} else if (input_idx < 63) {
|
||||
input_buffer[input_idx] = byte;
|
||||
input_idx += 1;
|
||||
const bs = [1]u8{byte};
|
||||
print(&bs);
|
||||
}
|
||||
}
|
||||
|
||||
fiber_yield();
|
||||
}
|
||||
}
|
||||
|
||||
fn process_command(cmd_text: []const u8, cmd_ring: *RingBuffer(CmdPacket)) void {
|
||||
if (std.mem.eql(u8, cmd_text, "io stop") or std.mem.eql(u8, cmd_text, "ion stop")) {
|
||||
print("[NexShell] Pushing CMD_ION_STOP...\n");
|
||||
push_cmd(cmd_ring, CMD_ION_STOP, 0);
|
||||
} else if (std.mem.eql(u8, cmd_text, "io start") or std.mem.eql(u8, cmd_text, "ion start")) {
|
||||
print("[NexShell] Pushing CMD_ION_START...\n");
|
||||
push_cmd(cmd_ring, CMD_ION_START, 0);
|
||||
} else if (cmd_text.len > 0) {
|
||||
print("[NexShell] Unknown Command: ");
|
||||
print(cmd_text);
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn push_cmd(ring: *RingBuffer(CmdPacket), kind: u32, arg: u32) void {
|
||||
const head = @atomicLoad(u32, &ring.head, .acquire);
|
||||
const tail = @atomicLoad(u32, &ring.tail, .monotonic);
|
||||
|
||||
const next = (head + 1) & ring.mask;
|
||||
if (next == tail) {
|
||||
print("[NexShell] CMD RING FULL!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ring.data[head & ring.mask] = .{ .kind = kind, .arg = arg };
|
||||
@atomicStore(u32, &ring.head, next, .release);
|
||||
}
|
||||
|
||||
// OS Shims
|
||||
extern fn write(fd: c_int, buf: [*]const u8, count: usize) isize;
|
||||
extern fn console_read() c_int;
|
||||
extern fn fiber_yield() void;
|
||||
|
||||
fn print(text: []const u8) void {
|
||||
_ = write(1, text.ptr, text.len);
|
||||
}
|
||||
Loading…
Reference in New Issue