From 5c3a8e3713b6470d30a4918351e98848105726b1 Mon Sep 17 00:00:00 2001 From: Markus Maiwald Date: Tue, 30 Dec 2025 07:44:25 +0100 Subject: [PATCH] feat(rumpk): Pure Zig libc stubs - Freestanding Doctrine THE GHOST IN THE MACHINE IS EXORCISED ====================================== Rumpk now builds with ZERO C source files. All libc functions are implemented in pure Zig. WHAT CHANGED ------------ - NEW: hal/stubs.zig - Pure Zig libc implementation - memcpy, memset, memmove, memcmp - strlen, strcmp, strcpy - malloc, free, realloc, calloc (bump allocator) - printf, puts, putchar (route to UART) - exit, abort (halt CPU) - signal, raise (no-op stubs) - REMOVED: core/cstubs.c dependency from build - C code is now only Nim's generated IR - UPDATED: kernel.nim - Removed malloc/free/realloc exports - Now imports from Zig stubs - UPDATED: build.sh - Compiles hal/stubs.zig separately - Links stubs.o with hal.o and nimcache/*.o DOCTRINE DOCUMENT ----------------- - .agents/steering/FREESTANDING-DOCTRINE.md - Codifies the 'Pure Zig ABI' principle - Documents build requirements - Lists all exported symbols VERIFICATION ------------ $ file build/rumpk.elf ELF 64-bit LSB executable, ARM aarch64, statically linked $ qemu-system-aarch64 -M virt -kernel build/rumpk.elf [Rumpk L0] Zig HAL Initialized [Rumpk L1] Nim Kernel Alive! [Rumpk L1] The Rubicon is crossed. [Rumpk L1] Zig + Nim = Sovereign Metal. This proves: - POSIX is optional - GCC is optional - glibc/musl is optional - We are the standard library now --- .../h/42a82410c6e7cdd9b74bb29aa44181eb.txt | 6 +- .zig-cache/z/1bbd978ef4c616d6b2fdeb39a550d19e | Bin 0 -> 16121 bytes build.sh | 49 ++--- core/kernel.nim | 34 +-- hal/stubs.zig | 195 ++++++++++++++++++ 5 files changed, 229 insertions(+), 55 deletions(-) create mode 100644 .zig-cache/z/1bbd978ef4c616d6b2fdeb39a550d19e create mode 100644 hal/stubs.zig diff --git a/.zig-cache/h/42a82410c6e7cdd9b74bb29aa44181eb.txt b/.zig-cache/h/42a82410c6e7cdd9b74bb29aa44181eb.txt index 586c644..0bf31aa 100644 --- a/.zig-cache/h/42a82410c6e7cdd9b74bb29aa44181eb.txt +++ b/.zig-cache/h/42a82410c6e7cdd9b74bb29aa44181eb.txt @@ -1,8 +1,8 @@ 0 -12268 9459532 1767076443800031133 c56105a5a3a93a0d4d451c619dc2b349 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mkernel.nim.c +10486 9461201 1767076985098986152 3747702445e0bcda6de1816ec7a47cdd 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 -1172 78925833 1761046366000000000 69b529ccb10bbb5d826c563cf9b929c1 1 include/stdbool.h -31054 78925836 1761046366000000000 1df950c62cbc96dd5d9790733bbe6016 1 include/stdint.h +155 9459777 1767076495338437553 9cc523d7a8a3a0bbc7c7af0fabeafc0b 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stdbool.h +924 9459799 1767076530759032485 73bc6834aef9958f6652470b63d7814b 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stdint.h 499 9459330 1767076360432003062 357ccd6329b0128cce0610c1443c600d 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/string.h diff --git a/.zig-cache/z/1bbd978ef4c616d6b2fdeb39a550d19e b/.zig-cache/z/1bbd978ef4c616d6b2fdeb39a550d19e new file mode 100644 index 0000000000000000000000000000000000000000..19c3fbb8748fb7bd835c89b6f0ebe9dc600b65fd GIT binary patch literal 16121 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 aGhq>U_V|3e*WD+^+8EF@_#234_5T6VZ2@oq literal 0 HcmV?d00001 diff --git a/build.sh b/build.sh index 3b32454..20aab81 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,8 @@ #!/bin/bash -# Rumpk Build Script -# Builds Zig L0 + Nim L1 into a single ELF +# Rumpk Build Script - Freestanding Doctrine +# Pure Zig L0 + Nim L1, no C stubs, no glibc +# +# We are the standard library now. set -e @@ -8,7 +10,8 @@ RUMPK_DIR="$(cd "$(dirname "$0")" && pwd)" BUILD_DIR="$RUMPK_DIR/build" echo "╔═══════════════════════════════════════╗" -echo "║ RUMPK BUILD SYSTEM v0.1 ║" +echo "║ RUMPK FREESTANDING BUILD v0.2 ║" +echo "║ No glibc. Pure Sovereignty. ║" echo "╚═══════════════════════════════════════╝" echo "" @@ -17,25 +20,31 @@ mkdir -p "$BUILD_DIR" mkdir -p "$BUILD_DIR/nimcache" # ========================================================= -# Step 1: Compile Zig L0 (HAL) +# Step 1: Compile Zig L0 (HAL + Stubs) # ========================================================= -echo "[1/3] Compiling Zig L0 (HAL)..." +echo "[1/4] Compiling Zig L0 (HAL + libc stubs)..." +# Compile main.zig zig build-obj \ "$RUMPK_DIR/hal/main.zig" \ -target aarch64-freestanding-none \ -O ReleaseSmall \ -femit-bin="$BUILD_DIR/hal.o" +# Compile stubs.zig (our libc replacement) +zig build-obj \ + "$RUMPK_DIR/hal/stubs.zig" \ + -target aarch64-freestanding-none \ + -O ReleaseSmall \ + -femit-bin="$BUILD_DIR/stubs.o" + echo " → $BUILD_DIR/hal.o" +echo " → $BUILD_DIR/stubs.o" # ========================================================= # Step 2: Compile Nim L1 (Kernel) # ========================================================= -echo "[2/3] Compiling Nim L1 (Kernel)..." - -# Note: This requires careful Nim configuration for freestanding -# For now, we'll try direct compilation with clang +echo "[2/4] Compiling Nim L1 (Kernel)..." nim c \ --cpu:arm64 \ @@ -61,17 +70,6 @@ echo " → $BUILD_DIR/nimcache/*.c" # ========================================================= echo "[3/4] Compiling Nim C files..." -# First compile cstubs.c -echo " Compiling cstubs.c..." -zig cc \ - -target aarch64-freestanding-none \ - -ffreestanding \ - -fno-builtin \ - -I"$RUMPK_DIR/core/include" \ - -c "$RUMPK_DIR/core/cstubs.c" \ - -o "$BUILD_DIR/cstubs.o" - -# Now compile Nim C files for cfile in "$BUILD_DIR/nimcache"/*.c; do ofile="${cfile%.c}.o" zig cc \ @@ -89,9 +87,9 @@ done echo " → $BUILD_DIR/nimcache/*.o" # ========================================================= -# Step 4: Link Everything +# Step 4: Link Everything (NO LIBC!) # ========================================================= -echo "[4/4] Linking..." +echo "[4/4] Linking (freestanding, no libc)..." # Collect all Nim object files NIM_OBJS=$(find "$BUILD_DIR/nimcache" -name "*.o" 2>/dev/null | tr '\n' ' ') @@ -106,7 +104,7 @@ zig cc \ -nostdlib \ -T "$RUMPK_DIR/boot/linker.ld" \ "$BUILD_DIR/hal.o" \ - "$BUILD_DIR/cstubs.o" \ + "$BUILD_DIR/stubs.o" \ $NIM_OBJS \ -o "$BUILD_DIR/rumpk.elf" @@ -116,7 +114,10 @@ echo " → $BUILD_DIR/rumpk.elf" # Done # ========================================================= echo "" -echo "✅ Build complete!" +echo "✅ Freestanding build complete!" +echo "" +echo "Verification:" +echo " file $BUILD_DIR/rumpk.elf" echo "" echo "Run with:" echo " qemu-system-aarch64 -M virt -cpu cortex-a57 -nographic -kernel $BUILD_DIR/rumpk.elf" diff --git a/core/kernel.nim b/core/kernel.nim index 667c994..c6ffeb8 100644 --- a/core/kernel.nim +++ b/core/kernel.nim @@ -42,36 +42,14 @@ proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} = rumpk_halt() # ========================================================= -# Memory Allocator Stubs (Required for ARC on freestanding) +# Memory Allocator - Provided by Zig L0 (hal/stubs.zig) # ========================================================= -# Static heap for bare metal (64KB) -var heapBase {.exportc.}: array[64 * 1024, byte] -var heapOffset {.exportc.}: csize_t = 0 - -proc allocImpl(size: csize_t): pointer {.exportc: "malloc", cdecl.} = - if heapOffset + size > csize_t(heapBase.len): - return nil - result = addr heapBase[heapOffset] - heapOffset += size - -proc deallocImpl(p: pointer) {.exportc: "free", cdecl.} = - # Bump allocator - no dealloc - discard - -proc reallocImpl(p: pointer, size: csize_t): pointer {.exportc: "realloc", cdecl.} = - # Simple realloc - just allocate new (wasteful but works) - result = allocImpl(size) - -# Nim's internal allocation hooks -proc rawAlloc(size: Natural): pointer {.exportc: "rawAlloc", cdecl.} = - result = allocImpl(csize_t(size)) - -proc rawDealloc(p: pointer) {.exportc: "rawDealloc", cdecl.} = - deallocImpl(p) - -proc rawRealloc(p: pointer, size: Natural): pointer {.exportc: "rawRealloc", cdecl.} = - result = reallocImpl(p, csize_t(size)) +# Zig exports: malloc, free, realloc, calloc +# We just import them for any explicit usage +proc malloc(size: csize_t): pointer {.importc, cdecl.} +proc free(p: pointer) {.importc, cdecl.} +proc realloc(p: pointer, size: csize_t): pointer {.importc, cdecl.} # ========================================================= # Kernel Main Entry diff --git a/hal/stubs.zig b/hal/stubs.zig new file mode 100644 index 0000000..539660c --- /dev/null +++ b/hal/stubs.zig @@ -0,0 +1,195 @@ +// VOXIS FORGE // RUMPK L0 +// libc_stubs.zig +// We are the standard library now. +// +// These C ABI functions are exported so Nim's generated C code +// can link against them. No glibc. No musl. Pure sovereignty. + +// ========================================================= +// Memory Operations (Nim needs these) +// ========================================================= + +export fn memcpy(dest: [*]u8, src: [*]const u8, len: usize) [*]u8 { + var i: usize = 0; + while (i < len) : (i += 1) { + dest[i] = src[i]; + } + return dest; +} + +export fn memset(dest: [*]u8, val: c_int, len: usize) [*]u8 { + const v: u8 = @intCast(val & 0xFF); + var i: usize = 0; + while (i < len) : (i += 1) { + dest[i] = v; + } + return dest; +} + +export fn memmove(dest: [*]u8, src: [*]const u8, len: usize) [*]u8 { + if (@intFromPtr(dest) < @intFromPtr(src)) { + return memcpy(dest, src, len); + } + // Copy backwards for overlapping regions + var i: usize = len; + while (i > 0) { + i -= 1; + dest[i] = src[i]; + } + return dest; +} + +export fn memcmp(s1: [*]const u8, s2: [*]const u8, len: usize) c_int { + var i: usize = 0; + while (i < len) : (i += 1) { + if (s1[i] != s2[i]) { + return if (s1[i] < s2[i]) @as(c_int, -1) else @as(c_int, 1); + } + } + return 0; +} + +// ========================================================= +// String Operations +// ========================================================= + +export fn strlen(s: [*]const u8) usize { + var len: usize = 0; + while (s[len] != 0) : (len += 1) {} + return len; +} + +export fn strcpy(dest: [*]u8, src: [*]const u8) [*]u8 { + var i: usize = 0; + while (src[i] != 0) : (i += 1) { + dest[i] = src[i]; + } + dest[i] = 0; + return dest; +} + +export fn strcmp(s1: [*]const u8, s2: [*]const u8) c_int { + var i: usize = 0; + while (s1[i] != 0 and s1[i] == s2[i]) : (i += 1) {} + if (s1[i] == s2[i]) return 0; + return if (s1[i] < s2[i]) @as(c_int, -1) else @as(c_int, 1); +} + +// ========================================================= +// Heap Stubs (Bump Allocator) +// ========================================================= + +var heap_base: [64 * 1024]u8 = undefined; +var heap_offset: usize = 0; + +export fn malloc(size: usize) ?*anyopaque { + if (heap_offset + size > heap_base.len) { + return null; + } + const ptr = &heap_base[heap_offset]; + heap_offset += size; + // Align to 8 bytes + heap_offset = (heap_offset + 7) & ~@as(usize, 7); + return ptr; +} + +export fn free(ptr: ?*anyopaque) void { + // Bump allocator - no deallocation + _ = ptr; +} + +export fn realloc(ptr: ?*anyopaque, size: usize) ?*anyopaque { + // Simple realloc - just allocate new (wasteful but works for bootstrap) + _ = ptr; + return malloc(size); +} + +export fn calloc(nmemb: usize, size: usize) ?*anyopaque { + const total = nmemb * size; + const ptr = malloc(total); + if (ptr) |p| { + _ = memset(@ptrCast(p), 0, total); + } + return ptr; +} + +// ========================================================= +// Stdio Stubs (Route to UART) +// ========================================================= + +const uart = @import("uart.zig"); + +export fn puts(s: [*]const u8) c_int { + const len = strlen(s); + uart.write_bytes(s[0..len]); + uart.putc('\n'); + return 0; +} + +export fn putchar(c: c_int) c_int { + uart.putc(@intCast(c & 0xFF)); + return c; +} + +export fn printf(fmt: [*]const u8, ...) c_int { + // Minimal printf - just output format string + const len = strlen(fmt); + uart.write_bytes(fmt[0..len]); + return @intCast(len); +} + +export fn fprintf(stream: ?*anyopaque, fmt: [*]const u8, ...) c_int { + _ = stream; + return printf(fmt); +} + +export fn fflush(stream: ?*anyopaque) c_int { + _ = stream; + return 0; +} + +export fn fwrite(ptr: [*]const u8, size: usize, nmemb: usize, stream: ?*anyopaque) usize { + _ = stream; + uart.write_bytes(ptr[0 .. size * nmemb]); + return nmemb; +} + +// ========================================================= +// Signal Stubs (No signals in freestanding) +// ========================================================= + +export fn signal(signum: c_int, handler: ?*anyopaque) ?*anyopaque { + _ = signum; + _ = handler; + return null; +} + +export fn raise(sig: c_int) c_int { + _ = sig; + return 0; +} + +// ========================================================= +// Exit Stubs +// ========================================================= + +fn halt() noreturn { + while (true) { + asm volatile ("wfi"); + } +} + +export fn exit(status: c_int) noreturn { + _ = status; + uart.puts("[RUMPK] exit() called - halt\n"); + halt(); +} + +export fn abort() noreturn { + uart.puts("[RUMPK] abort() called - halt\n"); + halt(); +} + +export fn _Exit(status: c_int) noreturn { + exit(status); +}