# SPDX-License-Identifier: LSL-1.0 # Copyright (c) 2026 Markus Maiwald # Stewardship: Self Sovereign Society Foundation # # This file is part of the Nexus Sovereign Core. # See legal/LICENSE_SOVEREIGN.md for license terms. ## Rumpk Layer 1: Fiber Execution (Motive Power) ## ## Implements the unified multi-arch fiber context switching. ## Supported Architectures: x86_64, AArch64, RISC-V. ## ## SAFETY: Direct manipulation of stack pointers and CPU registers via ## architecture-specific context frames. Swaps page tables during switch. {.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 = 128 const RET_ADDR_INDEX = 0 # ra at [sp + 0] const ARCH_NAME = "riscv64" else: {.error: "Unsupported architecture for Rumpk fibers".} # ========================================================= # Types # ========================================================= type Spectrum* = enum Photon = 0 # UI/Audio (Top Tier) Matter = 1 # Interactive (Middle Tier) Gravity = 2 # Batch (Bottom Tier) Void = 3 # Unclassified/Demoted (Default) FiberState* = object sp*: uint64 # The Stack Pointer (Must be first field!) entry*: proc() {.cdecl.} # Entry point for this fiber Fiber* = ptr FiberObject FiberObject* = object id*: uint64 name*: cstring state*: FiberState stack*: ptr UncheckedArray[uint8] phys_offset*: uint64 # Cellular Memory Offset stack_size*: int sleep_until*: uint64 # NS timestamp promises*: uint64 # [63:62]=Spectrum, [61:0]=Pledge bits pledge_budget*: uint64 # Microseconds allowed per frame (legacy) avg_burst*: uint64 # Moving average for telemetry (The Ratchet) user_entry*: pointer # Phase 29: User function pointer for workers user_arg*: uint64 # Phase 29: Argument for user function satp_value*: uint64 # Phase 31: Page table root (0 = use kernel map) wants_yield*: bool # Phase 37: Deferred yield flag # SPEC-102: The Ratchet budget_ns*: uint64 # "I promise to run for X ns max" last_burst_ns*: uint64 # Actual execution time of last run violations*: uint32 # Strike counter (3 strikes = demotion) pty_id*: int # Phase 40: Assigned PTY ID (-1 if none) user_sp_init*: uint64 # Initial SP for userland entry # Ground Zero Phase 1: Capability Space (SPEC-051) cspace_id*: uint64 # Index into global CSpace table # Spectrum Accessors proc getSpectrum*(f: Fiber): Spectrum = if f == nil: return Spectrum.Void Spectrum((f.promises shr 62) and 0x3) proc setSpectrum*(f: Fiber, s: Spectrum) = if f == nil: return f.promises = (f.promises and 0x3FFFFFFFFFFFFFFF'u64) or (uint64(s) shl 62) proc fiber_yield*() {.importc, cdecl.} # 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.} # Phase 31: Page Table Activation proc mm_activate_satp(satp_val: uint64) {.importc, cdecl.} proc mm_get_kernel_satp(): uint64 {.importc, cdecl.} # Import console for debugging proc console_write(p: pointer, len: csize_t) {.importc, cdecl.} proc debug*(s: string) = if s.len > 0: console_write(unsafeAddr s[0], csize_t(s.len)) proc print_arch_info*() = debug("[Rumpk] Architecture Context: " & ARCH_NAME & "\n") # ========================================================= # Constants # ========================================================= const STACK_SIZE* = 4096 # ========================================================= # Fiber State # ========================================================= var main_fiber: FiberObject var current_fiber* {.global.}: Fiber = addr main_fiber # ========================================================= # Trampoline (Entry point for new fibers) # ========================================================= proc fiber_trampoline() {.cdecl, exportc, noreturn.} = var msg = "[FIBER] Trampoline Entry!\n" console_write(addr msg[0], csize_t(msg.len)) let f = current_fiber if f.state.entry != nil: f.state.entry() # 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: {.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, size: int) = f.state.entry = entry f.stack = cast[ptr UncheckedArray[uint8]](stack_base) f.stack_size = size f.sleep_until = 0 f.pty_id = -1 f.user_sp_init = 0 f.cspace_id = f.id # Ground Zero: CSpace ID matches Fiber ID # Start at top of stack (using actual size) var sp = cast[uint64](stack_base) + cast[uint64](size) # 1. Align to 16 bytes (Universal requirement) sp = sp and not 15'u64 # 2. Reserve space for the context frame sp = sp - CONTEXT_SIZE # 3. Setup the Context (zero all, set return address) var stack_ptr = cast[ptr UncheckedArray[uint64]](sp) # Zero out the frame let num_regs = CONTEXT_SIZE div 8 for i in 0..