From 2f8a062a74f9e5a198e99bdbff2053252f7d99b5 Mon Sep 17 00:00:00 2001 From: Markus Maiwald Date: Tue, 30 Dec 2025 08:07:22 +0100 Subject: [PATCH] feat(rumpk): Multi-Architecture HAL (aarch64, x86_64, riscv64) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TRI-ARCH SOVEREIGNTY ==================== Rumpk now supports three major architectures: - aarch64 (ARM64): VisionFive 2, RPi, AWS Graviton - x86_64: Standard servers, trading, banking - riscv64: Sovereign compute, satellites, drones DIRECTORY STRUCTURE ------------------- hal/arch/ ├── aarch64/ │ ├── switch.S # ARM64 context switch (96 bytes) │ └── constants.nim # LR_OFFSET=11, FP_OFFSET=10 ├── x86_64/ │ ├── switch.S # System V ABI switch (56 bytes) │ └── constants.nim # RIP_OFFSET=6 └── riscv64/ ├── switch.S # RISC-V LP64 switch (112 bytes) └── constants.nim # RA_OFFSET=0 UNIFIED FIBER.NIM ----------------- Uses Nim's 'when defined()' for compile-time arch selection: - CONTEXT_SIZE varies by arch (56/96/112) - RET_ADDR_INDEX points to return address slot - Halt instruction varies (hlt/wfi) BUILD SYSTEM ------------ ./build.sh [aarch64|x86_64|riscv64] - Default: aarch64 - Output: build/rumpk-$ARCH.elf - Auto-selects linker script if arch-specific exists ABI SUMMARY ----------- | Arch | Callee-Saved | Frame | Alignment | |----------|------------------------|-------|-----------| | aarch64 | x19-x30 | 96B | 16-byte | | x86_64 | rbx,rbp,r12-r15 | 56B | 16-byte | | riscv64 | ra,s0-s11 | 112B | 16-byte | VERIFICATION ------------ ARM64 fibers still work: [Fiber A] I am alive! Yielding to B... [Fiber B] Hello from B! Yielding to A... [Fiber A] I am back! Yielding to B... One codebase. All profiles. NIIX philosophy enforced. --- .../h/31c6d0776b5b523af2f21bce16b73434.txt | 2 +- .../h/f385b25468511de3ae7285b5ccbf0f97.txt | 2 +- .../h/fa7ac5db5447ac8410777171db58a321.txt | 2 + build.sh | 117 ++++++++++++------ core/fiber.nim | 92 +++++++++++--- hal/arch/aarch64/constants.nim | 17 +++ hal/{ => arch/aarch64}/switch.S | 0 hal/arch/riscv64/constants.nim | 16 +++ hal/arch/riscv64/switch.S | 61 +++++++++ hal/arch/x86_64/constants.nim | 20 +++ hal/arch/x86_64/switch.S | 42 +++++++ 11 files changed, 313 insertions(+), 58 deletions(-) create mode 100644 .zig-cache/h/fa7ac5db5447ac8410777171db58a321.txt create mode 100644 hal/arch/aarch64/constants.nim rename hal/{ => arch/aarch64}/switch.S (100%) create mode 100644 hal/arch/riscv64/constants.nim create mode 100644 hal/arch/riscv64/switch.S create mode 100644 hal/arch/x86_64/constants.nim create mode 100644 hal/arch/x86_64/switch.S diff --git a/.zig-cache/h/31c6d0776b5b523af2f21bce16b73434.txt b/.zig-cache/h/31c6d0776b5b523af2f21bce16b73434.txt index 00715fd..394dffb 100644 --- a/.zig-cache/h/31c6d0776b5b523af2f21bce16b73434.txt +++ b/.zig-cache/h/31c6d0776b5b523af2f21bce16b73434.txt @@ -1,5 +1,5 @@ 0 -3010 9464225 1767078091252764644 d33830b1025db04959bdc2ff9bd43537 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mfiber.nim.c +3017 9465107 1767078402329925246 2cc632112af79aeb33a943b3ef26eb76 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mfiber.nim.c 19164 69191110 1749873121000000000 fe5756ed84745fc96fd9dfb15050f599 0 /usr/lib/nim/nimbase.h 639 9459383 1767076381899751290 1b9448bcfa47e3161459266750e8ded4 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/limits.h 268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h diff --git a/.zig-cache/h/f385b25468511de3ae7285b5ccbf0f97.txt b/.zig-cache/h/f385b25468511de3ae7285b5ccbf0f97.txt index 93ef178..7ed1b30 100644 --- a/.zig-cache/h/f385b25468511de3ae7285b5ccbf0f97.txt +++ b/.zig-cache/h/f385b25468511de3ae7285b5ccbf0f97.txt @@ -1,5 +1,5 @@ 0 -15874 9464226 1767078031260762209 d133b7af4a91c5ff6970726948774437 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mkernel.nim.c +15874 9465108 1767078402329925246 e5c92c416746964294e1e5d350d1d6c3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mkernel.nim.c 19164 69191110 1749873121000000000 fe5756ed84745fc96fd9dfb15050f599 0 /usr/lib/nim/nimbase.h 639 9459383 1767076381899751290 1b9448bcfa47e3161459266750e8ded4 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/limits.h 268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h diff --git a/.zig-cache/h/fa7ac5db5447ac8410777171db58a321.txt b/.zig-cache/h/fa7ac5db5447ac8410777171db58a321.txt new file mode 100644 index 0000000..772f157 --- /dev/null +++ b/.zig-cache/h/fa7ac5db5447ac8410777171db58a321.txt @@ -0,0 +1,2 @@ +0 +1104 9461671 1767078085543858486 a0b42b3b0dd9bf113104ca6ca3c6f51d 0 /home/markus/zWork/_Git/Nexus/core/rumpk/hal/arch/aarch64/switch.S diff --git a/build.sh b/build.sh index 527ed33..5b36fbf 100755 --- a/build.sh +++ b/build.sh @@ -1,17 +1,52 @@ #!/bin/bash -# Rumpk Build Script - Freestanding Doctrine -# Pure Zig L0 + Nim L1, no C stubs, no glibc -# -# We are the standard library now. +# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) +# Rumpk Build Script - Multi-Architecture +# Supports: aarch64, x86_64, riscv64 set -e RUMPK_DIR="$(cd "$(dirname "$0")" && pwd)" BUILD_DIR="$RUMPK_DIR/build" +# Default architecture +ARCH="${1:-aarch64}" + +# Validate architecture +case "$ARCH" in + aarch64|arm64) + ARCH="aarch64" + ZIG_TARGET="aarch64-freestanding-none" + NIM_CPU="arm64" + NIM_DEFINE="arm64" + QEMU_CMD="qemu-system-aarch64 -M virt -cpu cortex-a57" + UART_ADDR="0x09000000" + ;; + x86_64|amd64) + ARCH="x86_64" + ZIG_TARGET="x86_64-freestanding-none" + NIM_CPU="amd64" + NIM_DEFINE="amd64" + QEMU_CMD="qemu-system-x86_64 -M q35" + UART_ADDR="0x3F8" # COM1 + ;; + riscv64) + ARCH="riscv64" + ZIG_TARGET="riscv64-freestanding-none" + NIM_CPU="riscv64" + NIM_DEFINE="riscv64" + QEMU_CMD="qemu-system-riscv64 -M virt" + UART_ADDR="0x10000000" + ;; + *) + echo "Usage: $0 [aarch64|x86_64|riscv64]" + echo "Default: aarch64" + exit 1 + ;; +esac + echo "╔═══════════════════════════════════════╗" -echo "║ RUMPK FREESTANDING BUILD v0.2 ║" -echo "║ No glibc. Pure Sovereignty. ║" +echo "║ RUMPK MULTI-ARCH BUILD v0.3 ║" +echo "║ Architecture: $ARCH " echo "╚═══════════════════════════════════════╝" echo "" @@ -20,49 +55,55 @@ mkdir -p "$BUILD_DIR" mkdir -p "$BUILD_DIR/nimcache" # ========================================================= -# Step 1: Compile Zig L0 (HAL + Stubs + Context Switch) +# Step 1: Compile Zig L0 (HAL + Stubs) # ========================================================= -echo "[1/5] Compiling Zig L0 (HAL + libc stubs + context switch)..." +echo "[1/5] Compiling Zig L0 (HAL + libc stubs)..." # Compile main.zig zig build-obj \ "$RUMPK_DIR/hal/main.zig" \ - -target aarch64-freestanding-none \ + -target $ZIG_TARGET \ -O ReleaseSmall \ -femit-bin="$BUILD_DIR/hal.o" -# Compile stubs.zig (our libc replacement) +# Compile stubs.zig zig build-obj \ "$RUMPK_DIR/hal/stubs.zig" \ - -target aarch64-freestanding-none \ + -target $ZIG_TARGET \ -O ReleaseSmall \ -femit-bin="$BUILD_DIR/stubs.o" -# Compile switch.S (context switch assembly) -zig cc \ - -target aarch64-freestanding-none \ - -c "$RUMPK_DIR/hal/switch.S" \ - -o "$BUILD_DIR/switch.o" - echo " → $BUILD_DIR/hal.o" echo " → $BUILD_DIR/stubs.o" + +# ========================================================= +# Step 2: Compile Context Switch Assembly +# ========================================================= +echo "[2/5] Compiling context switch ($ARCH)..." + +zig cc \ + -target $ZIG_TARGET \ + -c "$RUMPK_DIR/hal/arch/$ARCH/switch.S" \ + -o "$BUILD_DIR/switch.o" + echo " → $BUILD_DIR/switch.o" # ========================================================= -# Step 2: Compile Nim L1 (Kernel + Fibers) +# Step 3: Compile Nim L1 (Kernel + Fibers) # ========================================================= -echo "[2/5] Compiling Nim L1 (Kernel + Fibers)..." +echo "[3/5] Compiling Nim L1 (Kernel + Fibers)..." nim c \ - --cpu:arm64 \ + --cpu:$NIM_CPU \ --os:any \ --mm:arc \ --noMain:on \ --cc:clang \ - --passC:"-target aarch64-unknown-none -ffreestanding -fno-stack-protector -fno-builtin" \ - --passL:"-target aarch64-unknown-none -nostdlib -ffreestanding" \ + --passC:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -ffreestanding -fno-stack-protector -fno-builtin" \ + --passL:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -nostdlib -ffreestanding" \ --define:useMalloc \ --define:StandaloneHeapSize=65536 \ + --define:$NIM_DEFINE \ -d:release \ -d:danger \ --checks:off \ @@ -77,14 +118,14 @@ nim c \ echo " → $BUILD_DIR/nimcache/*.c" # ========================================================= -# Step 3: Compile Nim C files to objects +# Step 4: Compile Nim C files to objects # ========================================================= -echo "[3/5] Compiling Nim C files..." +echo "[4/5] Compiling Nim C files..." for cfile in "$BUILD_DIR/nimcache"/*.c; do ofile="${cfile%.c}.o" zig cc \ - -target aarch64-freestanding-none \ + -target $ZIG_TARGET \ -ffreestanding \ -fno-stack-protector \ -fno-builtin \ @@ -99,11 +140,10 @@ done echo " → $BUILD_DIR/nimcache/*.o" # ========================================================= -# Step 4: Link Everything (NO LIBC!) +# Step 5: Link Everything # ========================================================= -echo "[4/5] Linking (freestanding, no libc)..." +echo "[5/5] Linking (freestanding, no libc)..." -# Collect all Nim object files NIM_OBJS=$(find "$BUILD_DIR/nimcache" -name "*.o" 2>/dev/null | tr '\n' ' ') if [ -z "$NIM_OBJS" ]; then @@ -111,26 +151,29 @@ if [ -z "$NIM_OBJS" ]; then exit 1 fi +# Select linker script based on architecture +LINKER_SCRIPT="$RUMPK_DIR/boot/linker.ld" +if [ -f "$RUMPK_DIR/boot/linker-$ARCH.ld" ]; then + LINKER_SCRIPT="$RUMPK_DIR/boot/linker-$ARCH.ld" +fi + zig cc \ - -target aarch64-freestanding-none \ + -target $ZIG_TARGET \ -nostdlib \ - -T "$RUMPK_DIR/boot/linker.ld" \ + -T "$LINKER_SCRIPT" \ "$BUILD_DIR/hal.o" \ "$BUILD_DIR/stubs.o" \ "$BUILD_DIR/switch.o" \ $NIM_OBJS \ - -o "$BUILD_DIR/rumpk.elf" + -o "$BUILD_DIR/rumpk-$ARCH.elf" -echo " → $BUILD_DIR/rumpk.elf" +echo " → $BUILD_DIR/rumpk-$ARCH.elf" # ========================================================= # Done # ========================================================= echo "" -echo "✅ Freestanding build complete!" -echo "" -echo "Verification:" -echo " file $BUILD_DIR/rumpk.elf" +echo "✅ Build complete for $ARCH!" echo "" echo "Run with:" -echo " qemu-system-aarch64 -M virt -cpu cortex-a57 -nographic -kernel $BUILD_DIR/rumpk.elf" +echo " $QEMU_CMD -nographic -kernel $BUILD_DIR/rumpk-$ARCH.elf" diff --git a/core/fiber.nim b/core/fiber.nim index 0dabc12..4ba6048 100644 --- a/core/fiber.nim +++ b/core/fiber.nim @@ -1,9 +1,40 @@ # MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) -# RUMPK CORE // FIBER +# RUMPK CORE // FIBER (Unified Multi-Arch) # The atom of execution. +# +# Supported Architectures: +# - aarch64 (ARM64): VisionFive 2, RPi, AWS Graviton +# - amd64 (x86_64): Standard servers, trading systems +# - riscv64 (RISC-V): Sovereign compute, satellites {.push stackTrace: off, lineTrace: off.} +# ========================================================= +# Architecture-Specific Constants +# ========================================================= + +when defined(amd64) or defined(x86_64): + const CONTEXT_SIZE = 56 + const RET_ADDR_INDEX = 6 # RIP at [sp + 48] + const ARCH_NAME = "x86_64" + +elif defined(arm64) or defined(aarch64): + const CONTEXT_SIZE = 96 + const RET_ADDR_INDEX = 11 # x30 (LR) at [sp + 88] + const ARCH_NAME = "aarch64" + +elif defined(riscv64): + const CONTEXT_SIZE = 112 + const RET_ADDR_INDEX = 0 # ra at [sp + 0] + const ARCH_NAME = "riscv64" + +else: + {.error: "Unsupported architecture for Rumpk fibers".} + +# ========================================================= +# Types +# ========================================================= + type FiberState* = object sp*: uint64 # The Stack Pointer (Must be first field!) @@ -17,7 +48,11 @@ type stack*: ptr UncheckedArray[uint8] stack_size*: int -# Import the Assembly Magic +# ========================================================= +# Imports +# ========================================================= + +# Import the Assembly Magic (same symbol name, different implementation per arch) proc cpu_switch_to(prev_sp_ptr: ptr uint64, next_sp: uint64) {.importc, cdecl.} # Import console for debugging @@ -27,17 +62,23 @@ proc debug(s: string) = if s.len > 0: console_write(unsafeAddr s[0], csize_t(s.len)) -# Context Frame Size: 6 pairs * 16 bytes = 96 bytes (16-byte aligned!) -const CONTEXT_SIZE = 96 +# ========================================================= +# Constants +# ========================================================= -# Stack Helper (Simple 4KB aligned stack) const STACK_SIZE* = 4096 -# We need a "Main" fiber to represent the boot thread +# ========================================================= +# Fiber State +# ========================================================= + var main_fiber: FiberObject var current_fiber*: Fiber = addr main_fiber -# Trampoline that calls the fiber's entry point +# ========================================================= +# Trampoline (Entry point for new fibers) +# ========================================================= + proc fiber_trampoline() {.cdecl, exportc, noreturn.} = let f = current_fiber @@ -45,8 +86,19 @@ proc fiber_trampoline() {.cdecl, exportc, noreturn.} = f.state.entry() # If the fiber returns, halt - while true: - {.emit: "asm volatile(\"wfi\");".} + when defined(amd64) or defined(x86_64): + while true: + {.emit: "asm volatile(\"hlt\");".} + elif defined(arm64) or defined(aarch64): + while true: + {.emit: "asm volatile(\"wfi\");".} + elif defined(riscv64): + while true: + {.emit: "asm volatile(\"wfi\");".} + +# ========================================================= +# Fiber Initialization (Arch-Specific) +# ========================================================= proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer) = f.state.entry = entry @@ -54,27 +106,29 @@ proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer) = # Start at top of stack var sp = cast[uint64](stack_base) + STACK_SIZE - # 1. Align to 16 bytes (Strict requirement) + # 1. Align to 16 bytes (Universal requirement) sp = sp and not 15'u64 - # 2. Reserve space for the context frame (96 bytes) + # 2. Reserve space for the context frame sp = sp - CONTEXT_SIZE - # 3. Setup the Context + # 3. Setup the Context (zero all, set return address) var stack_ptr = cast[ptr UncheckedArray[uint64]](sp) - # Zero out registers x19-x28 (indices 0-9) - for i in 0..<10: + # Zero out the frame + let num_regs = CONTEXT_SIZE div 8 + for i in 0..