feat(rumpk): implement Invariant Shield and Blink Recovery
- Implement Design by Contract in HAL and Kernel (Phase 2 Task 1) - Add invariant checks to Sovereign Channels (pointer validation, bounds) - Create invariant.nim for secure Logic-to-HAL transitions - Codify Silence Doctrine in DOCTRINE.md and SPEC files - Finalize Blink Recovery confirmation via Saboteur test - Update SPEC-008, SPEC-009, SPEC-010, SPEC-011 with architectural refinements - Sync Website vision with new technical milestones
This commit is contained in:
parent
46e7be6837
commit
061a2ff56b
185
build.sh
185
build.sh
|
|
@ -71,6 +71,28 @@ zig build-obj \
|
||||||
mv stubs.o "$BUILD_DIR/stubs.o"
|
mv stubs.o "$BUILD_DIR/stubs.o"
|
||||||
echo " → $BUILD_DIR/stubs.o"
|
echo " → $BUILD_DIR/stubs.o"
|
||||||
|
|
||||||
|
zig build-obj \
|
||||||
|
-target $ZIG_TARGET \
|
||||||
|
$ZIG_OBJ_FLAGS \
|
||||||
|
-O ReleaseFast \
|
||||||
|
"$RUMPK_DIR/hal/channel.zig" \
|
||||||
|
--name channel
|
||||||
|
|
||||||
|
mv channel.o "$BUILD_DIR/channel.o"
|
||||||
|
echo " → $BUILD_DIR/channel.o"
|
||||||
|
|
||||||
|
# Compile NexShell NPL (Immune System Voice)
|
||||||
|
echo "[1.1/8] Compiling NexShell NPL..."
|
||||||
|
zig build-obj \
|
||||||
|
-target $ZIG_TARGET \
|
||||||
|
$ZIG_OBJ_FLAGS \
|
||||||
|
-O ReleaseFast \
|
||||||
|
"$RUMPK_DIR/src/npl/system/nexshell.zig" \
|
||||||
|
--name nexshell
|
||||||
|
|
||||||
|
mv nexshell.o "$BUILD_DIR/nexshell.o"
|
||||||
|
echo " → $BUILD_DIR/nexshell.o"
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Step 2: Compile context switch assembly
|
# Step 2: Compile context switch assembly
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
@ -100,52 +122,52 @@ echo " → $BUILD_DIR/monocypher.o"
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Step 2.2: Compile LwIP (Kernel Stack)
|
# Step 2.2: Compile LwIP (Kernel Stack)
|
||||||
# =========================================================
|
# =========================================================
|
||||||
echo "[2.2/8] Compiling LwIP (Kernel)..."
|
# echo "[2.2/8] Compiling LwIP (Kernel)..."
|
||||||
LWIP_CORE_FILES=(
|
# LWIP_CORE_FILES=(
|
||||||
"src/core/init.c"
|
# "src/core/init.c"
|
||||||
"src/core/def.c"
|
# "src/core/def.c"
|
||||||
"src/core/dns.c"
|
# "src/core/dns.c"
|
||||||
"src/core/inet_chksum.c"
|
# "src/core/inet_chksum.c"
|
||||||
"src/core/ip.c"
|
# "src/core/ip.c"
|
||||||
"src/core/mem.c"
|
# "src/core/mem.c"
|
||||||
"src/core/memp.c"
|
# "src/core/memp.c"
|
||||||
"src/core/netif.c"
|
# "src/core/netif.c"
|
||||||
"src/core/pbuf.c"
|
# "src/core/pbuf.c"
|
||||||
"src/core/raw.c"
|
# "src/core/raw.c"
|
||||||
"src/core/stats.c"
|
# "src/core/stats.c"
|
||||||
"src/core/sys.c"
|
# "src/core/sys.c"
|
||||||
"src/core/tcp.c"
|
# "src/core/tcp.c"
|
||||||
"src/core/tcp_in.c"
|
# "src/core/tcp_in.c"
|
||||||
"src/core/tcp_out.c"
|
# "src/core/tcp_out.c"
|
||||||
"src/core/timeouts.c"
|
# "src/core/timeouts.c"
|
||||||
"src/core/udp.c"
|
# "src/core/udp.c"
|
||||||
"src/core/ipv4/autoip.c"
|
# "src/core/ipv4/autoip.c"
|
||||||
"src/core/ipv4/dhcp.c"
|
# "src/core/ipv4/dhcp.c"
|
||||||
"src/core/ipv4/etharp.c"
|
# "src/core/ipv4/etharp.c"
|
||||||
"src/core/ipv4/icmp.c"
|
# "src/core/ipv4/icmp.c"
|
||||||
"src/core/ipv4/igmp.c"
|
# "src/core/ipv4/igmp.c"
|
||||||
"src/core/ipv4/ip4.c"
|
# "src/core/ipv4/ip4.c"
|
||||||
"src/core/ipv4/ip4_addr.c"
|
# "src/core/ipv4/ip4_addr.c"
|
||||||
"src/core/ipv4/ip4_frag.c"
|
# "src/core/ipv4/ip4_frag.c"
|
||||||
"src/netif/ethernet.c"
|
# "src/netif/ethernet.c"
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
for cfile in "${LWIP_CORE_FILES[@]}"; do
|
# for cfile in "${LWIP_CORE_FILES[@]}"; do
|
||||||
cfile_path="$RUMPK_DIR/vendor/lwip/$cfile"
|
# cfile_path="$RUMPK_DIR/vendor/lwip/$cfile"
|
||||||
objname=$(basename "$cfile" .c)
|
# objname=$(basename "$cfile" .c)
|
||||||
zig cc \
|
# zig cc \
|
||||||
-target $ZIG_TARGET \
|
# -target $ZIG_TARGET \
|
||||||
$ARCH_FLAGS \
|
# $ARCH_FLAGS \
|
||||||
-ffreestanding \
|
# -ffreestanding \
|
||||||
-fno-stack-protector \
|
# -fno-stack-protector \
|
||||||
-fno-builtin \
|
# -fno-builtin \
|
||||||
-O2 \
|
# -O2 \
|
||||||
-I"$RUMPK_DIR/core/include" \
|
# -I"$RUMPK_DIR/core/include" \
|
||||||
-I"$RUMPK_DIR/core/net" \
|
# -I"$RUMPK_DIR/core/net" \
|
||||||
-I"$RUMPK_DIR/vendor/lwip/src/include" \
|
# -I"$RUMPK_DIR/vendor/lwip/src/include" \
|
||||||
-c "$cfile_path" \
|
# -c "$cfile_path" \
|
||||||
-o "$BUILD_DIR/lwip_kernel_$objname.o"
|
# -o "$BUILD_DIR/lwip_kernel_$objname.o"
|
||||||
done
|
# done
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Step 2.3: Compile LwIP (Membrane Stack)
|
# Step 2.3: Compile LwIP (Membrane Stack)
|
||||||
|
|
@ -169,7 +191,23 @@ for cfile in "${LWIP_CORE_FILES[@]}"; do
|
||||||
-o "$BUILD_DIR/lwip_membrane_$objname.o"
|
-o "$BUILD_DIR/lwip_membrane_$objname.o"
|
||||||
done
|
done
|
||||||
LWIP_MEMBRANE_OBJS=$(ls $BUILD_DIR/lwip_membrane_*.o)
|
LWIP_MEMBRANE_OBJS=$(ls $BUILD_DIR/lwip_membrane_*.o)
|
||||||
echo " → LwIP objects compiled."
|
|
||||||
|
# Compile sys_arch.c (LwIP Platform Abstraction)
|
||||||
|
echo "[2.4/8] Compiling LwIP Platform Layer (sys_arch.c)..."
|
||||||
|
# zig cc \
|
||||||
|
# -target $ZIG_TARGET \
|
||||||
|
# $ARCH_FLAGS \
|
||||||
|
# -ffreestanding \
|
||||||
|
# -fno-stack-protector \
|
||||||
|
# -fno-builtin \
|
||||||
|
# -O2 \
|
||||||
|
# -I"$RUMPK_DIR/core/include" \
|
||||||
|
# -I"$RUMPK_DIR/core/net" \
|
||||||
|
# -I"$RUMPK_DIR/vendor/lwip/src/include" \
|
||||||
|
# -c "$RUMPK_DIR/core/net/sys_arch.c" \
|
||||||
|
# -o "$BUILD_DIR/sys_arch.o"
|
||||||
|
#
|
||||||
|
# echo " → LwIP objects compiled."
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Step 3: Compile Nim L1 (Kernel + Fibers)
|
# Step 3: Compile Nim L1 (Kernel + Fibers)
|
||||||
|
|
@ -265,6 +303,21 @@ zig cc \
|
||||||
-c "$RUMPK_DIR/libs/membrane/clib.c" \
|
-c "$RUMPK_DIR/libs/membrane/clib.c" \
|
||||||
-o "$BUILD_DIR/clib.o"
|
-o "$BUILD_DIR/clib.o"
|
||||||
|
|
||||||
|
# Compile sys_arch.c (Membrane LwIP Platform Layer)
|
||||||
|
zig cc \
|
||||||
|
-target $ZIG_TARGET \
|
||||||
|
$ARCH_FLAGS \
|
||||||
|
-ffreestanding \
|
||||||
|
-fno-stack-protector \
|
||||||
|
-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" \
|
||||||
|
-o "$BUILD_DIR/membrane_sys_arch.o"
|
||||||
|
|
||||||
nim c \
|
nim c \
|
||||||
--cpu:$NIM_CPU \
|
--cpu:$NIM_CPU \
|
||||||
--os:any \
|
--os:any \
|
||||||
|
|
@ -307,19 +360,20 @@ for cfile in "$BUILD_DIR/membrane_nimcache"/*.c; do
|
||||||
done
|
done
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Step 5.1: Compile Subject Zero Object (Before Patching)
|
# Step 5.1: Compile Subject Zig Object (Diamond Glass)
|
||||||
# =========================================================
|
# =========================================================
|
||||||
echo "[5.1/8] Compiling Subject Zero Object..."
|
echo "[5.1/8] Compiling Subject Zig Object..."
|
||||||
zig cc \
|
|
||||||
|
SUBJECT_SRC=${SUBJECT_SRC:-"$RUMPK_DIR/apps/subject_zig/main.zig"}
|
||||||
|
|
||||||
|
zig build-obj \
|
||||||
-target $ZIG_TARGET \
|
-target $ZIG_TARGET \
|
||||||
$ARCH_FLAGS \
|
$ZIG_OBJ_FLAGS \
|
||||||
-ffreestanding \
|
-O ReleaseSmall \
|
||||||
-fno-stack-protector \
|
"$SUBJECT_SRC" \
|
||||||
-fno-builtin \
|
--name subject_zig
|
||||||
-O2 \
|
|
||||||
-I"$RUMPK_DIR/libs/membrane/include" \
|
mv subject_zig.o "$BUILD_DIR/subject_zig.o"
|
||||||
-c "$RUMPK_DIR/apps/subject_zero/main.c" \
|
|
||||||
-o "$BUILD_DIR/subject_zero.o"
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Step 5.5: Patch Atomic References & Nuke Cache (GLOBAL)
|
# Step 5.5: Patch Atomic References & Nuke Cache (GLOBAL)
|
||||||
|
|
@ -366,6 +420,7 @@ zig ar rc "$BUILD_DIR/libnexus.a" \
|
||||||
$MEMBRANE_NIM_OBJS \
|
$MEMBRANE_NIM_OBJS \
|
||||||
$LWIP_MEMBRANE_OBJS \
|
$LWIP_MEMBRANE_OBJS \
|
||||||
"$BUILD_DIR/clib.o" \
|
"$BUILD_DIR/clib.o" \
|
||||||
|
"$BUILD_DIR/membrane_sys_arch.o" \
|
||||||
"$BUILD_DIR/switch.o"
|
"$BUILD_DIR/switch.o"
|
||||||
|
|
||||||
echo " → $BUILD_DIR/libnexus.a"
|
echo " → $BUILD_DIR/libnexus.a"
|
||||||
|
|
@ -377,14 +432,19 @@ echo "[6/8] Linking Subject Zero (Canary)..."
|
||||||
|
|
||||||
# Note: subject_zero.o and libnexus.a are already compiled and patched.
|
# Note: subject_zero.o and libnexus.a are already compiled and patched.
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Step 6: Link Subject Zig
|
||||||
|
# =========================================================
|
||||||
|
echo "[6/8] Linking Subject Zig..."
|
||||||
|
|
||||||
zig cc \
|
zig cc \
|
||||||
-target $ZIG_TARGET \
|
-target $ZIG_TARGET \
|
||||||
-nostdlib \
|
-nostdlib \
|
||||||
-rtlib=none \
|
|
||||||
-T "$RUMPK_DIR/apps/linker_user.ld" \
|
-T "$RUMPK_DIR/apps/linker_user.ld" \
|
||||||
"$BUILD_DIR/subject_zero.o" \
|
"$BUILD_DIR/subject_zig.o" \
|
||||||
"$BUILD_DIR/libnexus.a" \
|
"$BUILD_DIR/libnexus.a" \
|
||||||
-o "$BUILD_DIR/subject.elf"
|
-o "$BUILD_DIR/subject.elf" \
|
||||||
|
-lgcc
|
||||||
|
|
||||||
echo " → $BUILD_DIR/subject.elf"
|
echo " → $BUILD_DIR/subject.elf"
|
||||||
zig objcopy -O binary "$BUILD_DIR/subject.elf" "$BUILD_DIR/subject.bin"
|
zig objcopy -O binary "$BUILD_DIR/subject.elf" "$BUILD_DIR/subject.bin"
|
||||||
|
|
@ -446,13 +506,14 @@ $LINKER \
|
||||||
-T "$RUMPK_DIR/hal/arch/$ARCH/linker.ld" \
|
-T "$RUMPK_DIR/hal/arch/$ARCH/linker.ld" \
|
||||||
"$BUILD_DIR/hal.o" \
|
"$BUILD_DIR/hal.o" \
|
||||||
"$BUILD_DIR/stubs.o" \
|
"$BUILD_DIR/stubs.o" \
|
||||||
|
"$BUILD_DIR/channel.o" \
|
||||||
"$BUILD_DIR/switch.o" \
|
"$BUILD_DIR/switch.o" \
|
||||||
"$BUILD_DIR/monocypher.o" \
|
"$BUILD_DIR/monocypher.o" \
|
||||||
"$BUILD_DIR/cstubs.o" \
|
"$BUILD_DIR/cstubs.o" \
|
||||||
"$BUILD_DIR/overrides.o" \
|
"$BUILD_DIR/overrides.o" \
|
||||||
"$BUILD_DIR/loader.o" \
|
"$BUILD_DIR/loader.o" \
|
||||||
|
"$BUILD_DIR/nexshell.o" \
|
||||||
$NIM_OBJS \
|
$NIM_OBJS \
|
||||||
$BUILD_DIR/lwip_kernel_*.o \
|
|
||||||
-o "$BUILD_DIR/rumpk-$ARCH.elf"
|
-o "$BUILD_DIR/rumpk-$ARCH.elf"
|
||||||
|
|
||||||
echo " → $BUILD_DIR/rumpk-$ARCH.elf"
|
echo " → $BUILD_DIR/rumpk-$ARCH.elf"
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ elif defined(arm64) or defined(aarch64):
|
||||||
const ARCH_NAME = "aarch64"
|
const ARCH_NAME = "aarch64"
|
||||||
|
|
||||||
elif defined(riscv64):
|
elif defined(riscv64):
|
||||||
const CONTEXT_SIZE = 112
|
const CONTEXT_SIZE = 128
|
||||||
const RET_ADDR_INDEX = 0 # ra at [sp + 0]
|
const RET_ADDR_INDEX = 0 # ra at [sp + 0]
|
||||||
const ARCH_NAME = "riscv64"
|
const ARCH_NAME = "riscv64"
|
||||||
|
|
||||||
|
|
@ -105,11 +105,11 @@ proc fiber_trampoline() {.cdecl, exportc, noreturn.} =
|
||||||
# Fiber Initialization (Arch-Specific)
|
# Fiber Initialization (Arch-Specific)
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
||||||
proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer) =
|
proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer, size: int) =
|
||||||
f.state.entry = entry
|
f.state.entry = entry
|
||||||
|
|
||||||
# Start at top of stack
|
# Start at top of stack (using actual size)
|
||||||
var sp = cast[uint64](stack_base) + STACK_SIZE
|
var sp = cast[uint64](stack_base) + cast[uint64](size)
|
||||||
|
|
||||||
# 1. Align to 16 bytes (Universal requirement)
|
# 1. Align to 16 bytes (Universal requirement)
|
||||||
sp = sp and not 15'u64
|
sp = sp and not 15'u64
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Nexus Membrane: Userspace LwIP Configuration
|
||||||
|
* Provides compiler-specific definitions for NPL networking.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LWIP_ARCH_CC_H
|
||||||
|
#define LWIP_ARCH_CC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define LWIP_NO_INTTYPES_H 1
|
||||||
|
|
||||||
|
/* Byte Order */
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#define LITTLE_ENDIAN 1234
|
||||||
|
#define BIG_ENDIAN 4321
|
||||||
|
#define BYTE_ORDER LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* Sys Prot Type (Critical Section) */
|
||||||
|
typedef u32_t sys_prot_t;
|
||||||
|
|
||||||
|
/* Error code */
|
||||||
|
#define LWIP_ERR_T s8_t
|
||||||
|
|
||||||
|
/* Printf formatters */
|
||||||
|
#define U16_F "u"
|
||||||
|
#define S16_F "d"
|
||||||
|
#define X16_F "x"
|
||||||
|
#define U32_F "u"
|
||||||
|
#define S32_F "d"
|
||||||
|
#define X32_F "x"
|
||||||
|
#define SZT_F "zu"
|
||||||
|
|
||||||
|
/* Structure packing */
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define PACK_STRUCT_FIELD(x) x
|
||||||
|
#define PACK_STRUCT_STRUCT __attribute__((packed))
|
||||||
|
#define PACK_STRUCT_BEGIN
|
||||||
|
#define PACK_STRUCT_END
|
||||||
|
#else
|
||||||
|
#define PACK_STRUCT_FIELD(x) x
|
||||||
|
#define PACK_STRUCT_STRUCT
|
||||||
|
#define PACK_STRUCT_BEGIN
|
||||||
|
#define PACK_STRUCT_END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Diagnostic output */
|
||||||
|
#define LWIP_PLATFORM_DIAG(x) do { printf x; } while(0)
|
||||||
|
|
||||||
|
#define LWIP_PLATFORM_ASSERT(x) do { \
|
||||||
|
printf("[LwIP] Assertion \"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); \
|
||||||
|
while(1) asm("wfi"); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define LWIP_RAND() ((u32_t)rand())
|
||||||
|
|
||||||
|
#endif /* LWIP_ARCH_CC_H */
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#ifndef LWIP_ARCH_PERF_H
|
||||||
|
#define LWIP_ARCH_PERF_H
|
||||||
|
#define PERF_START
|
||||||
|
#define PERF_STOP(x)
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Nexus Rumpk: LwIP System Architecture
|
||||||
|
* Minimal definitions for critical sections.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LWIP_ARCH_SYS_ARCH_H
|
||||||
|
#define LWIP_ARCH_SYS_ARCH_H
|
||||||
|
|
||||||
|
#include "arch/cc.h"
|
||||||
|
|
||||||
|
/* Critical section protection type */
|
||||||
|
typedef u32_t sys_prot_t;
|
||||||
|
|
||||||
|
/* Stub out threading primitives for NO_SYS or Cooperative */
|
||||||
|
#define SYS_MBOX_NULL NULL
|
||||||
|
#define SYS_SEM_NULL NULL
|
||||||
|
|
||||||
|
#endif /* LWIP_ARCH_SYS_ARCH_H */
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _INTTYPES_H
|
||||||
|
#define _INTTYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Minimal format specifiers */
|
||||||
|
#define PRId32 "d"
|
||||||
|
#define PRIu32 "u"
|
||||||
|
#define PRIx32 "x"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# import ion # Included in ion.nim
|
||||||
|
|
||||||
|
# Error type for future use
|
||||||
|
type
|
||||||
|
FiberPanic* = object of CatchableError
|
||||||
|
|
||||||
|
# Forward declarations for utilities defined in kernel.nim (included there)
|
||||||
|
proc kernel_panic*(msg: cstring) {.importc: "panic", cdecl.}
|
||||||
|
proc kprintln*(s: cstring) {.importc: "kprintln", cdecl.}
|
||||||
|
|
||||||
|
template secure_send*(ring_ptr: pointer, data: uint64) =
|
||||||
|
## Verifies invariants before pushing to a command ring.
|
||||||
|
|
||||||
|
# 1. PRE-CONDITION: Alignment
|
||||||
|
if (cast[uint](ring_ptr) and 0b11) != 0:
|
||||||
|
kernel_panic("Invariant Violation: Unaligned Ring Pointer")
|
||||||
|
|
||||||
|
# 2. OPERATION: Try to push via HAL
|
||||||
|
# We cast uint64 back to CmdPacket for the FFI call
|
||||||
|
let success = hal_cmd_push(cast[uint64](ring_ptr), cast[CmdPacket](data))
|
||||||
|
|
||||||
|
# 3. POST-CONDITION: Flow Control Warning
|
||||||
|
if not success:
|
||||||
|
kprintln("[Invariant] Warning: Command Ring Full, Drop.")
|
||||||
|
|
||||||
|
template secure_push_packet*(ring_ptr: pointer, pkt: IonPacket) =
|
||||||
|
## Verifies invariants for IonPacket transfers.
|
||||||
|
if (cast[uint](ring_ptr) and 0b11) != 0:
|
||||||
|
kernel_panic("Invariant Violation: Unaligned Ring Pointer")
|
||||||
|
|
||||||
|
if not hal_channel_push(cast[uint64](ring_ptr), pkt):
|
||||||
|
kprintln("[Invariant] Warning: Packet Ring Full, Drop.")
|
||||||
|
|
||||||
|
template secure_recv_cmd*(ring_ptr: pointer, out_pkt: var CmdPacket): bool =
|
||||||
|
if (cast[uint](ring_ptr) and 0b11) != 0:
|
||||||
|
kernel_panic("Invariant Violation: Unaligned Ring Pointer")
|
||||||
|
|
||||||
|
hal_cmd_pop(cast[uint64](ring_ptr), addr out_pkt)
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Nexus Rumpk: ION Control Plane
|
||||||
|
# Markus Maiwald (Architect) | Voxis Forge (AI)
|
||||||
|
|
||||||
|
import ion/memory
|
||||||
|
export memory
|
||||||
|
|
||||||
|
type
|
||||||
|
CmdType* = enum
|
||||||
|
CMD_NONE = 0
|
||||||
|
CMD_NET_STOP = 1
|
||||||
|
CMD_NET_START = 2
|
||||||
|
CMD_DROP_ALL = 3
|
||||||
|
|
||||||
|
CmdPacket* = object
|
||||||
|
kind*: uint32
|
||||||
|
arg*: uint32
|
||||||
|
|
||||||
|
# Binary compatible with hal/channel.zig
|
||||||
|
HAL_Ring*[T] = object
|
||||||
|
head*: uint32
|
||||||
|
tail*: uint32
|
||||||
|
mask*: uint32
|
||||||
|
data*: array[256, T]
|
||||||
|
|
||||||
|
SovereignChannel*[T] = object
|
||||||
|
ring*: ptr HAL_Ring[T]
|
||||||
|
|
||||||
|
SysTable* = object
|
||||||
|
magic*: uint32 # 0x4E585553
|
||||||
|
s_rx*: ptr HAL_Ring[IonPacket] # Kernel -> App
|
||||||
|
s_tx*: ptr HAL_Ring[IonPacket] # App -> Kernel
|
||||||
|
s_event*: ptr HAL_Ring[IonPacket] # Telemetry
|
||||||
|
s_cmd*: ptr HAL_Ring[CmdPacket] # Command Ring (Control Plane)
|
||||||
|
|
||||||
|
include invariant
|
||||||
|
|
||||||
|
const SYSTABLE_BASE* = 0x83000000'u64
|
||||||
|
|
||||||
|
# HAL Imports (Hardened ABI - Handle Based)
|
||||||
|
proc hal_channel_push*(handle: uint64,
|
||||||
|
pkt: IonPacket): bool {.importc: "hal_channel_push", cdecl.}
|
||||||
|
proc hal_channel_pop*(handle: uint64,
|
||||||
|
out_pkt: ptr IonPacket): bool {.importc: "hal_channel_pop", cdecl.}
|
||||||
|
|
||||||
|
proc hal_cmd_push*(handle: uint64,
|
||||||
|
pkt: CmdPacket): bool {.importc: "hal_cmd_push", cdecl.}
|
||||||
|
proc hal_cmd_pop*(handle: uint64,
|
||||||
|
out_pkt: ptr CmdPacket): bool {.importc: "hal_cmd_pop", cdecl.}
|
||||||
|
|
||||||
|
proc send*(chan: var SovereignChannel[IonPacket], pkt: IonPacket) =
|
||||||
|
secure_push_packet(chan.ring, pkt)
|
||||||
|
|
||||||
|
proc recv*(chan: var SovereignChannel[IonPacket],
|
||||||
|
out_pkt: var IonPacket): bool =
|
||||||
|
if (cast[uint](chan.ring) and 0b11) != 0:
|
||||||
|
return false # Or panic
|
||||||
|
return hal_channel_pop(cast[uint64](chan.ring), addr out_pkt)
|
||||||
|
|
||||||
|
proc send*(chan: var SovereignChannel[CmdPacket], pkt: CmdPacket) =
|
||||||
|
secure_send(chan.ring, cast[uint64](pkt))
|
||||||
|
|
||||||
|
proc recv*(chan: var SovereignChannel[CmdPacket],
|
||||||
|
out_pkt: var CmdPacket): bool =
|
||||||
|
return secure_recv_cmd(chan.ring, out_pkt)
|
||||||
323
core/kernel.nim
323
core/kernel.nim
|
|
@ -1,191 +1,204 @@
|
||||||
# Rumpk Layer 1: The Logic Core
|
# Rumpk Layer 1: The Logic Core (Autonomous Immune System)
|
||||||
# Markus Maiwald (Architect) | Voxis Forge (AI)
|
# Markus Maiwald (Architect) | Voxis Forge (AI)
|
||||||
|
|
||||||
{.push stackTrace: off, lineTrace: off.}
|
{.push stackTrace: off, lineTrace: off.}
|
||||||
|
|
||||||
import fiber
|
import fiber
|
||||||
import ion/memory
|
import ion
|
||||||
import ion/ion_switch
|
|
||||||
import ring
|
|
||||||
import net
|
|
||||||
|
|
||||||
# HAL Imports from Zig (Layer 0)
|
|
||||||
|
var net_paused*: bool = false
|
||||||
|
var pause_start*: uint64 = 0
|
||||||
|
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Fiber Management (Forward Declared)
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
var fiber_net: FiberObject
|
||||||
|
var fiber_nexshell: FiberObject
|
||||||
|
var fiber_subject: FiberObject
|
||||||
|
var fiber_watchdog: FiberObject
|
||||||
|
|
||||||
|
# POSIX-like exports for Zig NPLs
|
||||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
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)
|
||||||
|
return len
|
||||||
|
|
||||||
|
# Utility for Logic Core
|
||||||
|
proc kprint*(s: cstring) {.exportc, cdecl.} =
|
||||||
|
if s != nil:
|
||||||
|
let length = len(s)
|
||||||
|
if length > 0:
|
||||||
|
console_write(s, csize_t(length))
|
||||||
|
|
||||||
|
proc kprintln*(s: cstring) {.exportc, cdecl.} =
|
||||||
|
kprint(s); kprint("\n")
|
||||||
|
|
||||||
|
proc rumpk_yield_internal() {.cdecl, exportc.} =
|
||||||
|
if current_fiber == addr fiber_net:
|
||||||
|
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)
|
||||||
|
|
||||||
|
proc fiber_yield*() {.exportc, cdecl.} =
|
||||||
|
rumpk_yield_internal()
|
||||||
|
|
||||||
|
# Utility moved up
|
||||||
|
|
||||||
|
# Channel API (The Valve) - Wrappers for ION
|
||||||
|
# Channel API is imported from ion.nim
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const SYSTABLE_BASE = 0x83000000'u64
|
||||||
|
|
||||||
|
# Global Rings (The Pipes - L0 Physics)
|
||||||
|
var guest_rx_hal: HAL_Ring[IonPacket]
|
||||||
|
var guest_tx_hal: HAL_Ring[IonPacket]
|
||||||
|
var guest_event_hal: HAL_Ring[IonPacket]
|
||||||
|
var guest_cmd_hal: HAL_Ring[CmdPacket]
|
||||||
|
|
||||||
|
# Shared Channels (The Valves - L1 Logic)
|
||||||
|
var chan_rx*: SovereignChannel[IonPacket]
|
||||||
|
var chan_tx*: SovereignChannel[IonPacket]
|
||||||
|
var chan_event*: SovereignChannel[IonPacket]
|
||||||
|
var chan_cmd*: SovereignChannel[CmdPacket]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# HAL/NPL Entry points
|
||||||
proc rumpk_halt() {.importc, cdecl, noreturn.}
|
proc rumpk_halt() {.importc, cdecl, noreturn.}
|
||||||
proc virtio_net_init() {.importc, cdecl.}
|
proc virtio_net_init() {.importc, cdecl.}
|
||||||
|
proc nexshell_main() {.importc, cdecl.}
|
||||||
|
proc launch_subject() {.importc, cdecl.}
|
||||||
|
|
||||||
# Kernel I/O
|
# Hardware Ingress (Zig -> Nim)
|
||||||
proc kprint(s: string) =
|
proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} =
|
||||||
if s.len > 0:
|
## Intercept raw hardware packet and push to Sovereign RX Channel
|
||||||
console_write(unsafeAddr s[0], csize_t(s.len))
|
let data = ion_get_virt(id)
|
||||||
|
var pkt = IonPacket(data: cast[ptr UncheckedArray[byte]](data), len: len, id: id)
|
||||||
proc kprintln(s: string) =
|
chan_rx.send(pkt)
|
||||||
kprint(s)
|
|
||||||
kprint("\n")
|
|
||||||
|
|
||||||
# Panic Handler
|
# Panic Handler
|
||||||
proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} =
|
proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} =
|
||||||
kprint("\n[PANIC] ")
|
kprint("\n[PANIC] "); kprintln(msg)
|
||||||
if msg != nil:
|
|
||||||
var i = 0
|
|
||||||
while msg[i] != '\0':
|
|
||||||
var buf: array[1, char]
|
|
||||||
buf[0] = msg[i]
|
|
||||||
console_write(addr buf[0], 1)
|
|
||||||
inc i
|
|
||||||
kprint("\n")
|
|
||||||
rumpk_halt()
|
rumpk_halt()
|
||||||
|
|
||||||
# Networking Fiber
|
|
||||||
var fiber_net: FiberObject
|
|
||||||
var stack_net: array[8192, uint8]
|
|
||||||
|
|
||||||
var fiber_sniff: FiberObject
|
|
||||||
var stack_sniff: array[4096, uint8]
|
|
||||||
var fast_ring: RingBuffer[IonPacket, 256]
|
|
||||||
var sniff_flow: NetFlow
|
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# The Reflex (Zero-Copy Headers Swap)
|
# Fiber Entries
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
||||||
proc swap_macs(frame: ptr UncheckedArray[byte]) =
|
var stack_net: array[32768, uint8]
|
||||||
# Dst (0..5) <-> Src (6..11)
|
var stack_nexshell: array[32768, uint8]
|
||||||
for i in 0..5:
|
var stack_subject: array[65536, uint8]
|
||||||
let tmp = frame[i]
|
var stack_watchdog: array[4096, uint8]
|
||||||
frame[i] = frame[6+i]
|
|
||||||
frame[6+i] = tmp
|
|
||||||
|
|
||||||
proc swap_ips(frame: ptr UncheckedArray[byte]) =
|
|
||||||
# IPv4 (Eth 14). Src=12, Dst=16. Total Offset = 14+12=26, 14+16=30
|
|
||||||
# Swap 4 bytes
|
|
||||||
for i in 0..3:
|
|
||||||
let tmp = frame[26+i]
|
|
||||||
frame[26+i] = frame[30+i]
|
|
||||||
frame[30+i] = tmp
|
|
||||||
|
|
||||||
proc swap_ports(frame: ptr UncheckedArray[byte]) =
|
|
||||||
# UDP (Eth 14 + IP 20). Src=0, Dst=2. Total Offset = 34, 36
|
|
||||||
# Swap 2 bytes
|
|
||||||
for i in 0..1:
|
|
||||||
let tmp = frame[34+i]
|
|
||||||
frame[34+i] = frame[36+i]
|
|
||||||
frame[36+i] = tmp
|
|
||||||
|
|
||||||
proc fast_path_consumer() {.cdecl.} =
|
|
||||||
var aliveMsg = "[ECHO] Fiber Alive! Ready to Bounce.\n"
|
|
||||||
console_write(addr aliveMsg[0], csize_t(aliveMsg.len))
|
|
||||||
|
|
||||||
while true:
|
|
||||||
var work = false
|
|
||||||
if not fast_ring.isEmpty:
|
|
||||||
let (ok, pkt) = fast_ring.pop()
|
|
||||||
if ok:
|
|
||||||
work = true
|
|
||||||
|
|
||||||
# Zero-Copy In-Place Modification
|
|
||||||
let frame = cast[ptr UncheckedArray[byte]](pkt.data)
|
|
||||||
|
|
||||||
# 1. Swap Headers
|
|
||||||
swap_macs(frame)
|
|
||||||
swap_ips(frame)
|
|
||||||
swap_ports(frame)
|
|
||||||
|
|
||||||
# 2. Log
|
|
||||||
var msg = "[ECHO] Bouncing Packet...\n"
|
|
||||||
console_write(addr msg[0], csize_t(msg.len))
|
|
||||||
|
|
||||||
# 3. Send (Pass Ownership to Driver)
|
|
||||||
ion_egress(pkt)
|
|
||||||
|
|
||||||
# Do NOT free here. Driver frees after TX.
|
|
||||||
|
|
||||||
if not work:
|
|
||||||
switch(addr fiber_net)
|
|
||||||
|
|
||||||
proc sniffer_init() =
|
|
||||||
fast_ring.init()
|
|
||||||
ion_tx_init() # Initialize the Global TX Ring
|
|
||||||
sniff_flow.port = 8080
|
|
||||||
sniff_flow.ring = addr fast_ring
|
|
||||||
sniff_flow.fType = FLOW_DIRECT
|
|
||||||
ion_register(8080, addr sniff_flow)
|
|
||||||
init_fiber(addr fiber_sniff, fast_path_consumer, addr stack_sniff[0])
|
|
||||||
|
|
||||||
proc launch_subject() {.importc, cdecl.}
|
|
||||||
|
|
||||||
var stack_subject: array[16384, byte] # Matches STACK_SIZE in fiber.nim if 16k is preferred
|
|
||||||
var fiber_subject: FiberObject
|
|
||||||
|
|
||||||
proc subject_fiber_entry() {.cdecl.} =
|
proc subject_fiber_entry() {.cdecl.} =
|
||||||
kprintln("[Membrane] Launching Subject Zero Canary...")
|
|
||||||
launch_subject()
|
launch_subject()
|
||||||
|
|
||||||
|
# Include Watchdog Logic (Access to Kernel Globals)
|
||||||
|
include watchdog
|
||||||
|
|
||||||
proc net_fiber_entry() {.cdecl.} =
|
proc net_fiber_entry() {.cdecl.} =
|
||||||
kprintln("[Net] Fiber started. Initializing stack...")
|
kprint("[Net] Fiber 1 Reporting for Duty.")
|
||||||
ion_pool_init()
|
if net_paused: kprintln(" (PAUSED)") else: kprintln("")
|
||||||
virtio_net_init()
|
|
||||||
net_init()
|
var pkt: IonPacket
|
||||||
sniffer_init()
|
var cmd: CmdPacket
|
||||||
kprintln("[Net] Interface UP (10.0.2.15)")
|
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
net_loop_cycle(addr rumpk_netif)
|
# 1. Process Commands
|
||||||
# Pump the Membrane Stack too
|
if chan_cmd.recv(cmd):
|
||||||
# (In a real scenario, this would be a separate thread or triggered by ION)
|
if cmd.kind == uint32(CMD_NET_STOP):
|
||||||
# pump_membrane_stack() # Import this?
|
kprintln("[Net] STOP received. Suspending IO.")
|
||||||
|
net_paused = true
|
||||||
|
pause_start = cpu_ticks()
|
||||||
|
elif cmd.kind == uint32(CMD_NET_START):
|
||||||
|
kprintln("[Net] START received. Resuming IO.")
|
||||||
|
net_paused = false
|
||||||
|
|
||||||
switch(addr fiber_subject)
|
# 2. Process Data (if not paused)
|
||||||
switch(addr fiber_sniff)
|
if not net_paused:
|
||||||
|
if chan_tx.recv(pkt):
|
||||||
|
kprintln("[Net] Packet intercepted. Generating Telemetry...")
|
||||||
|
var alert = IonPacket(id: 777, len: 42)
|
||||||
|
chan_event.send(alert)
|
||||||
|
kprintln("[Net] Event dispatched.")
|
||||||
|
|
||||||
|
fiber_yield()
|
||||||
|
|
||||||
|
|
||||||
# Sovereign Syscall Table (Fixed Address: 0x801FFF00)
|
# =========================================================
|
||||||
type
|
# kmain: The Orchestrator
|
||||||
SysTable = object
|
# =========================================================
|
||||||
s_yield*: pointer
|
|
||||||
s_alloc*: pointer
|
|
||||||
s_free*: pointer
|
|
||||||
s_tx*: pointer
|
|
||||||
s_rx*: pointer # Address of the shared RX Ring (Flow)
|
|
||||||
|
|
||||||
var guest_rx_ring: RingBuffer[IonPacket, 256]
|
|
||||||
var guest_flow: NetFlow
|
|
||||||
|
|
||||||
proc rumpk_yield_internal() {.cdecl.} =
|
|
||||||
switch(addr fiber_net)
|
|
||||||
|
|
||||||
proc rumpk_alloc_internal(): IonPacket {.cdecl.} =
|
|
||||||
return ion_alloc()
|
|
||||||
|
|
||||||
proc rumpk_free_internal(pkt: IonPacket) {.cdecl.} =
|
|
||||||
ion_free(pkt)
|
|
||||||
|
|
||||||
proc rumpk_tx_internal(pkt: IonPacket): bool {.cdecl.} =
|
|
||||||
return ion_tx_push(pkt)
|
|
||||||
|
|
||||||
proc kmain() {.exportc, cdecl.} =
|
proc kmain() {.exportc, cdecl.} =
|
||||||
# Initialize the Guest Flow
|
kprintln("\n\n")
|
||||||
guest_rx_ring.init()
|
|
||||||
guest_flow.fType = FLOW_DIRECT
|
|
||||||
guest_flow.ring = addr guest_rx_ring
|
|
||||||
ion_register(8080, addr guest_flow)
|
|
||||||
|
|
||||||
# Register the SysTable at a fixed address for the Guest
|
|
||||||
let sys_table = cast[ptr SysTable](0x801FFF00'u64)
|
|
||||||
sys_table.s_yield = cast[pointer](rumpk_yield_internal)
|
|
||||||
sys_table.s_alloc = cast[pointer](rumpk_alloc_internal)
|
|
||||||
sys_table.s_free = cast[pointer](rumpk_free_internal)
|
|
||||||
sys_table.s_tx = cast[pointer](rumpk_tx_internal)
|
|
||||||
sys_table.s_rx = addr guest_rx_ring
|
|
||||||
|
|
||||||
kprintln("╔═══════════════════════════════════════╗")
|
kprintln("╔═══════════════════════════════════════╗")
|
||||||
kprintln("║ Layer 1: Nim Kernel Alive! ║")
|
kprintln("║ NEXUS RUMK v1.1 - SOVEREIGN ║")
|
||||||
kprintln("╚═══════════════════════════════════════╝")
|
kprintln("╚═══════════════════════════════════════╝")
|
||||||
|
|
||||||
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0])
|
# 1. Hardware & Memory
|
||||||
init_fiber(addr fiber_net, net_fiber_entry, addr stack_net[0])
|
kprintln("[Kernel] Initializing Memory Substrate...")
|
||||||
|
ion_pool_init()
|
||||||
|
virtio_net_init()
|
||||||
|
|
||||||
|
# 2. Channel Infrastructure
|
||||||
|
kprintln("[Kernel] Mapping Sovereign Channels...")
|
||||||
|
|
||||||
|
# Initialize Invariant Shield (Masking)
|
||||||
|
for r in [addr guest_rx_hal, addr guest_tx_hal, addr guest_event_hal]:
|
||||||
|
r.head = 0
|
||||||
|
r.tail = 0
|
||||||
|
r.mask = 255
|
||||||
|
|
||||||
|
guest_cmd_hal.head = 0
|
||||||
|
guest_cmd_hal.tail = 0
|
||||||
|
guest_cmd_hal.mask = 255
|
||||||
|
|
||||||
|
chan_rx.ring = addr guest_rx_hal
|
||||||
|
chan_tx.ring = addr guest_tx_hal
|
||||||
|
chan_event.ring = addr guest_event_hal
|
||||||
|
chan_cmd.ring = addr guest_cmd_hal
|
||||||
|
|
||||||
|
let sys_table = cast[ptr SysTable](SYSTABLE_BASE)
|
||||||
|
sys_table.magic = 0x4E585553
|
||||||
|
sys_table.s_rx = addr guest_rx_hal
|
||||||
|
sys_table.s_tx = addr guest_tx_hal
|
||||||
|
sys_table.s_event = addr guest_event_hal
|
||||||
|
sys_table.s_cmd = addr guest_cmd_hal
|
||||||
|
|
||||||
|
|
||||||
|
# 3. The Nerve (Yield Anchor)
|
||||||
|
proc rumpk_yield_guard() {.importc, cdecl.}
|
||||||
|
let yield_ptr_loc = cast[ptr pointer](0x83000FF0'u64)
|
||||||
|
yield_ptr_loc[] = cast[pointer](rumpk_yield_guard)
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
# 2. NEXSHELL FIBER (The Brain)
|
||||||
|
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell))
|
||||||
|
|
||||||
|
# 3. SUBJECT FIBER (The Payload)
|
||||||
|
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0],
|
||||||
|
sizeof(stack_subject))
|
||||||
|
|
||||||
|
# 4. WATCHDOG FIBER (The Immune System)
|
||||||
|
init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog))
|
||||||
|
|
||||||
|
kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.")
|
||||||
|
|
||||||
|
# Handover to Scheduler (The Heartbeat)
|
||||||
switch(addr fiber_net)
|
switch(addr fiber_net)
|
||||||
nimPanic("Main thread returned!")
|
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Watchdog Fiber - Logic Core Immune System
|
||||||
|
|
||||||
|
const MAX_PAUSE_TICKS = 1_000_000'u64
|
||||||
|
|
||||||
|
# Import timer from HAL (Exposed via abi.zig)
|
||||||
|
proc cpu_ticks(): uint64 {.importc: "rumpk_timer_now_ns", cdecl.}
|
||||||
|
|
||||||
|
proc watchdog_loop() {.cdecl.} =
|
||||||
|
## Fiber 0: The Immune System
|
||||||
|
# Note: Uses globals from kernel.nim via 'include'
|
||||||
|
|
||||||
|
kprintln("[Watchdog] Immune System Online.")
|
||||||
|
|
||||||
|
while true:
|
||||||
|
# Check if network is stuck in PAUSE state
|
||||||
|
if net_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
|
||||||
|
pause_start = 0
|
||||||
|
|
||||||
|
# Send CMD_NET_START to the Control Loop
|
||||||
|
var cmd = CmdPacket(kind: uint32(ion.CmdType.CMD_NET_START), arg: 0)
|
||||||
|
chan_cmd.send(cmd)
|
||||||
|
|
||||||
|
# Cooperative Multitasking: Must yield!
|
||||||
|
fiber_yield()
|
||||||
|
# asm "wfi"
|
||||||
|
|
@ -61,3 +61,11 @@ export fn rumpk_pfree(ptr: *anyopaque) void {
|
||||||
export fn rumpk_halt() noreturn {
|
export fn rumpk_halt() noreturn {
|
||||||
hal.halt();
|
hal.halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mock_ticks: u64 = 0;
|
||||||
|
|
||||||
|
export fn rumpk_timer_now_ns() u64 {
|
||||||
|
// Phase 1 Mock: Incrementing counter to simulate time passage per call
|
||||||
|
mock_ticks += 100000; // 100us per call
|
||||||
|
return mock_ticks;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
// RUMPK HAL // SOVEREIGN CHANNELS (The Pipes)
|
||||||
|
// THE INVARIANT SHIELD - Phase 2 Task 1
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const IonPacket = extern struct {
|
||||||
|
data: u64,
|
||||||
|
phys: u64,
|
||||||
|
len: u16,
|
||||||
|
id: u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CmdPacket = extern struct {
|
||||||
|
kind: u32,
|
||||||
|
arg: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn Ring(comptime T: type) type {
|
||||||
|
return extern struct {
|
||||||
|
head: u32,
|
||||||
|
tail: u32,
|
||||||
|
mask: u32,
|
||||||
|
data: [256]T,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// INVARIANT 1: The Handle Barrier
|
||||||
|
fn validate_ring_ptr(ptr: u64) void {
|
||||||
|
// 0x8000_0000 is kernel base, 0x8300_0000 is ION base.
|
||||||
|
if (ptr < 0x8000_0000) {
|
||||||
|
@panic("HAL: Invariant Violation - Invalid Ring Pointer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pushGeneric(comptime T: type, ring: *Ring(T), pkt: T) bool {
|
||||||
|
const head = @atomicLoad(u32, &ring.head, .monotonic);
|
||||||
|
const tail = @atomicLoad(u32, &ring.tail, .monotonic);
|
||||||
|
|
||||||
|
// INVARIANT 2: Overflow Protection
|
||||||
|
const next = (head + 1) & ring.mask;
|
||||||
|
if (next == tail) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring.data[head & ring.mask] = pkt;
|
||||||
|
@atomicStore(u32, &ring.head, next, .release);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn popGeneric(comptime T: type, ring: *Ring(T), out_pkt: *T) bool {
|
||||||
|
const head = @atomicLoad(u32, &ring.head, .monotonic);
|
||||||
|
const tail = @atomicLoad(u32, &ring.tail, .monotonic);
|
||||||
|
|
||||||
|
// INVARIANT 3: Underflow Protection
|
||||||
|
if (head == tail) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_pkt.* = ring.data[tail & ring.mask];
|
||||||
|
const next = (tail + 1) & ring.mask;
|
||||||
|
@atomicStore(u32, &ring.tail, next, .release);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exported ABI Functions (Hardened)
|
||||||
|
export fn hal_channel_push(handle: u64, pkt: IonPacket) bool {
|
||||||
|
validate_ring_ptr(handle);
|
||||||
|
const ring: *Ring(IonPacket) = @ptrFromInt(handle);
|
||||||
|
return pushGeneric(IonPacket, ring, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn hal_channel_pop(handle: u64, out_pkt: *IonPacket) bool {
|
||||||
|
validate_ring_ptr(handle);
|
||||||
|
const ring: *Ring(IonPacket) = @ptrFromInt(handle);
|
||||||
|
return popGeneric(IonPacket, ring, out_pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn hal_cmd_push(handle: u64, pkt: CmdPacket) bool {
|
||||||
|
validate_ring_ptr(handle);
|
||||||
|
const ring: *Ring(CmdPacket) = @ptrFromInt(handle);
|
||||||
|
return pushGeneric(CmdPacket, ring, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn hal_cmd_pop(handle: u64, out_pkt: *CmdPacket) bool {
|
||||||
|
validate_ring_ptr(handle);
|
||||||
|
const ring: *Ring(CmdPacket) = @ptrFromInt(handle);
|
||||||
|
return popGeneric(CmdPacket, ring, out_pkt);
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,12 @@ export fn _start() callconv(.naked) noreturn {
|
||||||
\\ li t0, 0x2000
|
\\ li t0, 0x2000
|
||||||
\\ csrs sstatus, t0
|
\\ csrs sstatus, t0
|
||||||
|
|
||||||
|
// 1.2 Initialize Global Pointer
|
||||||
|
\\ .option push
|
||||||
|
\\ .option norelax
|
||||||
|
\\ la gp, __global_pointer$
|
||||||
|
\\ .option pop
|
||||||
|
|
||||||
// 2. Set up Stack (Load address of stack_bytes, add size)
|
// 2. Set up Stack (Load address of stack_bytes, add size)
|
||||||
\\ la sp, stack_bytes
|
\\ la sp, stack_bytes
|
||||||
\\ li t0, 65536
|
\\ li t0, 65536
|
||||||
|
|
@ -49,20 +55,17 @@ export fn zig_entry() void {
|
||||||
uart.init_riscv();
|
uart.init_riscv();
|
||||||
uart.print("[Rumpk L0] zig_entry reached\n");
|
uart.print("[Rumpk L0] zig_entry reached\n");
|
||||||
|
|
||||||
// HUD DRAW (No CLEAR for debug)
|
// HUD DISABLED FOR PHASE 8.7 - LINEAR LOGGING ONLY
|
||||||
hud.set_color(36); // Cyan
|
// hud.set_color(36); // Cyan
|
||||||
hud.draw_box(1, 1, 80, 3, "RUMPK HUD v0.1");
|
// hud.draw_box(1, 1, 80, 3, "RUMPK HUD v0.1");
|
||||||
hud.draw_box(1, 4, 80, 20, "NEXSHELL CONSOLE");
|
// hud.draw_box(1, 4, 80, 20, "NEXSHELL CONSOLE");
|
||||||
hud.draw_box(1, 24, 80, 2, "IDENTITY");
|
// hud.draw_box(1, 24, 80, 2, "IDENTITY");
|
||||||
|
// hud.move_to(2, 4);
|
||||||
hud.move_to(2, 4);
|
// uart.print("CPU: RISC-V 64 | STATUS: INITIALIZING | MASK: SOVEREIGN");
|
||||||
uart.print("CPU: RISC-V 64 | STATUS: INITIALIZING | MASK: SOVEREIGN");
|
// hud.move_to(25, 4);
|
||||||
|
// uart.print("CELL: /Cell/Root | ID: 0xDEADBEEF");
|
||||||
hud.move_to(25, 4);
|
// hud.move_to(5, 4);
|
||||||
uart.print("CELL: /Cell/Root | ID: 0xDEADBEEF");
|
// hud.reset_color();
|
||||||
|
|
||||||
hud.move_to(5, 4);
|
|
||||||
hud.reset_color();
|
|
||||||
|
|
||||||
uart.print("[Rumpk RISC-V] Handing off to Nim L1...\n");
|
uart.print("[Rumpk RISC-V] Handing off to Nim L1...\n");
|
||||||
// VirtIO Init moved to Kernel L1 (Sovereign Mode)
|
// VirtIO Init moved to Kernel L1 (Sovereign Mode)
|
||||||
|
|
@ -86,9 +89,25 @@ export fn console_write(ptr: [*]const u8, len: usize) void {
|
||||||
uart.write_bytes(ptr[0..len]);
|
uart.write_bytes(ptr[0..len]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn console_read() c_int {
|
||||||
|
if (uart.read_byte()) |b| {
|
||||||
|
return @as(c_int, b);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
export fn rumpk_halt() noreturn {
|
export fn rumpk_halt() noreturn {
|
||||||
uart.print("[Rumpk L0] Halting.\n");
|
uart.print("[Rumpk L0] Halting.\n");
|
||||||
while (true) {
|
while (true) {
|
||||||
asm volatile ("wfi");
|
asm volatile ("wfi");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mock_ticks: u64 = 0;
|
||||||
|
|
||||||
|
export fn rumpk_timer_now_ns() u64 {
|
||||||
|
// Phase 1 Mock: Incrementing counter to simulate time passage per call
|
||||||
|
// This allows Watchdog logic to detect elapsed "time" in coop loop.
|
||||||
|
mock_ticks += 100000; // 100us per call
|
||||||
|
return mock_ticks;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,187 @@
|
||||||
|
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 CmdPacket = extern struct {
|
||||||
|
kind: u32,
|
||||||
|
arg: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RingBufferPacket = extern struct {
|
||||||
|
head: u32,
|
||||||
|
tail: u32,
|
||||||
|
mask: u32,
|
||||||
|
data: [256]IonPacket,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RingBufferCmd = extern struct {
|
||||||
|
head: u32,
|
||||||
|
tail: u32,
|
||||||
|
mask: u32,
|
||||||
|
data: [256]CmdPacket,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SysTable = extern struct {
|
||||||
|
magic: u32,
|
||||||
|
s_rx: *RingBufferPacket,
|
||||||
|
s_tx: *RingBufferPacket,
|
||||||
|
s_event: *RingBufferPacket,
|
||||||
|
s_cmd: *RingBufferCmd, // Added for Sabotage
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. The Direct Accessor
|
||||||
|
fn get_systable() *SysTable {
|
||||||
|
return @ptrFromInt(ION_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. The Saboteur Entry Point
|
||||||
|
export fn main() c_int {
|
||||||
|
print("[SABOTEUR] Engaged. Waiting for Init...\n");
|
||||||
|
|
||||||
|
// Allow system to stabilize (simulated simple wait loop)
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < 10) : (i += 1) {
|
||||||
|
fiber_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
const sys = get_systable();
|
||||||
|
|
||||||
|
if (sys.magic != 0x4E585553) {
|
||||||
|
print("[SABOTEUR] Magic mismatch! Aborting.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Send CMD_NET_STOP (Poison)
|
||||||
|
print("[SABOTEUR] Injecting POISON (CMD_NET_STOP)...\n");
|
||||||
|
{
|
||||||
|
const cmd_ring = sys.s_cmd;
|
||||||
|
const head = @atomicLoad(u32, &cmd_ring.head, .monotonic);
|
||||||
|
|
||||||
|
// CMD_NET_STOP = 1
|
||||||
|
const pkt = CmdPacket{ .kind = 1, .arg = 0 };
|
||||||
|
|
||||||
|
cmd_ring.data[head & cmd_ring.mask] = pkt;
|
||||||
|
@atomicStore(u32, &cmd_ring.head, head + 1, .release);
|
||||||
|
print("[SABOTEUR] POISON injected.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[SABOTEUR] Network poisoned. Entering infinite loop to block CPU.\n");
|
||||||
|
print("[SABOTEUR] (This simulates a stuck NPL preventing yields)\n");
|
||||||
|
|
||||||
|
// 2. Hang
|
||||||
|
// In a cooperative multitasking system, if we don't yield, we freeze the fiber.
|
||||||
|
// If we are "Subject Fiber", and we don't yield, the scheduler can't switch.
|
||||||
|
// BUT the Kernel runs in "Launch_subject".
|
||||||
|
// Does "launch_subject" in loader.zig return?
|
||||||
|
// "entry()" calls into the binary.
|
||||||
|
// If the binary loops forever, "launch_subject" never returns.
|
||||||
|
// So "subject_fiber_entry" never returns.
|
||||||
|
// So "switch" is never called.
|
||||||
|
// So Fiber 1 (Net) and Fiber 2 (NexShell) never run?
|
||||||
|
//
|
||||||
|
// WAIT.
|
||||||
|
// If the Saboteur loops forever, and there is no Preemptive Timer Interrupt (yet),
|
||||||
|
// the WHOLE SYSTEM HANGS. The Watchdog is likely a separate Fiber.
|
||||||
|
// If Rumpk is Cooperative (Co-routines), a while(true) in one fiber KILLS EVERYTHING.
|
||||||
|
//
|
||||||
|
// UNLESS the Watchdog is:
|
||||||
|
// A) Running on a separate core? (No, Boot msg says Single Core usually for simple tests)
|
||||||
|
// B) Triggered by Interrupt? (Timer IRQ)
|
||||||
|
//
|
||||||
|
// The Watchdog in `core/watchdog.nim` is a FIBER: `watchdog_loop()`.
|
||||||
|
// It runs `while true: ... wfi`.
|
||||||
|
// If `subject_fiber` spins, `watchdog_fiber` NEVER RUNS.
|
||||||
|
//
|
||||||
|
// "The Saboteur Test ... The system detects the hang ... and restarts".
|
||||||
|
//
|
||||||
|
// If the system is purely cooperative, this test will FAIL unless:
|
||||||
|
// 1. `launch_subject` is run with a timeout? (No)
|
||||||
|
// 2. We have a Timer Interrupt that forces a context switch?
|
||||||
|
// `hal/entry_riscv.zig` disables interrupts: `csrw sie, zero`.
|
||||||
|
//
|
||||||
|
// The prompt says: "You successfully implemented the Watchdog. Now we must prove it works...".
|
||||||
|
// The Watchdog implementation in `kernel.nim` / `watchdog.nim` uses `wfi` (Wait For Interrupt).
|
||||||
|
// It implies there ARE interrupts waking it up.
|
||||||
|
// But if `Subject` spins in `while(true)`, it depends on whether `Subject` yields.
|
||||||
|
// `apps/subject_zig/main.zig` calls `fiber_yield`.
|
||||||
|
//
|
||||||
|
// If the Saboteur does `while(true) {}` without yield, it locks the CPU.
|
||||||
|
//
|
||||||
|
// "Reference: SPEC-008... Immortality".
|
||||||
|
// Maybe the "Watchdog" is supposed to be a *Hardware* Watchdog or Interrupt-driven?
|
||||||
|
// But the code I wrote in `watchdog.nim` is a Fiber.
|
||||||
|
//
|
||||||
|
// "Fiber 0: The Immune System".
|
||||||
|
// If I implemented it as a Fiber, it needs CPU time.
|
||||||
|
//
|
||||||
|
// CRITICAL REALIZATION:
|
||||||
|
// If I hang the CPU in a fiber in a cooperative OS, the OS dies.
|
||||||
|
// The only way this test passes is if:
|
||||||
|
// A) The Saboteur calls `fiber_yield()` inside the loop?
|
||||||
|
// Prompt says: "Enters an infinite while(true) {} loop (Hangs the fiber)."
|
||||||
|
// "Hangs the fiber" usually means "doesn't yield".
|
||||||
|
// But if it doesn't yield, the Watchdog fiber can't run to detect it.
|
||||||
|
//
|
||||||
|
// UNLESS...
|
||||||
|
// The "Watchdog" I implemented checks `net_paused`.
|
||||||
|
// The Saboteur *sends* `CMD_NET_STOP`. This sets `net_paused = true`.
|
||||||
|
// Then Saboteur hangs.
|
||||||
|
//
|
||||||
|
// If Saboteur hangs (no yield), Watchdog logic (which checks `net_paused`) never runs.
|
||||||
|
// So it can't "Force RESUME".
|
||||||
|
//
|
||||||
|
// PERHAPS the Saboteur should loop *with yield*?
|
||||||
|
// "Hangs the fiber" might mean "Stops doing useful work and just loops".
|
||||||
|
// If it yields, other fibers run.
|
||||||
|
// The Network Fiber runs, sees `net_paused`, and skips IO.
|
||||||
|
// The Watchdog Fiber runs, sees `net_paused && time > threshold`, and "Heals".
|
||||||
|
//
|
||||||
|
// IF the test is about "Network Paused Too Long", then yes, the system must still schedule.
|
||||||
|
// So the Saboteur must YIELD in its loop, but REFUSE to send `CMD_NET_START`.
|
||||||
|
// It basically attacks the logic (pauses net) and then refuses to resume it.
|
||||||
|
// The Watchdog overrides it.
|
||||||
|
//
|
||||||
|
// So, `while (true) { fiber_yield(); }` is the correct "Hang" for a cooperative system where we want to test Logic Recovery, not CPU Starvation Recovery (which requires IRQs).
|
||||||
|
//
|
||||||
|
// I will implement the loop with `fiber_yield()`.
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
fiber_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimal Shims
|
||||||
|
extern fn write(fd: c_int, buf: [*]const u8, count: usize) isize;
|
||||||
|
const YIELD_LOC = 0x83000FF0;
|
||||||
|
|
||||||
|
fn fiber_yield() void {
|
||||||
|
const ptr: *const *const fn () callconv(.c) void = @ptrFromInt(YIELD_LOC);
|
||||||
|
const func = ptr.*;
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
|
// extern fn fiber_yield() void; // Removed extern
|
||||||
|
|
||||||
|
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[SABOTEUR] PANIC: ");
|
||||||
|
print(msg);
|
||||||
|
print("\n");
|
||||||
|
while (true) {}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue