From b3d9c2a49d15fdde1e0ca09499e34897d71ca9ab Mon Sep 17 00:00:00 2001 From: Markus Maiwald Date: Tue, 30 Dec 2025 21:45:00 +0100 Subject: [PATCH] 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. --- apps/subject_rust/Cargo.lock | 7 + apps/subject_rust/Cargo.toml | 16 ++ apps/subject_rust/src/lib.rs | 105 ++++++++ apps/subject_rust/target/.rustc_info.json | 1 + apps/subject_rust/target/CACHEDIR.TAG | 3 + apps/subject_rust/target/release/.cargo-lock | 0 .../riscv64gc-unknown-linux-gnu/CACHEDIR.TAG | 3 + .../release/.cargo-lock | 0 .../invoked.timestamp | 1 + .../output-lib-subject_rust | 3 + .../riscv64gc-unknown-none-elf/CACHEDIR.TAG | 3 + .../release/.cargo-lock | 0 .../invoked.timestamp | 1 + .../output-bin-subject_rust | 3 + .../invoked.timestamp | 1 + .../output-lib-subject_rust | 3 + apps/subject_zig/main.zig | 126 ++++++++++ build.sh | 6 +- core/README.md | 8 +- core/bus.nim | 31 --- core/channel.nim | 2 +- core/crypto.nim | 39 --- core/cstubs.c | 8 +- core/ion.nim | 4 +- core/ion/ion_switch.nim | 121 ---------- core/ion/memory.nim | 10 +- core/kernel.nim | 46 ++-- core/net.nim | 225 ------------------ core/net/arch/cc.h | 39 --- core/net/arch/perf.h | 5 - core/net/lwipopts.h | 38 --- core/npl.nim | 123 ---------- core/watchdog.nim | 13 +- hal/abi.zig | 2 +- hal/arch/riscv64/linker.ld | 2 + hal/arch/riscv64/switch.S | 99 +++++--- hal/uart.zig | 21 ++ hal/virtio_net.zig | 2 +- libs/membrane/clib.c | 48 +++- {core => libs/membrane}/include/arch/cc.h | 0 {core => libs/membrane}/include/arch/perf.h | 0 .../membrane}/include/arch/sys_arch.h | 0 libs/membrane/ion_client.nim | 33 ++- libs/membrane/libc.nim | 37 +++ libs/membrane/net_glue.nim | 11 + libs/membrane/socket.nim | 3 +- libs/membrane/sys_arch.c | 28 +++ npl/saboteur.zig | 8 +- src/npl/system/nexshell.zig | 131 ++++++++++ 49 files changed, 677 insertions(+), 742 deletions(-) create mode 100644 apps/subject_rust/Cargo.lock create mode 100644 apps/subject_rust/Cargo.toml create mode 100644 apps/subject_rust/src/lib.rs create mode 100644 apps/subject_rust/target/.rustc_info.json create mode 100644 apps/subject_rust/target/CACHEDIR.TAG create mode 100644 apps/subject_rust/target/release/.cargo-lock create mode 100644 apps/subject_rust/target/riscv64gc-unknown-linux-gnu/CACHEDIR.TAG create mode 100644 apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.cargo-lock create mode 100644 apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/invoked.timestamp create mode 100644 apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/output-lib-subject_rust create mode 100644 apps/subject_rust/target/riscv64gc-unknown-none-elf/CACHEDIR.TAG create mode 100644 apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.cargo-lock create mode 100644 apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/invoked.timestamp create mode 100644 apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/output-bin-subject_rust create mode 100644 apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/invoked.timestamp create mode 100644 apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/output-lib-subject_rust create mode 100644 apps/subject_zig/main.zig delete mode 100644 core/bus.nim delete mode 100644 core/crypto.nim delete mode 100644 core/ion/ion_switch.nim delete mode 100644 core/net.nim delete mode 100644 core/net/arch/cc.h delete mode 100644 core/net/arch/perf.h delete mode 100644 core/net/lwipopts.h delete mode 100644 core/npl.nim rename {core => libs/membrane}/include/arch/cc.h (100%) rename {core => libs/membrane}/include/arch/perf.h (100%) rename {core => libs/membrane}/include/arch/sys_arch.h (100%) create mode 100644 libs/membrane/sys_arch.c create mode 100644 src/npl/system/nexshell.zig diff --git a/apps/subject_rust/Cargo.lock b/apps/subject_rust/Cargo.lock new file mode 100644 index 0000000..9db585f --- /dev/null +++ b/apps/subject_rust/Cargo.lock @@ -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" diff --git a/apps/subject_rust/Cargo.toml b/apps/subject_rust/Cargo.toml new file mode 100644 index 0000000..542a6e4 --- /dev/null +++ b/apps/subject_rust/Cargo.toml @@ -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" diff --git a/apps/subject_rust/src/lib.rs b/apps/subject_rust/src/lib.rs new file mode 100644 index 0000000..dbda48e --- /dev/null +++ b/apps/subject_rust/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); } } +} diff --git a/apps/subject_rust/target/.rustc_info.json b/apps/subject_rust/target/.rustc_info.json new file mode 100644 index 0000000..dd91d09 --- /dev/null +++ b/apps/subject_rust/target/.rustc_info.json @@ -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":{}} \ No newline at end of file diff --git a/apps/subject_rust/target/CACHEDIR.TAG b/apps/subject_rust/target/CACHEDIR.TAG new file mode 100644 index 0000000..20d7c31 --- /dev/null +++ b/apps/subject_rust/target/CACHEDIR.TAG @@ -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/ diff --git a/apps/subject_rust/target/release/.cargo-lock b/apps/subject_rust/target/release/.cargo-lock new file mode 100644 index 0000000..e69de29 diff --git a/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/CACHEDIR.TAG b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/CACHEDIR.TAG new file mode 100644 index 0000000..20d7c31 --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/CACHEDIR.TAG @@ -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/ diff --git a/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.cargo-lock b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.cargo-lock new file mode 100644 index 0000000..e69de29 diff --git a/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/invoked.timestamp b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/invoked.timestamp new file mode 100644 index 0000000..e00328d --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/invoked.timestamp @@ -0,0 +1 @@ +This file has an mtime of when this was started. \ No newline at end of file diff --git a/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/output-lib-subject_rust b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/output-lib-subject_rust new file mode 100644 index 0000000..d7cd0dc --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-linux-gnu/release/.fingerprint/subject_rust-ccc850a177bfb478/output-lib-subject_rust @@ -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"} diff --git a/apps/subject_rust/target/riscv64gc-unknown-none-elf/CACHEDIR.TAG b/apps/subject_rust/target/riscv64gc-unknown-none-elf/CACHEDIR.TAG new file mode 100644 index 0000000..20d7c31 --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-none-elf/CACHEDIR.TAG @@ -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/ diff --git a/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.cargo-lock b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.cargo-lock new file mode 100644 index 0000000..e69de29 diff --git a/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/invoked.timestamp b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/invoked.timestamp new file mode 100644 index 0000000..e00328d --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/invoked.timestamp @@ -0,0 +1 @@ +This file has an mtime of when this was started. \ No newline at end of file diff --git a/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/output-bin-subject_rust b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/output-bin-subject_rust new file mode 100644 index 0000000..4a8c5d1 --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-4df52201e6d012e6/output-bin-subject_rust @@ -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"} diff --git a/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/invoked.timestamp b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/invoked.timestamp new file mode 100644 index 0000000..e00328d --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/invoked.timestamp @@ -0,0 +1 @@ +This file has an mtime of when this was started. \ No newline at end of file diff --git a/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/output-lib-subject_rust b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/output-lib-subject_rust new file mode 100644 index 0000000..4a8c5d1 --- /dev/null +++ b/apps/subject_rust/target/riscv64gc-unknown-none-elf/release/.fingerprint/subject_rust-aca8265dce184b0e/output-lib-subject_rust @@ -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"} diff --git a/apps/subject_zig/main.zig b/apps/subject_zig/main.zig new file mode 100644 index 0000000..dccf56d --- /dev/null +++ b/apps/subject_zig/main.zig @@ -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) {} +} diff --git a/build.sh b/build.sh index 05ae269..cb75768 100755 --- a/build.sh +++ b/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" \ diff --git a/core/README.md b/core/README.md index eb4b761..c6c1f5a 100644 --- a/core/README.md +++ b/core/README.md @@ -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 diff --git a/core/bus.nim b/core/bus.nim deleted file mode 100644 index 2c0cc7d..0000000 --- a/core/bus.nim +++ /dev/null @@ -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.. 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) diff --git a/core/ion/memory.nim b/core/ion/memory.nim index 9c60a14..ca55da7 100644 --- a/core/ion/memory.nim +++ b/core/ion/memory.nim @@ -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. diff --git a/core/kernel.nim b/core/kernel.nim index b0a5070..c3086b3 100644 --- a/core/kernel.nim +++ b/core/kernel.nim @@ -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.} diff --git a/core/net.nim b/core/net.nim deleted file mode 100644 index e162fc8..0000000 --- a/core/net.nim +++ /dev/null @@ -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() diff --git a/core/net/arch/cc.h b/core/net/arch/cc.h deleted file mode 100644 index e1d0ecd..0000000 --- a/core/net/arch/cc.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef LWIP_HDR_CC_H -#define LWIP_HDR_CC_H - -#include -#include - -// 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 diff --git a/core/net/arch/perf.h b/core/net/arch/perf.h deleted file mode 100644 index 4b5c545..0000000 --- a/core/net/arch/perf.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef LWIP_HDR_PERF_H -#define LWIP_HDR_PERF_H -#define LWIP_PERF_START -#define LWIP_PERF_STOP(x) -#endif diff --git a/core/net/lwipopts.h b/core/net/lwipopts.h deleted file mode 100644 index d7e1c9d..0000000 --- a/core/net/lwipopts.h +++ /dev/null @@ -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 diff --git a/core/npl.nim b/core/npl.nim deleted file mode 100644 index 56b31ea..0000000 --- a/core/npl.nim +++ /dev/null @@ -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.} diff --git a/core/watchdog.nim b/core/watchdog.nim index da53d63..bcf5da3 100644 --- a/core/watchdog.nim +++ b/core/watchdog.nim @@ -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! diff --git a/hal/abi.zig b/hal/abi.zig index cbde89b..69fdea3 100644 --- a/hal/abi.zig +++ b/hal/abi.zig @@ -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 diff --git a/hal/arch/riscv64/linker.ld b/hal/arch/riscv64/linker.ld index 75cb46c..3d62a81 100644 --- a/hal/arch/riscv64/linker.ld +++ b/hal/arch/riscv64/linker.ld @@ -14,6 +14,8 @@ SECTIONS } .data : { + . = ALIGN(8); + PROVIDE(__global_pointer$ = . + 0x800); *(.data .data.*) *(.sdata .sdata.*) } diff --git a/hal/arch/riscv64/switch.S b/hal/arch/riscv64/switch.S index dc46122..2a5c424 100644 --- a/hal/arch/riscv64/switch.S +++ b/hal/arch/riscv64/switch.S @@ -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 diff --git a/hal/uart.zig b/hal/uart.zig index 75aed49..605980f 100644 --- a/hal/uart.zig +++ b/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); } diff --git a/hal/virtio_net.zig b/hal/virtio_net.zig index 3f2d0ce..18b71ab 100644 --- a/hal/virtio_net.zig +++ b/hal/virtio_net.zig @@ -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()) { diff --git a/libs/membrane/clib.c b/libs/membrane/clib.c index 098ee38..79dd788 100644 --- a/libs/membrane/clib.c +++ b/libs/membrane/clib.c @@ -1,20 +1,48 @@ #include #include -// 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) { diff --git a/core/include/arch/cc.h b/libs/membrane/include/arch/cc.h similarity index 100% rename from core/include/arch/cc.h rename to libs/membrane/include/arch/cc.h diff --git a/core/include/arch/perf.h b/libs/membrane/include/arch/perf.h similarity index 100% rename from core/include/arch/perf.h rename to libs/membrane/include/arch/perf.h diff --git a/core/include/arch/sys_arch.h b/libs/membrane/include/arch/sys_arch.h similarity index 100% rename from core/include/arch/sys_arch.h rename to libs/membrane/include/arch/sys_arch.h diff --git a/libs/membrane/ion_client.nim b/libs/membrane/ion_client.nim index 407e086..9f10caf 100644 --- a/libs/membrane/ion_client.nim +++ b/libs/membrane/ion_client.nim @@ -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 diff --git a/libs/membrane/libc.nim b/libs/membrane/libc.nim index 792241d..726b683 100644 --- a/libs/membrane/libc.nim +++ b/libs/membrane/libc.nim @@ -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 diff --git a/libs/membrane/net_glue.nim b/libs/membrane/net_glue.nim index 314d51e..c34fbad 100644 --- a/libs/membrane/net_glue.nim +++ b/libs/membrane/net_glue.nim @@ -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() diff --git a/libs/membrane/socket.nim b/libs/membrane/socket.nim index c993644..3f11b7e 100644 --- a/libs/membrane/socket.nim +++ b/libs/membrane/socket.nim @@ -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 diff --git a/libs/membrane/sys_arch.c b/libs/membrane/sys_arch.c new file mode 100644 index 0000000..57d5acb --- /dev/null +++ b/libs/membrane/sys_arch.c @@ -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 diff --git a/npl/saboteur.zig b/npl/saboteur.zig index 1e2e1a4..ecb4d6c 100644 --- a/npl/saboteur.zig +++ b/npl/saboteur.zig @@ -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 diff --git a/src/npl/system/nexshell.zig b/src/npl/system/nexshell.zig new file mode 100644 index 0000000..ad2defd --- /dev/null +++ b/src/npl/system/nexshell.zig @@ -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); +}