# 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: Fibers (The Sovereign Thread) # MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # Rumpk Phase 10: Multitasking & Context Switching # # Responsibilities: # - Define the Fiber abstraction (Hardware Context + Stack) # - Abstract the ISA-specific context switch mechanism # - Provide a high-level API for yielding and scheduling {.push stackTrace: off, lineTrace: off.} # Architecture Configuration # ========================================================= when defined(riscv64): const ARCH_NAME* = "riscv64" const CONTEXT_SIZE* = 128 const RET_ADDR_INDEX* = 0 # Offset in stack for RA elif defined(amd64) or defined(x86_64): const ARCH_NAME* = "amd64" const CONTEXT_SIZE* = 64 const RET_ADDR_INDEX* = 0 else: {.error: "Unsupported Architecture".} # --- FIBER DEFINITION --- type Spectrum* {.pure.} = enum Void = 0, # Default/Uninitialized Photon = 1, # Real-time (0-1ms latency) Matter = 2, # Interactive (1-10ms latency) Gravity = 3, # Batch/Idle (100ms+ latency) 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 # Ground Zero Phase 3: Typed Channels & I/O Multiplexing blocked_on_mask*: uint64 # Bitmask of capability slots fiber is waiting on is_blocked*: bool # True if fiber is waiting for I/O # 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.} proc debug(s: string) = proc console_write(p: pointer, len: int) {.importc, cdecl.} if s.len > 0: console_write(unsafeAddr s[0], 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" # We can't use kprintln here if it's not imported or we use emit proc console_write(p: pointer, len: int) {.importc, cdecl.} console_write(addr msg[0], msg.len) let f = current_fiber if f.state.entry != nil: f.state.entry() # If the fiber returns, halt when defined(riscv64): while true: {.emit: "asm volatile(\"wfi\");".} else: while true: discard # ========================================================= # 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 f.blocked_on_mask = 0 f.is_blocked = false # 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..