feat(rumpk): Multi-Architecture HAL (aarch64, x86_64, riscv64)
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.
This commit is contained in:
parent
b8da01d879
commit
2f8a062a74
|
|
@ -1,5 +1,5 @@
|
||||||
0
|
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
|
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
|
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
|
268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
0
|
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
|
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
|
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
|
268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
0
|
||||||
|
1104 9461671 1767078085543858486 a0b42b3b0dd9bf113104ca6ca3c6f51d 0 /home/markus/zWork/_Git/Nexus/core/rumpk/hal/arch/aarch64/switch.S
|
||||||
117
build.sh
117
build.sh
|
|
@ -1,17 +1,52 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Rumpk Build Script - Freestanding Doctrine
|
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
# Pure Zig L0 + Nim L1, no C stubs, no glibc
|
# Rumpk Build Script - Multi-Architecture
|
||||||
#
|
# Supports: aarch64, x86_64, riscv64
|
||||||
# We are the standard library now.
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
RUMPK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
RUMPK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
BUILD_DIR="$RUMPK_DIR/build"
|
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 "╔═══════════════════════════════════════╗"
|
||||||
echo "║ RUMPK FREESTANDING BUILD v0.2 ║"
|
echo "║ RUMPK MULTI-ARCH BUILD v0.3 ║"
|
||||||
echo "║ No glibc. Pure Sovereignty. ║"
|
echo "║ Architecture: $ARCH "
|
||||||
echo "╚═══════════════════════════════════════╝"
|
echo "╚═══════════════════════════════════════╝"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
|
@ -20,49 +55,55 @@ mkdir -p "$BUILD_DIR"
|
||||||
mkdir -p "$BUILD_DIR/nimcache"
|
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
|
# Compile main.zig
|
||||||
zig build-obj \
|
zig build-obj \
|
||||||
"$RUMPK_DIR/hal/main.zig" \
|
"$RUMPK_DIR/hal/main.zig" \
|
||||||
-target aarch64-freestanding-none \
|
-target $ZIG_TARGET \
|
||||||
-O ReleaseSmall \
|
-O ReleaseSmall \
|
||||||
-femit-bin="$BUILD_DIR/hal.o"
|
-femit-bin="$BUILD_DIR/hal.o"
|
||||||
|
|
||||||
# Compile stubs.zig (our libc replacement)
|
# Compile stubs.zig
|
||||||
zig build-obj \
|
zig build-obj \
|
||||||
"$RUMPK_DIR/hal/stubs.zig" \
|
"$RUMPK_DIR/hal/stubs.zig" \
|
||||||
-target aarch64-freestanding-none \
|
-target $ZIG_TARGET \
|
||||||
-O ReleaseSmall \
|
-O ReleaseSmall \
|
||||||
-femit-bin="$BUILD_DIR/stubs.o"
|
-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/hal.o"
|
||||||
echo " → $BUILD_DIR/stubs.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"
|
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 \
|
nim c \
|
||||||
--cpu:arm64 \
|
--cpu:$NIM_CPU \
|
||||||
--os:any \
|
--os:any \
|
||||||
--mm:arc \
|
--mm:arc \
|
||||||
--noMain:on \
|
--noMain:on \
|
||||||
--cc:clang \
|
--cc:clang \
|
||||||
--passC:"-target aarch64-unknown-none -ffreestanding -fno-stack-protector -fno-builtin" \
|
--passC:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -ffreestanding -fno-stack-protector -fno-builtin" \
|
||||||
--passL:"-target aarch64-unknown-none -nostdlib -ffreestanding" \
|
--passL:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -nostdlib -ffreestanding" \
|
||||||
--define:useMalloc \
|
--define:useMalloc \
|
||||||
--define:StandaloneHeapSize=65536 \
|
--define:StandaloneHeapSize=65536 \
|
||||||
|
--define:$NIM_DEFINE \
|
||||||
-d:release \
|
-d:release \
|
||||||
-d:danger \
|
-d:danger \
|
||||||
--checks:off \
|
--checks:off \
|
||||||
|
|
@ -77,14 +118,14 @@ nim c \
|
||||||
echo " → $BUILD_DIR/nimcache/*.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
|
for cfile in "$BUILD_DIR/nimcache"/*.c; do
|
||||||
ofile="${cfile%.c}.o"
|
ofile="${cfile%.c}.o"
|
||||||
zig cc \
|
zig cc \
|
||||||
-target aarch64-freestanding-none \
|
-target $ZIG_TARGET \
|
||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
-fno-stack-protector \
|
-fno-stack-protector \
|
||||||
-fno-builtin \
|
-fno-builtin \
|
||||||
|
|
@ -99,11 +140,10 @@ done
|
||||||
echo " → $BUILD_DIR/nimcache/*.o"
|
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' ' ')
|
NIM_OBJS=$(find "$BUILD_DIR/nimcache" -name "*.o" 2>/dev/null | tr '\n' ' ')
|
||||||
|
|
||||||
if [ -z "$NIM_OBJS" ]; then
|
if [ -z "$NIM_OBJS" ]; then
|
||||||
|
|
@ -111,26 +151,29 @@ if [ -z "$NIM_OBJS" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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 \
|
zig cc \
|
||||||
-target aarch64-freestanding-none \
|
-target $ZIG_TARGET \
|
||||||
-nostdlib \
|
-nostdlib \
|
||||||
-T "$RUMPK_DIR/boot/linker.ld" \
|
-T "$LINKER_SCRIPT" \
|
||||||
"$BUILD_DIR/hal.o" \
|
"$BUILD_DIR/hal.o" \
|
||||||
"$BUILD_DIR/stubs.o" \
|
"$BUILD_DIR/stubs.o" \
|
||||||
"$BUILD_DIR/switch.o" \
|
"$BUILD_DIR/switch.o" \
|
||||||
$NIM_OBJS \
|
$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
|
# Done
|
||||||
# =========================================================
|
# =========================================================
|
||||||
echo ""
|
echo ""
|
||||||
echo "✅ Freestanding build complete!"
|
echo "✅ Build complete for $ARCH!"
|
||||||
echo ""
|
|
||||||
echo "Verification:"
|
|
||||||
echo " file $BUILD_DIR/rumpk.elf"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Run with:"
|
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"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,40 @@
|
||||||
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
# RUMPK CORE // FIBER
|
# RUMPK CORE // FIBER (Unified Multi-Arch)
|
||||||
# The atom of execution.
|
# 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.}
|
{.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
|
type
|
||||||
FiberState* = object
|
FiberState* = object
|
||||||
sp*: uint64 # The Stack Pointer (Must be first field!)
|
sp*: uint64 # The Stack Pointer (Must be first field!)
|
||||||
|
|
@ -17,7 +48,11 @@ type
|
||||||
stack*: ptr UncheckedArray[uint8]
|
stack*: ptr UncheckedArray[uint8]
|
||||||
stack_size*: int
|
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.}
|
proc cpu_switch_to(prev_sp_ptr: ptr uint64, next_sp: uint64) {.importc, cdecl.}
|
||||||
|
|
||||||
# Import console for debugging
|
# Import console for debugging
|
||||||
|
|
@ -27,17 +62,23 @@ proc debug(s: string) =
|
||||||
if s.len > 0:
|
if s.len > 0:
|
||||||
console_write(unsafeAddr s[0], csize_t(s.len))
|
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
|
const STACK_SIZE* = 4096
|
||||||
|
|
||||||
# We need a "Main" fiber to represent the boot thread
|
# =========================================================
|
||||||
|
# Fiber State
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
var main_fiber: FiberObject
|
var main_fiber: FiberObject
|
||||||
var current_fiber*: Fiber = addr main_fiber
|
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.} =
|
proc fiber_trampoline() {.cdecl, exportc, noreturn.} =
|
||||||
let f = current_fiber
|
let f = current_fiber
|
||||||
|
|
||||||
|
|
@ -45,8 +86,19 @@ proc fiber_trampoline() {.cdecl, exportc, noreturn.} =
|
||||||
f.state.entry()
|
f.state.entry()
|
||||||
|
|
||||||
# If the fiber returns, halt
|
# If the fiber returns, halt
|
||||||
|
when defined(amd64) or defined(x86_64):
|
||||||
|
while true:
|
||||||
|
{.emit: "asm volatile(\"hlt\");".}
|
||||||
|
elif defined(arm64) or defined(aarch64):
|
||||||
while true:
|
while true:
|
||||||
{.emit: "asm volatile(\"wfi\");".}
|
{.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) =
|
proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer) =
|
||||||
f.state.entry = entry
|
f.state.entry = entry
|
||||||
|
|
@ -54,27 +106,29 @@ proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer) =
|
||||||
# Start at top of stack
|
# Start at top of stack
|
||||||
var sp = cast[uint64](stack_base) + STACK_SIZE
|
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
|
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
|
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)
|
var stack_ptr = cast[ptr UncheckedArray[uint64]](sp)
|
||||||
|
|
||||||
# Zero out registers x19-x28 (indices 0-9)
|
# Zero out the frame
|
||||||
for i in 0..<10:
|
let num_regs = CONTEXT_SIZE div 8
|
||||||
|
for i in 0..<num_regs:
|
||||||
stack_ptr[i] = 0
|
stack_ptr[i] = 0
|
||||||
|
|
||||||
# Set x29 (FP) to 0 - Offset 80 / 8 = index 10
|
# Set return address to trampoline
|
||||||
stack_ptr[10] = 0
|
stack_ptr[RET_ADDR_INDEX] = cast[uint64](fiber_trampoline)
|
||||||
|
|
||||||
# Set x30 (LR) to trampoline - Offset 88 / 8 = index 11
|
|
||||||
stack_ptr[11] = cast[uint64](fiber_trampoline)
|
|
||||||
|
|
||||||
f.state.sp = sp
|
f.state.sp = sp
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Context Switch
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
proc switch*(next: Fiber) =
|
proc switch*(next: Fiber) =
|
||||||
let prev = current_fiber
|
let prev = current_fiber
|
||||||
current_fiber = next
|
current_fiber = next
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
# RUMPK HAL // AARCH64 CONSTANTS
|
||||||
|
|
||||||
|
# ARM64 Context Frame
|
||||||
|
# 6 register pairs (x19-x30) * 16 bytes = 96 bytes
|
||||||
|
# 16-byte aligned per ARM64 ABI
|
||||||
|
const CONTEXT_SIZE* = 96
|
||||||
|
|
||||||
|
# Register Layout in switch.S frame:
|
||||||
|
# [sp + 0] = x19, x20
|
||||||
|
# [sp + 16] = x21, x22
|
||||||
|
# [sp + 32] = x23, x24
|
||||||
|
# [sp + 48] = x25, x26
|
||||||
|
# [sp + 64] = x27, x28
|
||||||
|
# [sp + 80] = x29 (FP), x30 (LR/Return Address)
|
||||||
|
const LR_OFFSET* = 11 # x30 is at index 11 (88 bytes / 8)
|
||||||
|
const FP_OFFSET* = 10 # x29 is at index 10 (80 bytes / 8)
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
# RUMPK HAL // RISC-V 64 CONSTANTS
|
||||||
|
|
||||||
|
# RISC-V Context Frame
|
||||||
|
# ra + s0-s11 = 13 registers * 8 bytes = 104
|
||||||
|
# Aligned to 112 for 16-byte alignment
|
||||||
|
const CONTEXT_SIZE* = 112
|
||||||
|
|
||||||
|
# Stack layout after saves in switch.S:
|
||||||
|
# [sp + 0] = ra (return address)
|
||||||
|
# [sp + 8] = s0
|
||||||
|
# [sp + 16] = s1
|
||||||
|
# ...
|
||||||
|
# [sp + 96] = s11
|
||||||
|
|
||||||
|
const RA_OFFSET* = 0 # Return address at index 0
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
RUMPK HAL // RISC-V 64 CONTEXT SWITCH
|
||||||
|
|
||||||
|
RISC-V LP64 ABI Callee-Saved:
|
||||||
|
- ra (return address)
|
||||||
|
- s0-s11 (12 saved registers)
|
||||||
|
- fp (frame pointer, alias for s0)
|
||||||
|
|
||||||
|
Frame: 14 regs * 8 = 112 bytes (16-byte aligned)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.global cpu_switch_to
|
||||||
|
.type cpu_switch_to, @function
|
||||||
|
|
||||||
|
# void cpu_switch_to(uint64_t* prev_sp_ptr, uint64_t next_sp);
|
||||||
|
# a0 = prev_sp_ptr
|
||||||
|
# a1 = next_sp
|
||||||
|
|
||||||
|
cpu_switch_to:
|
||||||
|
# 1. Allocate Stack (112 bytes)
|
||||||
|
addi sp, sp, -112
|
||||||
|
|
||||||
|
# 2. Save Context (ra, s0-s11, fp)
|
||||||
|
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
|
||||||
|
|
||||||
|
# 3. Save Old SP
|
||||||
|
sd sp, 0(a0)
|
||||||
|
|
||||||
|
# 4. Load New SP
|
||||||
|
mv sp, a1
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
addi sp, sp, 112
|
||||||
|
ret
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
# RUMPK HAL // X86_64 CONSTANTS
|
||||||
|
|
||||||
|
# x86_64 Context Frame (System V ABI)
|
||||||
|
# 6 callee-saved: rbx, rbp, r12, r13, r14, r15
|
||||||
|
# Each 8 bytes = 48 bytes for regs
|
||||||
|
# + 8 bytes for return address (RIP)
|
||||||
|
# Total: 56 bytes, but we round to 64 for alignment
|
||||||
|
const CONTEXT_SIZE* = 56
|
||||||
|
|
||||||
|
# Stack layout after pushes in switch.S:
|
||||||
|
# [rsp + 0] = r15
|
||||||
|
# [rsp + 8] = r14
|
||||||
|
# [rsp + 16] = r13
|
||||||
|
# [rsp + 24] = r12
|
||||||
|
# [rsp + 32] = rbx
|
||||||
|
# [rsp + 40] = rbp
|
||||||
|
# [rsp + 48] = rip (return address, pushed by call or manually)
|
||||||
|
|
||||||
|
const RIP_OFFSET* = 6 # RIP at index 6 for init (48 / 8)
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
RUMPK HAL // X86_64 CONTEXT SWITCH
|
||||||
|
|
||||||
|
System V ABI (x86_64) Callee-Saved:
|
||||||
|
- rbx, rbp, r12, r13, r14, r15
|
||||||
|
- rip is saved by CALL instruction (on stack)
|
||||||
|
|
||||||
|
Frame: 6 regs * 8 = 48 bytes + 8 (RIP) = 56, aligned to 64
|
||||||
|
*/
|
||||||
|
|
||||||
|
.global cpu_switch_to
|
||||||
|
.type cpu_switch_to, @function
|
||||||
|
|
||||||
|
// void cpu_switch_to(uint64_t* prev_sp_ptr, uint64_t next_sp);
|
||||||
|
// rdi = prev_sp_ptr
|
||||||
|
// rsi = next_sp
|
||||||
|
|
||||||
|
cpu_switch_to:
|
||||||
|
// 1. Save Callee-Saved Registers (48 bytes)
|
||||||
|
pushq %rbp
|
||||||
|
pushq %rbx
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
|
||||||
|
// 2. Save Old Stack Pointer to *rdi
|
||||||
|
movq %rsp, (%rdi)
|
||||||
|
|
||||||
|
// 3. Load New Stack Pointer from rsi
|
||||||
|
movq %rsi, %rsp
|
||||||
|
|
||||||
|
// 4. Restore Callee-Saved Registers
|
||||||
|
popq %r15
|
||||||
|
popq %r14
|
||||||
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %rbx
|
||||||
|
popq %rbp
|
||||||
|
|
||||||
|
// 5. Return (pops RIP from stack)
|
||||||
|
ret
|
||||||
Loading…
Reference in New Issue