feat(kernel): implement System Truth Ledger and Causal Trace
- Implemented System Ontology (SPEC-060) and STL (SPEC-061) in Zig HAL - Created Nim bindings and high-level event emission API - Integrated STL into kernel boot sequence (SystemBoot, FiberSpawn, CapGrant) - Implemented Causal Graph Engine (SPEC-062) for lineage tracing - Verified self-aware causal auditing in boot logs - Optimized Event structure to 58 bytes for cache efficiency
This commit is contained in:
parent
bf427290f1
commit
3779197eb9
|
|
@ -0,0 +1,96 @@
|
|||
# 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.
|
||||
|
||||
# SPEC-051: CSpace Integration with Fiber Control Block
|
||||
# Ground Zero Phase 1: Kernel Integration
|
||||
|
||||
## CSpace Nim Bindings
|
||||
|
||||
# Kernel logging (freestanding-safe)
|
||||
proc kprintln(s: cstring) {.importc, cdecl.}
|
||||
|
||||
# Import CSpace from HAL
|
||||
proc cspace_init*() {.importc, cdecl.}
|
||||
proc cspace_get*(fiber_id: uint64): pointer {.importc, cdecl.}
|
||||
proc cspace_grant_cap*(
|
||||
fiber_id: uint64,
|
||||
cap_type: uint8,
|
||||
perms: uint8,
|
||||
object_id: uint64,
|
||||
bounds_start: uint64,
|
||||
bounds_end: uint64
|
||||
): int32 {.importc, cdecl.}
|
||||
proc cspace_lookup*(fiber_id: uint64, slot: uint): pointer {.importc, cdecl.}
|
||||
proc cspace_revoke*(fiber_id: uint64, slot: uint) {.importc, cdecl.}
|
||||
proc cspace_check_perm*(fiber_id: uint64, slot: uint, perm_bits: uint8): bool {.importc, cdecl.}
|
||||
|
||||
## Capability Types (Mirror from cspace.zig)
|
||||
type
|
||||
CapType* = enum
|
||||
CapNull = 0
|
||||
CapEntity = 1
|
||||
CapChannel = 2
|
||||
CapMemory = 3
|
||||
CapInterrupt = 4
|
||||
CapTime = 5
|
||||
CapEntropy = 6
|
||||
|
||||
## Permission Flags
|
||||
const
|
||||
PERM_READ* = 0x01'u8
|
||||
PERM_WRITE* = 0x02'u8
|
||||
PERM_EXECUTE* = 0x04'u8
|
||||
PERM_MAP* = 0x08'u8
|
||||
PERM_DELEGATE* = 0x10'u8
|
||||
PERM_REVOKE* = 0x20'u8
|
||||
PERM_COPY* = 0x40'u8
|
||||
PERM_SPAWN* = 0x80'u8
|
||||
|
||||
## High-level API for kernel use
|
||||
|
||||
proc fiber_grant_channel*(fiber_id: uint64, channel_id: uint64, perms: uint8): int32 =
|
||||
## Grant a Channel capability to a fiber
|
||||
return cspace_grant_cap(
|
||||
fiber_id,
|
||||
uint8(CapChannel),
|
||||
perms,
|
||||
channel_id,
|
||||
0, # No bounds for channels
|
||||
0
|
||||
)
|
||||
|
||||
proc fiber_grant_memory*(
|
||||
fiber_id: uint64,
|
||||
region_id: uint64,
|
||||
start_addr: uint64,
|
||||
end_addr: uint64,
|
||||
perms: uint8
|
||||
): int32 =
|
||||
## Grant a Memory capability to a fiber
|
||||
return cspace_grant_cap(
|
||||
fiber_id,
|
||||
uint8(CapMemory),
|
||||
perms,
|
||||
region_id,
|
||||
start_addr,
|
||||
end_addr
|
||||
)
|
||||
|
||||
proc fiber_check_channel_access*(fiber_id: uint64, slot: uint, write: bool): bool =
|
||||
## Check if fiber has channel access via capability
|
||||
let perm = if write: PERM_WRITE else: PERM_READ
|
||||
return cspace_check_perm(fiber_id, slot, perm)
|
||||
|
||||
proc fiber_revoke_capability*(fiber_id: uint64, slot: uint) =
|
||||
## Revoke a capability from a fiber
|
||||
cspace_revoke(fiber_id, slot)
|
||||
|
||||
## Initialization
|
||||
proc init_cspace_subsystem*() =
|
||||
## Initialize the CSpace subsystem (call from kmain)
|
||||
cspace_init()
|
||||
kprintln("[CSpace] Capability system initialized")
|
||||
|
|
@ -58,6 +58,7 @@ type
|
|||
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
|
||||
|
|
@ -67,12 +68,14 @@ type
|
|||
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-250: The Ratchet
|
||||
# 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 =
|
||||
|
|
@ -151,6 +154,7 @@ proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer, size: i
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ proc vfs_add_mount(prefix: cstring, mode: VFSMode) =
|
|||
mnt_count += 1
|
||||
|
||||
proc vfs_mount_init*() =
|
||||
# Restore the SPEC-130 baseline
|
||||
# Restore the SPEC-502 baseline
|
||||
vfs_add_mount("/nexus", MODE_SFS)
|
||||
vfs_add_mount("/sysro", MODE_TAR)
|
||||
vfs_add_mount("/state", MODE_RAM)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ type
|
|||
# Phase 35e: Crypto
|
||||
fn_siphash*: proc(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.cdecl.}
|
||||
fn_ed25519_verify*: proc(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.cdecl.}
|
||||
# SPEC-021: Monolith Key Derivation
|
||||
# SPEC-503: Monolith Key Derivation
|
||||
fn_blake3*: proc(data: pointer, len: uint64, out_hash: ptr array[32, byte]) {.cdecl.}
|
||||
|
||||
# Phase 36.2: Network Membrane (The Veins)
|
||||
|
|
|
|||
100
core/kernel.nim
100
core/kernel.nim
|
|
@ -1,7 +1,14 @@
|
|||
# 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.
|
||||
|
||||
# Nexus Sovereign Core: Kernel Implementation
|
||||
# target Bravo: Complete Build Unification
|
||||
|
||||
import ion, fiber, sched, pty
|
||||
import ion, fiber, sched, pty, cspace, ontology
|
||||
import fs/vfs, fs/tar, fs/sfs
|
||||
import loader/elf
|
||||
import ../libs/membrane/term
|
||||
|
|
@ -139,19 +146,22 @@ proc kload_phys(path: cstring, phys_offset: uint64): uint64 =
|
|||
{.emit: """asm volatile ("li t1, 0x40000; csrs sstatus, t1" : : : "t1");""" .}
|
||||
|
||||
let dest = cast[ptr UncheckedArray[byte]](phdr.p_vaddr)
|
||||
|
||||
|
||||
if phdr.p_filesz > 0:
|
||||
if tar.vfs_read_at(tar_path, dest, phdr.p_filesz, phdr.p_offset) != int64(phdr.p_filesz):
|
||||
kprintln("[Loader] Error: Segment load failed")
|
||||
|
||||
if phdr.p_memsz > phdr.p_filesz:
|
||||
let bss_start = cast[uint64](dest) + phdr.p_filesz
|
||||
let bss_start = phdr.p_vaddr + phdr.p_filesz
|
||||
let bss_len = phdr.p_memsz - phdr.p_filesz
|
||||
kprint(" - Zeroing BSS: VA="); kprint_hex(bss_start); kprint(" Len="); kprint_hex(bss_len); kprintln("")
|
||||
k_zero_mem(cast[pointer](bss_start), bss_len)
|
||||
|
||||
{.emit: """asm volatile ("li t1, 0x40000; csrc sstatus, t1" : : : "t1");""" .}
|
||||
|
||||
# ⚡ ARCH-SYNC: Flush I-Cache after loading new code
|
||||
{.emit: """asm volatile ("fence.i" : : : "memory");""" .}
|
||||
|
||||
discard ion_vfs_close(fd)
|
||||
return ehdr.e_entry
|
||||
|
||||
|
|
@ -159,20 +169,21 @@ proc kload_phys(path: cstring, phys_offset: uint64): uint64 =
|
|||
|
||||
proc subject_fiber_entry() {.cdecl.} =
|
||||
let fid = current_fiber.id
|
||||
kprint("[Subject:"); kprint_hex(fid); kprintln("] Fiber Entry reached.")
|
||||
kprint("[Subject:"); kprint_hex(fid); kprint("] Fiber Entry reached. PA_Offset="); kprint_hex(current_fiber.phys_offset); kprintln("")
|
||||
|
||||
# Use new robust loader
|
||||
kprint("[Loader:"); kprint_hex(fid); kprint("] Loading: "); kprintln(cast[cstring](addr subject_loading_path[0]))
|
||||
|
||||
let entry_addr = kload_phys(cast[cstring](addr subject_loading_path[0]), 0)
|
||||
# Load into Cellular Slot (phys_offset)
|
||||
let entry_addr = kload_phys(cast[cstring](addr subject_loading_path[0]), current_fiber.phys_offset)
|
||||
|
||||
if entry_addr != 0:
|
||||
kprint("[Subject:"); kprint_hex(fid); kprint("] Entering Payload at: "); kprint_hex(entry_addr); kprintln("")
|
||||
proc hal_enter_userland(entry, systable, sp: uint64) {.importc, cdecl.}
|
||||
var sp = current_fiber.user_sp_init
|
||||
if sp == 0:
|
||||
# Fallback (Legacy/Init)
|
||||
sp = 0x8FFFFEE0'u64
|
||||
# Fallback (Legacy/Init) - Top of the 64MB Sentinel Cell
|
||||
sp = 0x8BFFFFF0'u64
|
||||
|
||||
kprint("[Subject:"); kprint_hex(fid); kprint("] JUMPING to Userland. SP="); kprint_hex(sp); kprintln("")
|
||||
hal_enter_userland(entry_addr, SYSTABLE_BASE, sp)
|
||||
|
|
@ -189,7 +200,7 @@ proc compositor_fiber_entry() {.cdecl.} =
|
|||
term.term_render()
|
||||
fiber_sleep(33) # 30Hz
|
||||
|
||||
proc mm_create_worker_map(stack_base: uint64, stack_size: uint64, packet_addr: uint64, code_base_pa: uint64): uint64 {.importc, cdecl.}
|
||||
proc mm_create_worker_map(stack_base: uint64, stack_size: uint64, packet_addr: uint64, phys_base: uint64, region_size: uint64): uint64 {.importc, cdecl.}
|
||||
|
||||
proc setup_mksh_stack(stack_base: pointer, stack_size: int): uint64 =
|
||||
var sp = cast[uint64](stack_base) + cast[uint64](stack_size)
|
||||
|
|
@ -264,7 +275,15 @@ proc ion_fiber_entry() {.cdecl.} =
|
|||
fiber_child.pty_id = pid
|
||||
fiber_child.user_sp_init = setup_mksh_stack(addr stack_child[0], sizeof(stack_child))
|
||||
|
||||
fiber_child.satp_value = mm_create_worker_map(cast[uint64](addr stack_child[0]), uint64(sizeof(stack_child)), SYSTABLE_BASE, 0x90000000'u64)
|
||||
# 🏛️ CELLULAR ALLOCATION (SPEC-202 Rev 2)
|
||||
# Sentinel (Init) takes 0x88000000 - 0x8C000000 (64MB)
|
||||
# Mksh (First Child) starts in the 'Wild' at 0x8C000000
|
||||
let cell_base = 0x8C000000'u64
|
||||
fiber_child.phys_offset = cell_base
|
||||
|
||||
# Allocate 64MB Slot for Mksh (Needs >32MB for BSS)
|
||||
let cell_size = 64 * 1024 * 1024'u64
|
||||
fiber_child.satp_value = mm_create_worker_map(cast[uint64](addr stack_child[0]), uint64(sizeof(stack_child)), SYSTABLE_BASE, cell_base, cell_size)
|
||||
kprintln("[ION] Child fiber spawned successfully")
|
||||
else: discard
|
||||
fiber_sleep(10)
|
||||
|
|
@ -274,10 +293,11 @@ proc fiber_yield*() {.exportc, cdecl.} =
|
|||
rumpk_yield_guard()
|
||||
|
||||
proc rumpk_yield_internal*() {.exportc, cdecl.} =
|
||||
if not sched_tick_spectrum(active_fibers_arr.toOpenArray(0, 4)):
|
||||
# Schedule fibers 0-5 (ION, NexShell, Compositor, NetSwitch, Init, Mksh)
|
||||
if not sched_tick_spectrum(active_fibers_arr.toOpenArray(0, 5)):
|
||||
# No runnable fibers (all sleeping).
|
||||
# Return to Dispatcher (Main Fiber) to enter sleep/wfi mode.
|
||||
switch(active_fibers_arr[5])
|
||||
# Return to Dispatcher (Main Fiber) at index 6 to enter sleep/wfi mode.
|
||||
switch(active_fibers_arr[6])
|
||||
|
||||
proc fiber_netswitch_entry() {.cdecl.} =
|
||||
kprintln("[NetSwitch] Traffic Engine Online")
|
||||
|
|
@ -337,8 +357,13 @@ proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
|||
discard chan_cmd.send(pkt)
|
||||
current_fiber.wants_yield = true
|
||||
return 0
|
||||
of 0x65: # NANOSLEEP
|
||||
let now = sched_get_now_ns()
|
||||
current_fiber.sleep_until = now + a0
|
||||
fiber_yield()
|
||||
return 0
|
||||
of 0x100: # YIELD
|
||||
current_fiber.wants_yield = true
|
||||
fiber_yield()
|
||||
return 0
|
||||
of 0x200: # OPEN
|
||||
# return uint(libc_impl.libc_impl_open(cast[cstring](a0), int(a1)))
|
||||
|
|
@ -424,6 +449,14 @@ proc kmain() {.exportc, cdecl.} =
|
|||
mm_init()
|
||||
mm_enable_kernel_paging()
|
||||
|
||||
# Ground Zero Phase 1: Initialize Capability System (SPEC-051)
|
||||
init_cspace_subsystem()
|
||||
kprintln("[CSpace] Capability system initialized")
|
||||
|
||||
# Ground Zero Phase 2: Initialize System Truth Ledger (SPEC-060)
|
||||
init_stl_subsystem()
|
||||
let boot_id = emit_system_boot()
|
||||
|
||||
ion_init_input()
|
||||
hal_io_init()
|
||||
pty_init()
|
||||
|
|
@ -482,13 +515,41 @@ proc kmain() {.exportc, cdecl.} =
|
|||
fiber_subject.id = 4; fiber_child.id = 5
|
||||
|
||||
init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion))
|
||||
init_fiber(addr fiber_compositor, compositor_fiber_entry, addr stack_compositor[0], sizeof(stack_compositor))
|
||||
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell))
|
||||
init_fiber(addr fiber_netswitch, fiber_netswitch_entry, addr stack_netswitch[0], sizeof(stack_netswitch))
|
||||
let ion_spawn_id = emit_fiber_spawn(1, 0, boot_id) # ION fiber
|
||||
discard ion_spawn_id
|
||||
|
||||
init_fiber(addr fiber_compositor, compositor_fiber_entry, addr stack_compositor[0], sizeof(stack_compositor))
|
||||
let compositor_spawn_id = emit_fiber_spawn(3, 0, boot_id) # Compositor fiber
|
||||
discard compositor_spawn_id
|
||||
|
||||
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell))
|
||||
let shell_spawn_id = emit_fiber_spawn(2, 0, boot_id) # NexShell fiber
|
||||
|
||||
init_fiber(addr fiber_netswitch, fiber_netswitch_entry, addr stack_netswitch[0], sizeof(stack_netswitch))
|
||||
let netswitch_spawn_id = emit_fiber_spawn(6, 0, boot_id) # NetSwitch fiber
|
||||
discard netswitch_spawn_id
|
||||
|
||||
proc mm_create_worker_map(stack_base: uint64, stack_size: uint64, packet_addr: uint64, code_base_pa: uint64): uint64 {.importc, cdecl.}
|
||||
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0], sizeof(stack_subject))
|
||||
fiber_subject.satp_value = mm_create_worker_map(cast[uint64](addr stack_subject[0]), uint64(sizeof(stack_subject)), SYSTABLE_BASE, 0x88000000'u64)
|
||||
let subject_spawn_id = emit_fiber_spawn(4, 0, boot_id) # Subject fiber
|
||||
|
||||
# Ground Zero Phase 1: Grant Initial Capabilities (SPEC-051)
|
||||
# Grant console I/O to NexShell (fiber 2)
|
||||
discard fiber_grant_channel(2, 0x1000, PERM_READ or PERM_WRITE) # console.input
|
||||
discard emit_capability_grant(2, 2, 0x1000, 0, shell_spawn_id) # Log event
|
||||
|
||||
discard fiber_grant_channel(2, 0x1001, PERM_READ or PERM_WRITE) # console.output
|
||||
discard emit_capability_grant(2, 2, 0x1001, 1, shell_spawn_id) # Log event
|
||||
kprintln("[CSpace] Granted console capabilities to NexShell")
|
||||
|
||||
# Grant console output to Subject (fiber 4)
|
||||
discard fiber_grant_channel(4, 0x1001, PERM_WRITE) # console.output (write-only)
|
||||
discard emit_capability_grant(4, 2, 0x1001, 0, subject_spawn_id) # Log event
|
||||
kprintln("[CSpace] Granted output capability to Subject")
|
||||
|
||||
# Init (Subject) lives in Cell 0 (0x88000000) - Needs 64MB for large BSS
|
||||
fiber_subject.phys_offset = 0x88000000'u64
|
||||
let init_size = 64 * 1024 * 1024'u64
|
||||
fiber_subject.satp_value = mm_create_worker_map(cast[uint64](addr stack_subject[0]), uint64(sizeof(stack_subject)), SYSTABLE_BASE, fiber_subject.phys_offset, init_size)
|
||||
|
||||
# Interrupt Setup
|
||||
asm "csrsi sstatus, 2"
|
||||
|
|
@ -512,6 +573,9 @@ proc kmain() {.exportc, cdecl.} =
|
|||
(addr fiber_subject).setSpectrum(Spectrum.Void) # Untrusted Background
|
||||
(addr fiber_child).setSpectrum(Spectrum.Void) # Child process (spawned)
|
||||
current_fiber.setSpectrum(Spectrum.Void) # Main loop (dispatcher)
|
||||
|
||||
# Ground Zero Phase 2: Introspection
|
||||
stl_print_summary()
|
||||
|
||||
kprintln("[Rumpk] Multi-Fiber Dispatcher starting...")
|
||||
switch(addr fiber_ion)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ proc netswitch_process_packet(pkt: IonPacket): bool =
|
|||
return false
|
||||
return true
|
||||
|
||||
of 0x88B5: # Sovereign UTCP (SPEC-410)
|
||||
of 0x88B5: # Sovereign UTCP (SPEC-700)
|
||||
# TODO: Route to dedicated UTCP channel
|
||||
# kprintln("[NetSwitch] UTCP Sovereign Packet Identified")
|
||||
ion_free(pkt)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
# 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.
|
||||
|
||||
# SPEC-060: System Ontology - Nim Bindings
|
||||
# Ground Zero Phase 2: Event System
|
||||
|
||||
## Event System Nim Bindings
|
||||
|
||||
# Kernel logging (freestanding-safe)
|
||||
proc kprint(s: cstring) {.importc, cdecl.}
|
||||
proc kprint_hex(n: uint64) {.importc, cdecl.}
|
||||
proc kprintln(s: cstring) {.importc, cdecl.}
|
||||
|
||||
# Import STL from HAL
|
||||
proc stl_init*() {.importc, cdecl.}
|
||||
proc stl_emit*(
|
||||
kind: uint16,
|
||||
fiber_id: uint64,
|
||||
entity_id: uint64,
|
||||
cause_id: uint64,
|
||||
data0: uint64,
|
||||
data1: uint64,
|
||||
data2: uint64
|
||||
): uint64 {.importc, cdecl.}
|
||||
proc stl_lookup*(event_id: uint64): pointer {.importc, cdecl.}
|
||||
proc stl_count*(): uint32 {.importc, cdecl.}
|
||||
|
||||
type
|
||||
QueryResult* = object
|
||||
count*: uint32
|
||||
events*: array[64, pointer]
|
||||
|
||||
proc stl_query_by_fiber*(fiber_id: uint64, result: var QueryResult) {.importc, cdecl.}
|
||||
proc stl_query_by_kind*(kind: uint16, result: var QueryResult) {.importc, cdecl.}
|
||||
proc stl_get_recent*(max_count: uint32, result: var QueryResult) {.importc, cdecl.}
|
||||
|
||||
type
|
||||
LineageResult* = object
|
||||
count*: uint32
|
||||
event_ids*: array[16, uint64]
|
||||
|
||||
proc stl_trace_lineage*(event_id: uint64, result: var LineageResult) {.importc, cdecl.}
|
||||
|
||||
## Event Types (Mirror from ontology.zig)
|
||||
type
|
||||
EventKind* = enum
|
||||
EvNull = 0
|
||||
# Lifecycle
|
||||
EvSystemBoot = 1
|
||||
EvSystemShutdown = 2
|
||||
EvFiberSpawn = 3
|
||||
EvFiberTerminate = 4
|
||||
# Capability
|
||||
EvCapabilityGrant = 10
|
||||
EvCapabilityRevoke = 11
|
||||
EvCapabilityDelegate = 12
|
||||
# I/O
|
||||
EvChannelOpen = 20
|
||||
EvChannelClose = 21
|
||||
EvChannelRead = 22
|
||||
EvChannelWrite = 23
|
||||
# Memory
|
||||
EvMemoryAllocate = 30
|
||||
EvMemoryFree = 31
|
||||
EvMemoryMap = 32
|
||||
# Network
|
||||
EvNetworkPacketRx = 40
|
||||
EvNetworkPacketTx = 41
|
||||
# Security
|
||||
EvAccessDenied = 50
|
||||
EvPolicyViolation = 51
|
||||
|
||||
## High-level API for kernel use
|
||||
|
||||
proc emit_system_boot*(): uint64 =
|
||||
## Emit system boot event
|
||||
return stl_emit(
|
||||
uint16(EvSystemBoot),
|
||||
0, # fiber_id (kernel)
|
||||
0, # entity_id
|
||||
0, # cause_id
|
||||
0, 0, 0 # data
|
||||
)
|
||||
|
||||
proc emit_fiber_spawn*(fiber_id: uint64, parent_id: uint64, cause_id: uint64 = 0): uint64 =
|
||||
## Emit fiber spawn event
|
||||
return stl_emit(
|
||||
uint16(EvFiberSpawn),
|
||||
parent_id,
|
||||
fiber_id,
|
||||
cause_id,
|
||||
0, 0, 0
|
||||
)
|
||||
|
||||
proc emit_capability_grant*(
|
||||
fiber_id: uint64,
|
||||
cap_type: uint8,
|
||||
object_id: uint64,
|
||||
slot: uint32,
|
||||
cause_id: uint64 = 0
|
||||
): uint64 =
|
||||
## Emit capability grant event
|
||||
return stl_emit(
|
||||
uint16(EvCapabilityGrant),
|
||||
fiber_id,
|
||||
object_id,
|
||||
cause_id,
|
||||
uint64(cap_type),
|
||||
uint64(slot),
|
||||
0
|
||||
)
|
||||
|
||||
proc emit_channel_write*(
|
||||
fiber_id: uint64,
|
||||
channel_id: uint64,
|
||||
bytes_written: uint64,
|
||||
cause_id: uint64 = 0
|
||||
): uint64 =
|
||||
## Emit channel write event
|
||||
return stl_emit(
|
||||
uint16(EvChannelWrite),
|
||||
fiber_id,
|
||||
channel_id,
|
||||
cause_id,
|
||||
bytes_written,
|
||||
0, 0
|
||||
)
|
||||
|
||||
proc emit_access_denied*(
|
||||
fiber_id: uint64,
|
||||
resource_id: uint64,
|
||||
attempted_perm: uint8,
|
||||
cause_id: uint64 = 0
|
||||
): uint64 =
|
||||
## Emit access denied event (security)
|
||||
return stl_emit(
|
||||
uint16(EvAccessDenied),
|
||||
fiber_id,
|
||||
resource_id,
|
||||
cause_id,
|
||||
uint64(attempted_perm),
|
||||
0, 0
|
||||
)
|
||||
|
||||
## Initialization
|
||||
proc init_stl_subsystem*() =
|
||||
## Initialize the STL subsystem (call from kmain)
|
||||
stl_init()
|
||||
kprintln("[STL] System Truth Ledger initialized")
|
||||
|
||||
## Query API
|
||||
proc stl_print_summary*() =
|
||||
## Print a summary of the STL ledger to the console
|
||||
kprintln("\n[STL] Event Summary:")
|
||||
let total = stl_count()
|
||||
kprint("[STL] Total Events: "); kprint_hex(uint64(total)); kprintln("")
|
||||
|
||||
var res: QueryResult
|
||||
|
||||
# Boot Events
|
||||
stl_query_by_kind(uint16(EvSystemBoot), res)
|
||||
kprint("[STL] SystemBoot: "); kprint_hex(uint64(res.count)); kprintln("")
|
||||
|
||||
# Fiber Spawn
|
||||
stl_query_by_kind(uint16(EvFiberSpawn), res)
|
||||
kprint("[STL] FiberSpawn: "); kprint_hex(uint64(res.count)); kprintln("")
|
||||
|
||||
# Cap Grants
|
||||
stl_query_by_kind(uint16(EvCapabilityGrant), res)
|
||||
kprint("[STL] CapGrant: "); kprint_hex(uint64(res.count)); kprintln("")
|
||||
|
||||
# Demonstrate Lineage Tracing for the last event
|
||||
if total > 0:
|
||||
let last_id = uint64(total - 1)
|
||||
var lineage: LineageResult
|
||||
stl_trace_lineage(last_id, lineage)
|
||||
|
||||
kprint("[STL] Lineage Trace for Event "); kprint_hex(last_id); kprintln(":")
|
||||
for i in 0..<lineage.count:
|
||||
let eid = lineage.event_ids[i]
|
||||
let ev_ptr = stl_lookup(eid)
|
||||
if ev_ptr != nil:
|
||||
# We can't easily access fields of Event struct from Nim if it's packed in Zig
|
||||
# but we know kind is at offset 0 (2 bytes)
|
||||
let kind = cast[ptr uint16](ev_ptr)[]
|
||||
kprint(" <- ["); kprint_hex(eid); kprint("] Kind="); kprint_hex(uint64(kind)); kprintln("")
|
||||
else:
|
||||
kprint(" <- ["); kprint_hex(eid); kprintln("] (Lookup Failed)")
|
||||
|
||||
kprintln("[STL] Summary complete.")
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
## Rumpk Layer 1: The Reactive Dispatcher (The Tyrant)
|
||||
##
|
||||
## Implements the Silence Doctrine (SPEC-250).
|
||||
## Implements the Silence Doctrine (SPEC-102).
|
||||
## - No Tick.
|
||||
## - No Policy.
|
||||
## - Only Physics.
|
||||
|
|
@ -36,7 +36,7 @@ import fiber
|
|||
|
||||
# To avoid circular imports, kernel.nim will likely INCLUDE sched.nim or sched.nim
|
||||
# will act on a passed context.
|
||||
# BUT, SPEC-250 implies sched.nim *is* the logic.
|
||||
# BUT, SPEC-102 implies sched.nim *is* the logic.
|
||||
#
|
||||
# Let's define the Harmonic logic.
|
||||
# We need access to `current_fiber` (from fiber.nim) and `get_now_ns` (helper).
|
||||
|
|
|
|||
14
hal/abi.zig
14
hal/abi.zig
|
|
@ -82,3 +82,17 @@ export fn rumpk_timer_now_ns() u64 {
|
|||
mock_ticks += 100000; // 100us per call
|
||||
return mock_ticks;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Ground Zero Phase 1: CSpace Integration (SPEC-020)
|
||||
// =========================================================
|
||||
|
||||
pub const cspace = @import("cspace.zig");
|
||||
|
||||
// Re-export CSpace functions for Nim FFI
|
||||
pub const cspace_init = cspace.cspace_init;
|
||||
pub const cspace_get = cspace.cspace_get;
|
||||
pub const cspace_grant_cap = cspace.cspace_grant_cap;
|
||||
pub const cspace_lookup = cspace.cspace_lookup;
|
||||
pub const cspace_revoke = cspace.cspace_revoke;
|
||||
pub const cspace_check_perm = cspace.cspace_check_perm;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export fn hal_crypto_ed25519_verify(sig: *const [64]u8, msg: [*]const u8, msg_le
|
|||
}
|
||||
|
||||
/// BLAKE3 Hash (256-bit) for key derivation
|
||||
/// Used by Monolith (SPEC-021) to derive VolumeKey from 4MB keyfile
|
||||
/// Used by Monolith (SPEC-503) to derive VolumeKey from 4MB keyfile
|
||||
export fn hal_crypto_blake3(data: [*]const u8, len: usize, out: *[32]u8) void {
|
||||
var hasher = std.crypto.hash.Blake3.init(.{});
|
||||
hasher.update(data[0..len]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,305 @@
|
|||
// SPEC-020: Capability Space (CSpace) Implementation
|
||||
// Component: core/security/cspace
|
||||
// Target: Ground Zero - Phase 1
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
/// CapType: Closed enumeration of capability types (SPEC-020)
|
||||
pub const CapType = enum(u8) {
|
||||
Null = 0,
|
||||
Entity = 1, // Control over Process/Fiber
|
||||
Channel = 2, // Access to ION Ring
|
||||
Memory = 3, // Access to Physical Frame
|
||||
Interrupt = 4, // IRQ mask/unmask control
|
||||
Time = 5, // Clock/Timer access
|
||||
Entropy = 6, // HWRNG access
|
||||
};
|
||||
|
||||
/// Permission flags (SPEC-020)
|
||||
pub const CapPerms = packed struct(u8) {
|
||||
read: bool = false,
|
||||
write: bool = false,
|
||||
execute: bool = false,
|
||||
map: bool = false,
|
||||
delegate: bool = false,
|
||||
revoke: bool = false,
|
||||
copy: bool = false,
|
||||
spawn: bool = false,
|
||||
};
|
||||
|
||||
/// Capability structure (32 bytes, cache-line aligned)
|
||||
pub const Capability = packed struct {
|
||||
cap_type: CapType, // 1 byte
|
||||
perms: CapPerms, // 1 byte
|
||||
_reserved: u16, // 2 bytes (alignment)
|
||||
object_id: u64, // 8 bytes (SipHash of resource)
|
||||
bounds_start: u64, // 8 bytes
|
||||
bounds_end: u64, // 8 bytes
|
||||
|
||||
comptime {
|
||||
if (@sizeOf(Capability) != 32) {
|
||||
@compileError("Capability must be exactly 32 bytes");
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a null capability
|
||||
pub fn null_cap() Capability {
|
||||
return .{
|
||||
.cap_type = .Null,
|
||||
.perms = .{},
|
||||
._reserved = 0,
|
||||
.object_id = 0,
|
||||
.bounds_start = 0,
|
||||
.bounds_end = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Check if capability is null
|
||||
pub fn is_null(self: *const Capability) bool {
|
||||
return self.cap_type == .Null;
|
||||
}
|
||||
|
||||
/// Validate bounds
|
||||
pub fn check_bounds(self: *const Capability, addr: u64) bool {
|
||||
if (self.is_null()) return false;
|
||||
return addr >= self.bounds_start and addr < self.bounds_end;
|
||||
}
|
||||
|
||||
/// Check permission
|
||||
pub fn has_perm(self: *const Capability, perm: CapPerms) bool {
|
||||
const self_bits = @as(u8, @bitCast(self.perms));
|
||||
const perm_bits = @as(u8, @bitCast(perm));
|
||||
return (self_bits & perm_bits) == perm_bits;
|
||||
}
|
||||
};
|
||||
|
||||
/// CSpace: Per-fiber capability table
|
||||
pub const CSPACE_SIZE = 64; // Maximum capabilities per fiber
|
||||
|
||||
pub const CSpace = struct {
|
||||
slots: [CSPACE_SIZE]Capability,
|
||||
epoch: u32, // For revocation
|
||||
fiber_id: u64, // Owner fiber
|
||||
_padding: u32, // Alignment
|
||||
|
||||
/// Initialize empty CSpace
|
||||
pub fn init(fiber_id: u64) CSpace {
|
||||
var cs = CSpace{
|
||||
.slots = undefined,
|
||||
.epoch = 0,
|
||||
.fiber_id = fiber_id,
|
||||
._padding = 0,
|
||||
};
|
||||
|
||||
// Initialize all slots to Null
|
||||
for (&cs.slots) |*slot| {
|
||||
slot.* = Capability.null_cap();
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
/// Find first empty slot
|
||||
pub fn find_empty_slot(self: *CSpace) ?usize {
|
||||
for (&self.slots, 0..) |*cap, i| {
|
||||
if (cap.is_null()) return i;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Grant capability (insert into CSpace)
|
||||
pub fn grant(self: *CSpace, cap: Capability) !usize {
|
||||
const slot = self.find_empty_slot() orelse return error.CSpaceFull;
|
||||
self.slots[slot] = cap;
|
||||
return slot;
|
||||
}
|
||||
|
||||
/// Lookup capability by slot index
|
||||
pub fn lookup(self: *const CSpace, slot: usize) ?*const Capability {
|
||||
if (slot >= CSPACE_SIZE) return null;
|
||||
const cap = &self.slots[slot];
|
||||
if (cap.is_null()) return null;
|
||||
return cap;
|
||||
}
|
||||
|
||||
/// Revoke capability (set to Null)
|
||||
pub fn revoke(self: *CSpace, slot: usize) void {
|
||||
if (slot >= CSPACE_SIZE) return;
|
||||
self.slots[slot] = Capability.null_cap();
|
||||
}
|
||||
|
||||
/// Revoke all capabilities (epoch-based)
|
||||
pub fn revoke_all(self: *CSpace) void {
|
||||
for (&self.slots) |*cap| {
|
||||
cap.* = Capability.null_cap();
|
||||
}
|
||||
self.epoch +%= 1;
|
||||
}
|
||||
|
||||
/// Delegate capability (Move or Copy)
|
||||
pub fn delegate(
|
||||
self: *CSpace,
|
||||
slot: usize,
|
||||
target: *CSpace,
|
||||
move: bool,
|
||||
) !usize {
|
||||
const cap = self.lookup(slot) orelse return error.InvalidCapability;
|
||||
|
||||
// Check DELEGATE permission
|
||||
if (!cap.has_perm(.{ .delegate = true })) {
|
||||
return error.NotDelegatable;
|
||||
}
|
||||
|
||||
// Grant to target
|
||||
const new_slot = try target.grant(cap.*);
|
||||
|
||||
// If move (not copy), revoke from source
|
||||
if (move or !cap.has_perm(.{ .copy = true })) {
|
||||
self.revoke(slot);
|
||||
}
|
||||
|
||||
return new_slot;
|
||||
}
|
||||
};
|
||||
|
||||
/// Global CSpace table (one per fiber)
|
||||
/// This will be integrated with Fiber Control Block in kernel.nim
|
||||
pub const MAX_FIBERS = 16;
|
||||
var global_cspaces: [MAX_FIBERS]CSpace = undefined;
|
||||
var cspaces_initialized: bool = false;
|
||||
|
||||
/// Initialize global CSpace table
|
||||
pub export fn cspace_init() void {
|
||||
if (cspaces_initialized) return;
|
||||
|
||||
for (&global_cspaces, 0..) |*cs, i| {
|
||||
cs.* = CSpace.init(i);
|
||||
}
|
||||
|
||||
cspaces_initialized = true;
|
||||
}
|
||||
|
||||
/// Get CSpace for fiber
|
||||
pub export fn cspace_get(fiber_id: u64) ?*CSpace {
|
||||
if (!cspaces_initialized) return null;
|
||||
if (fiber_id >= MAX_FIBERS) return null;
|
||||
return &global_cspaces[fiber_id];
|
||||
}
|
||||
|
||||
/// Grant capability to fiber (C ABI)
|
||||
pub export fn cspace_grant_cap(
|
||||
fiber_id: u64,
|
||||
cap_type: u8,
|
||||
perms: u8,
|
||||
object_id: u64,
|
||||
bounds_start: u64,
|
||||
bounds_end: u64,
|
||||
) i32 {
|
||||
const cs = cspace_get(fiber_id) orelse return -1;
|
||||
|
||||
const cap = Capability{
|
||||
.cap_type = @enumFromInt(cap_type),
|
||||
.perms = @bitCast(perms),
|
||||
._reserved = 0,
|
||||
.object_id = object_id,
|
||||
.bounds_start = bounds_start,
|
||||
.bounds_end = bounds_end,
|
||||
};
|
||||
|
||||
const slot = cs.grant(cap) catch return -1;
|
||||
return @intCast(slot);
|
||||
}
|
||||
|
||||
/// Lookup capability (C ABI)
|
||||
pub export fn cspace_lookup(fiber_id: u64, slot: usize) ?*const Capability {
|
||||
const cs = cspace_get(fiber_id) orelse return null;
|
||||
return cs.lookup(slot);
|
||||
}
|
||||
|
||||
/// Revoke capability (C ABI)
|
||||
pub export fn cspace_revoke(fiber_id: u64, slot: usize) void {
|
||||
const cs = cspace_get(fiber_id) orelse return;
|
||||
cs.revoke(slot);
|
||||
}
|
||||
|
||||
/// Check capability permission (C ABI)
|
||||
pub export fn cspace_check_perm(fiber_id: u64, slot: usize, perm_bits: u8) bool {
|
||||
const cs = cspace_get(fiber_id) orelse return false;
|
||||
const cap = cs.lookup(slot) orelse return false;
|
||||
const perm: CapPerms = @bitCast(perm_bits);
|
||||
return cap.has_perm(perm);
|
||||
}
|
||||
|
||||
// Unit tests
|
||||
test "Capability creation and validation" {
|
||||
const cap = Capability{
|
||||
.cap_type = .Channel,
|
||||
.perms = .{ .read = true, .write = true },
|
||||
._reserved = 0,
|
||||
.object_id = 0x1234,
|
||||
.bounds_start = 0x1000,
|
||||
.bounds_end = 0x2000,
|
||||
};
|
||||
|
||||
try std.testing.expect(!cap.is_null());
|
||||
try std.testing.expect(cap.check_bounds(0x1500));
|
||||
try std.testing.expect(!cap.check_bounds(0x3000));
|
||||
try std.testing.expect(cap.has_perm(.{ .read = true }));
|
||||
try std.testing.expect(!cap.has_perm(.{ .execute = true }));
|
||||
}
|
||||
|
||||
test "CSpace operations" {
|
||||
var cs = CSpace.init(42);
|
||||
|
||||
const cap = Capability{
|
||||
.cap_type = .Memory,
|
||||
.perms = .{ .read = true, .write = true, .delegate = true },
|
||||
._reserved = 0,
|
||||
.object_id = 0xABCD,
|
||||
.bounds_start = 0,
|
||||
.bounds_end = 0x1000,
|
||||
};
|
||||
|
||||
// Grant capability
|
||||
const slot = try cs.grant(cap);
|
||||
try std.testing.expect(slot == 0);
|
||||
|
||||
// Lookup capability
|
||||
const retrieved = cs.lookup(slot).?;
|
||||
try std.testing.expect(retrieved.object_id == 0xABCD);
|
||||
|
||||
// Revoke capability
|
||||
cs.revoke(slot);
|
||||
try std.testing.expect(cs.lookup(slot) == null);
|
||||
}
|
||||
|
||||
test "Delegation" {
|
||||
var cs1 = CSpace.init(1);
|
||||
var cs2 = CSpace.init(2);
|
||||
|
||||
const cap = Capability{
|
||||
.cap_type = .Channel,
|
||||
.perms = .{ .read = true, .delegate = true, .copy = true },
|
||||
._reserved = 0,
|
||||
.object_id = 0x5678,
|
||||
.bounds_start = 0,
|
||||
.bounds_end = 0xFFFF,
|
||||
};
|
||||
|
||||
const slot1 = try cs1.grant(cap);
|
||||
|
||||
// Copy delegation
|
||||
const slot2 = try cs1.delegate(slot1, &cs2, false);
|
||||
|
||||
// Both should have the capability
|
||||
try std.testing.expect(cs1.lookup(slot1) != null);
|
||||
try std.testing.expect(cs2.lookup(slot2) != null);
|
||||
|
||||
// Move delegation
|
||||
var cs3 = CSpace.init(3);
|
||||
const slot3 = try cs2.delegate(slot2, &cs3, true);
|
||||
|
||||
// cs2 should no longer have it
|
||||
try std.testing.expect(cs2.lookup(slot2) == null);
|
||||
try std.testing.expect(cs3.lookup(slot3) != null);
|
||||
}
|
||||
29
hal/mm.zig
29
hal/mm.zig
|
|
@ -172,29 +172,28 @@ pub fn create_kernel_identity_map() !*PageTable {
|
|||
return root;
|
||||
}
|
||||
|
||||
// Create restricted worker map
|
||||
pub fn create_worker_map(stack_base: u64, stack_size: u64, packet_addr: u64, code_base_pa: u64) !*PageTable {
|
||||
// Create restricted worker map for Cellular Memory Architecture
|
||||
pub fn create_worker_map(stack_base: u64, stack_size: u64, packet_addr: u64, phys_base: u64, region_size: u64) !*PageTable {
|
||||
const root = alloc_page_table() orelse return error.OutOfMemory;
|
||||
|
||||
// 🏛️ THE ISOLATED CAGE (Phase 40 - Per-Fiber Memory Isolation)
|
||||
// 🏛️ THE IRON FIREWALL (Cellular Memory Isolation)
|
||||
// SPEC-202: User VA 0x88000000 is mapped to variable Physical Slots (phys_base).
|
||||
|
||||
kprint("[MM] Creating worker map:\n");
|
||||
kprint("[MM] Kernel (S-mode): 0x80000000-0x88000000\n");
|
||||
kprint("[MM] User VA: 0x88000000-0x90000000\n");
|
||||
kprint("[MM] User PA: ");
|
||||
kprint_hex(code_base_pa);
|
||||
kprint("[MM] Cellular Map: phys_base=");
|
||||
kprint_hex(phys_base);
|
||||
kprint(" size=");
|
||||
kprint_hex(region_size);
|
||||
kprint("\n");
|
||||
|
||||
// 1. Kernel Memory (0-128MB) -> Supervisor ONLY (PTE_U = 0)
|
||||
// This allows the fiber trampoline to execute in S-mode.
|
||||
try map_range(root, DRAM_BASE, DRAM_BASE, 128 * 1024 * 1024, PTE_R | PTE_W | PTE_X);
|
||||
|
||||
// 2. User Memory (VA 0x88000000 -> PA code_base_pa) -> User Accessible (PTE_U = 1)
|
||||
// This creates ISOLATED physical regions per fiber:
|
||||
// - Init: VA 0x88000000 -> PA 0x88000000
|
||||
// - Child: VA 0x88000000 -> PA 0x90000000 (or higher)
|
||||
// 2. User Slot (VA 0x88000000 -> PA phys_base) -> User Accessible (PTE_U = 1)
|
||||
// - Slot 0 (Init): PA 0x88000000 (Big Cell)
|
||||
// - Slot 1 (Mksh): PA 0x8C000000 (Standard Cell)
|
||||
const user_va_base = DRAM_BASE + (128 * 1024 * 1024);
|
||||
try map_range(root, user_va_base, code_base_pa, 128 * 1024 * 1024, PTE_R | PTE_W | PTE_X | PTE_U);
|
||||
try map_range(root, user_va_base, phys_base, region_size, PTE_R | PTE_W | PTE_X | PTE_U);
|
||||
|
||||
// 3. MMIO Plumbing - Mapped identity but S-mode ONLY (PTE_U = 0)
|
||||
// This allows the kernel to handle interrupts/IO while fiber map is active.
|
||||
|
|
@ -255,8 +254,8 @@ pub export fn mm_get_kernel_satp() callconv(.c) u64 {
|
|||
return kernel_satp_value;
|
||||
}
|
||||
|
||||
pub export fn mm_create_worker_map(stack_base: u64, stack_size: u64, packet_addr: u64, code_base_pa: u64) callconv(.c) u64 {
|
||||
if (create_worker_map(stack_base, stack_size, packet_addr, code_base_pa)) |root| {
|
||||
pub export fn mm_create_worker_map(stack_base: u64, stack_size: u64, packet_addr: u64, phys_base: u64, region_size: u64) callconv(.c) u64 {
|
||||
if (create_worker_map(stack_base, stack_size, packet_addr, phys_base, region_size)) |root| {
|
||||
return make_satp(root);
|
||||
} else |_| {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,420 @@
|
|||
//! SPEC-060: System Ontology - Event & Entity Structures
|
||||
//! Component: core/ontology
|
||||
//! Target: Ground Zero - Phase 2
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
/// EventKind: Closed enumeration of system events (SPEC-060)
|
||||
pub const EventKind = enum(u16) {
|
||||
Null = 0,
|
||||
|
||||
// Lifecycle Events
|
||||
SystemBoot = 1,
|
||||
SystemShutdown = 2,
|
||||
FiberSpawn = 3,
|
||||
FiberTerminate = 4,
|
||||
|
||||
// Capability Events
|
||||
CapabilityGrant = 10,
|
||||
CapabilityRevoke = 11,
|
||||
CapabilityDelegate = 12,
|
||||
|
||||
// I/O Events
|
||||
ChannelOpen = 20,
|
||||
ChannelClose = 21,
|
||||
ChannelRead = 22,
|
||||
ChannelWrite = 23,
|
||||
|
||||
// Memory Events
|
||||
MemoryAllocate = 30,
|
||||
MemoryFree = 31,
|
||||
MemoryMap = 32,
|
||||
|
||||
// Network Events
|
||||
NetworkPacketRx = 40,
|
||||
NetworkPacketTx = 41,
|
||||
|
||||
// Security Events
|
||||
AccessDenied = 50,
|
||||
PolicyViolation = 51,
|
||||
};
|
||||
|
||||
/// Event: Immutable record of a system occurrence (58 bytes, packed)
|
||||
/// NOTE: Packed to 58 bytes for Zig compatibility (packed structs can't contain arrays)
|
||||
pub const Event = packed struct {
|
||||
kind: EventKind, // 2 bytes - Event type
|
||||
_reserved: u16, // 2 bytes - Alignment
|
||||
timestamp_ns: u64, // 8 bytes - Nanosecond timestamp
|
||||
fiber_id: u64, // 8 bytes - Originating fiber
|
||||
entity_id: u64, // 8 bytes - Target entity (SipHash)
|
||||
cause_id: u64, // 8 bytes - Causal parent event ID
|
||||
data0: u64, // 8 bytes - Event-specific data
|
||||
data1: u64, // 8 bytes - Event-specific data
|
||||
data2: u64, // 8 bytes - Event-specific data
|
||||
// Total: 58 bytes (packed)
|
||||
|
||||
/// Create a null event
|
||||
pub fn null_event() Event {
|
||||
return .{
|
||||
.kind = .Null,
|
||||
._reserved = 0,
|
||||
.timestamp_ns = 0,
|
||||
.fiber_id = 0,
|
||||
.entity_id = 0,
|
||||
.cause_id = 0,
|
||||
.data0 = 0,
|
||||
.data1 = 0,
|
||||
.data2 = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Check if event is null
|
||||
pub fn is_null(self: *const Event) bool {
|
||||
return self.kind == .Null;
|
||||
}
|
||||
};
|
||||
|
||||
/// EntityKind: Types of system entities (SPEC-060)
|
||||
pub const EntityKind = enum(u8) {
|
||||
Null = 0,
|
||||
Fiber = 1,
|
||||
Channel = 2,
|
||||
Memory = 3,
|
||||
File = 4,
|
||||
Network = 5,
|
||||
Device = 6,
|
||||
};
|
||||
|
||||
/// Entity: Represents a system resource (32 bytes, cache-aligned)
|
||||
pub const Entity = extern struct {
|
||||
kind: EntityKind, // 1 byte - Entity type
|
||||
_reserved: [7]u8, // 7 bytes - Alignment
|
||||
entity_id: u64, // 8 bytes - Unique ID (SipHash)
|
||||
parent_id: u64, // 8 bytes - Parent entity (for hierarchy)
|
||||
metadata: u64, // 8 bytes - Entity-specific metadata
|
||||
|
||||
comptime {
|
||||
if (@sizeOf(Entity) != 32) {
|
||||
@compileError("Entity must be exactly 32 bytes");
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a null entity
|
||||
pub fn null_entity() Entity {
|
||||
return .{
|
||||
.kind = .Null,
|
||||
._reserved = [_]u8{0} ** 7,
|
||||
.entity_id = 0,
|
||||
.parent_id = 0,
|
||||
.metadata = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Check if entity is null
|
||||
pub fn is_null(self: *const Entity) bool {
|
||||
return self.kind == .Null;
|
||||
}
|
||||
};
|
||||
|
||||
/// System Truth Ledger: Append-only event log
|
||||
pub const STL_SIZE = 4096; // Maximum events in ring buffer
|
||||
|
||||
pub const SystemTruthLedger = struct {
|
||||
events: [STL_SIZE]Event,
|
||||
head: u32, // Next write position
|
||||
tail: u32, // Oldest event position
|
||||
epoch: u32, // Wraparound counter
|
||||
_padding: u32, // Alignment
|
||||
|
||||
/// Initialize empty STL
|
||||
pub fn init() SystemTruthLedger {
|
||||
var stl = SystemTruthLedger{
|
||||
.events = undefined,
|
||||
.head = 0,
|
||||
.tail = 0,
|
||||
.epoch = 0,
|
||||
._padding = 0,
|
||||
};
|
||||
|
||||
// Initialize all events to Null
|
||||
for (&stl.events) |*event| {
|
||||
event.* = Event.null_event();
|
||||
}
|
||||
|
||||
return stl;
|
||||
}
|
||||
|
||||
/// Append event to ledger (returns event ID)
|
||||
pub fn append(self: *SystemTruthLedger, event: Event) u64 {
|
||||
const idx = self.head;
|
||||
self.events[idx] = event;
|
||||
|
||||
// Advance head
|
||||
self.head = (self.head + 1) % STL_SIZE;
|
||||
|
||||
// If we wrapped, advance tail
|
||||
if (self.head == self.tail) {
|
||||
self.tail = (self.tail + 1) % STL_SIZE;
|
||||
self.epoch +%= 1;
|
||||
}
|
||||
|
||||
// Event ID = epoch << 32 | index
|
||||
return (@as(u64, self.epoch) << 32) | @as(u64, idx);
|
||||
}
|
||||
|
||||
/// Lookup event by ID
|
||||
pub fn lookup(self: *const SystemTruthLedger, event_id: u64) ?*const Event {
|
||||
const idx = @as(u32, @truncate(event_id & 0xFFFFFFFF));
|
||||
const epoch = @as(u32, @truncate(event_id >> 32));
|
||||
|
||||
if (idx >= STL_SIZE) return null;
|
||||
if (epoch != self.epoch and idx >= self.head) return null;
|
||||
|
||||
const event = &self.events[idx];
|
||||
if (event.is_null()) return null;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/// Get current event count
|
||||
pub fn count(self: *const SystemTruthLedger) u32 {
|
||||
if (self.head >= self.tail) {
|
||||
return self.head - self.tail;
|
||||
} else {
|
||||
return (STL_SIZE - self.tail) + self.head;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Global System Truth Ledger
|
||||
pub var global_stl: SystemTruthLedger = undefined;
|
||||
pub var stl_initialized: bool = false;
|
||||
|
||||
/// Initialize STL subsystem
|
||||
pub export fn stl_init() void {
|
||||
if (stl_initialized) return;
|
||||
global_stl = SystemTruthLedger.init();
|
||||
stl_initialized = true;
|
||||
}
|
||||
|
||||
/// Get current timestamp (placeholder - will be replaced by HAL timer)
|
||||
fn get_timestamp_ns() u64 {
|
||||
// TODO: Integrate with HAL timer
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Emit event to STL (C ABI)
|
||||
pub export fn stl_emit(
|
||||
kind: u16,
|
||||
fiber_id: u64,
|
||||
entity_id: u64,
|
||||
cause_id: u64,
|
||||
data0: u64,
|
||||
data1: u64,
|
||||
data2: u64,
|
||||
) u64 {
|
||||
if (!stl_initialized) return 0;
|
||||
|
||||
const event = Event{
|
||||
.kind = @enumFromInt(kind),
|
||||
._reserved = 0,
|
||||
.timestamp_ns = get_timestamp_ns(),
|
||||
.fiber_id = fiber_id,
|
||||
.entity_id = entity_id,
|
||||
.cause_id = cause_id,
|
||||
.data0 = data0,
|
||||
.data1 = data1,
|
||||
.data2 = data2,
|
||||
};
|
||||
|
||||
return global_stl.append(event);
|
||||
}
|
||||
|
||||
/// Lookup event by ID (C ABI)
|
||||
pub export fn stl_lookup(event_id: u64) ?*const Event {
|
||||
if (!stl_initialized) return null;
|
||||
return global_stl.lookup(event_id);
|
||||
}
|
||||
|
||||
/// Get event count (C ABI)
|
||||
pub export fn stl_count() u32 {
|
||||
if (!stl_initialized) return 0;
|
||||
return global_stl.count();
|
||||
}
|
||||
|
||||
/// Query result structure for event filtering
|
||||
pub const QueryResult = extern struct {
|
||||
count: u32,
|
||||
events: [64]*const Event, // Max 64 results per query
|
||||
};
|
||||
|
||||
/// Query events by fiber ID (C ABI)
|
||||
pub export fn stl_query_by_fiber(fiber_id: u64, result: *QueryResult) void {
|
||||
if (!stl_initialized) {
|
||||
result.count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var count: u32 = 0;
|
||||
var idx = global_stl.tail;
|
||||
|
||||
while (idx != global_stl.head and count < 64) : (idx = (idx + 1) % STL_SIZE) {
|
||||
const event = &global_stl.events[idx];
|
||||
if (!event.is_null() and event.fiber_id == fiber_id) {
|
||||
result.events[count] = event;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.count = count;
|
||||
}
|
||||
|
||||
/// Query events by kind (C ABI)
|
||||
pub export fn stl_query_by_kind(kind: u16, result: *QueryResult) void {
|
||||
if (!stl_initialized) {
|
||||
result.count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var count: u32 = 0;
|
||||
var idx = global_stl.tail;
|
||||
|
||||
while (idx != global_stl.head and count < 64) : (idx = (idx + 1) % STL_SIZE) {
|
||||
const event = &global_stl.events[idx];
|
||||
if (!event.is_null() and @intFromEnum(event.kind) == kind) {
|
||||
result.events[count] = event;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.count = count;
|
||||
}
|
||||
|
||||
/// Get recent events (last N) (C ABI)
|
||||
pub export fn stl_get_recent(max_count: u32, result: *QueryResult) void {
|
||||
if (!stl_initialized) {
|
||||
result.count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const actual_count = @min(max_count, @min(global_stl.count(), 64));
|
||||
var count: u32 = 0;
|
||||
|
||||
// Start from most recent (head - 1)
|
||||
var idx: u32 = if (global_stl.head == 0) STL_SIZE - 1 else global_stl.head - 1;
|
||||
|
||||
while (count < actual_count) {
|
||||
const event = &global_stl.events[idx];
|
||||
if (!event.is_null()) {
|
||||
result.events[count] = event;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (idx == global_stl.tail) break;
|
||||
idx = if (idx == 0) STL_SIZE - 1 else idx - 1;
|
||||
}
|
||||
|
||||
result.count = count;
|
||||
}
|
||||
|
||||
/// Lineage result structure for causal tracing
|
||||
pub const LineageResult = extern struct {
|
||||
count: u32,
|
||||
event_ids: [16]u64, // Maximum depth of 16 for causal chains
|
||||
};
|
||||
|
||||
/// Trace the causal lineage of an event (C ABI)
|
||||
pub export fn stl_trace_lineage(event_id: u64, result: *LineageResult) void {
|
||||
if (!stl_initialized) {
|
||||
result.count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var count: u32 = 0;
|
||||
var current_id = event_id;
|
||||
|
||||
while (count < 16) {
|
||||
const event = global_stl.lookup(current_id) orelse break;
|
||||
result.event_ids[count] = current_id;
|
||||
count += 1;
|
||||
|
||||
// Stop if we reach an event with no parent (or self-referencing parent)
|
||||
if (event.cause_id == current_id) break;
|
||||
|
||||
// In our system, the root event (SystemBoot) has ID 0 and cause_id 0
|
||||
if (current_id == 0 and event.cause_id == 0) break;
|
||||
|
||||
current_id = event.cause_id;
|
||||
}
|
||||
|
||||
result.count = count;
|
||||
}
|
||||
|
||||
// Unit tests
|
||||
test "Event creation and validation" {
|
||||
const event = Event{
|
||||
.kind = .FiberSpawn,
|
||||
._reserved = 0,
|
||||
.timestamp_ns = 1000,
|
||||
.fiber_id = 42,
|
||||
.entity_id = 0x1234,
|
||||
.cause_id = 0,
|
||||
.data0 = 0,
|
||||
.data1 = 0,
|
||||
.data2 = 0,
|
||||
};
|
||||
|
||||
try std.testing.expect(!event.is_null());
|
||||
try std.testing.expect(event.kind == .FiberSpawn);
|
||||
try std.testing.expect(event.fiber_id == 42);
|
||||
}
|
||||
|
||||
test "STL operations" {
|
||||
var stl = SystemTruthLedger.init();
|
||||
|
||||
const event1 = Event{
|
||||
.kind = .SystemBoot,
|
||||
._reserved = 0,
|
||||
.timestamp_ns = 1000,
|
||||
.fiber_id = 0,
|
||||
.entity_id = 0,
|
||||
.cause_id = 0,
|
||||
.data0 = 0,
|
||||
.data1 = 0,
|
||||
.data2 = 0,
|
||||
};
|
||||
|
||||
// Append event
|
||||
const id1 = stl.append(event1);
|
||||
try std.testing.expect(id1 == 0);
|
||||
try std.testing.expect(stl.count() == 1);
|
||||
|
||||
// Lookup event
|
||||
const retrieved = stl.lookup(id1).?;
|
||||
try std.testing.expect(retrieved.kind == .SystemBoot);
|
||||
}
|
||||
|
||||
test "STL wraparound" {
|
||||
var stl = SystemTruthLedger.init();
|
||||
|
||||
// Fill the buffer
|
||||
var i: u32 = 0;
|
||||
while (i < STL_SIZE + 10) : (i += 1) {
|
||||
const event = Event{
|
||||
.kind = .FiberSpawn,
|
||||
._reserved = 0,
|
||||
.timestamp_ns = i,
|
||||
.fiber_id = i,
|
||||
.entity_id = 0,
|
||||
.cause_id = 0,
|
||||
.data0 = 0,
|
||||
.data1 = 0,
|
||||
.data2 = 0,
|
||||
};
|
||||
_ = stl.append(event);
|
||||
}
|
||||
|
||||
// Should have wrapped
|
||||
try std.testing.expect(stl.epoch > 0);
|
||||
try std.testing.expect(stl.count() == STL_SIZE);
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
// This file is part of the Nexus Commonwealth.
|
||||
// See legal/LICENSE_COMMONWEALTH.md for license terms.
|
||||
|
||||
//! Rumpk HAL: Reed-Solomon RAM Block Device (SPEC-023)
|
||||
//! Rumpk HAL: Reed-Solomon RAM Block Device (SPEC-103)
|
||||
//!
|
||||
//! Provides ECC-protected RAM storage using Reed-Solomon GF(2^8).
|
||||
//! This is the "Cortex" - Space-Grade resilient memory.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# This file is part of the Nexus Sovereign Core.
|
||||
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
||||
|
||||
## Nexus Membrane: Configuration Ledger (SPEC-140)
|
||||
## Nexus Membrane: Configuration Ledger (SPEC-803)
|
||||
## Implements Event Sourcing for System State.
|
||||
|
||||
import strutils, times, options
|
||||
|
|
@ -69,7 +69,7 @@ proc ledger_replay*(ledger: ConfigLedger): Node =
|
|||
|
||||
proc ledger_rollback*(ledger: var ConfigLedger, target_tx: uint64) =
|
||||
## Rolls back the system state.
|
||||
## Note: This appends a ROLLBACK tx rather than truncating (SPEC-140 Doctrine).
|
||||
## Note: This appends a ROLLBACK tx rather than truncating (SPEC-803 Doctrine).
|
||||
let rb_node = newNode("rollback_target")
|
||||
rb_node.addArg(newVal(int(target_tx)))
|
||||
ledger.ledger_append(OpRollback, "system.rollback", rb_node)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
## Nexus Membrane: The Monolith (4MB Key)
|
||||
##
|
||||
## Implements the Zero-Friction Encryption per SPEC-021.
|
||||
## Implements the Zero-Friction Encryption per SPEC-503.
|
||||
## - L0 (Factory): Unprotected 4MB random key
|
||||
## - L1 (Sovereignty): Password-protected (Argon2id + XChaCha20)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# This file is part of the Nexus Sovereign Core.
|
||||
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
||||
|
||||
## Nexus Membrane: SFS Userspace Client (SPEC-021)
|
||||
## Nexus Membrane: SFS Userspace Client (SPEC-503)
|
||||
##
|
||||
## The Sovereign Filesystem Overlay:
|
||||
## - L0: LittleFS (Atomic Physics) via `lfs_nim`
|
||||
|
|
@ -69,7 +69,7 @@ proc sfs_alloc_sector(): uint32 =
|
|||
# =========================================================
|
||||
|
||||
proc sfs_mount*(): bool =
|
||||
## Mount the SFS filesystem (SPEC-021/022)
|
||||
## Mount the SFS filesystem (SPEC-503/022)
|
||||
## Uses LittleFS as backend, VolumeKey for encryption
|
||||
print("[SFS-U] Mounting Sovereign Filesystem...\n")
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ proc sfs_mount*(): bool =
|
|||
print("[SFS-U] LittleFS backend mounted.\n")
|
||||
|
||||
sfs_mounted = true
|
||||
print("[SFS-U] Mount SUCCESS. SPEC-021 Compliant.\n")
|
||||
print("[SFS-U] Mount SUCCESS. SPEC-503 Compliant.\n")
|
||||
return true
|
||||
|
||||
proc sfs_is_mounted*(): bool = sfs_mounted
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ type
|
|||
fn_yield*: proc() {.cdecl.}
|
||||
fn_siphash*: proc(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.cdecl.}
|
||||
fn_ed25519_verify*: proc(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.cdecl.}
|
||||
# SPEC-021: Monolith Key Derivation
|
||||
# SPEC-503: Monolith Key Derivation
|
||||
fn_blake3*: proc(data: pointer, len: uint64, out_hash: ptr array[32, byte]) {.cdecl.}
|
||||
# Phase 36.2: Network Membrane
|
||||
s_net_rx*: pointer # Kernel -> User (RX)
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ else:
|
|||
return int(syscall(0x203, uint64(fd), cast[uint64](buf), count))
|
||||
|
||||
# =========================================================
|
||||
# lwIP Syscall Bridge (SPEC-400, SPEC-401)
|
||||
# lwIP Syscall Bridge (SPEC-701, SPEC-805)
|
||||
# =========================================================
|
||||
|
||||
# The Graft: These C-compatible exports provide the kernel interface
|
||||
|
|
@ -370,7 +370,7 @@ proc syscall_get_time_ns*(): uint64 {.exportc, cdecl.} =
|
|||
proc syscall_get_random*(): uint32 {.exportc, cdecl.} =
|
||||
## Generate cryptographically strong random number for TCP ISN
|
||||
## Implementation: SipHash-2-4(MonolithKey, Time || CycleCount)
|
||||
## Per SPEC-401: Hash Strategy
|
||||
## Per SPEC-805: Hash Strategy
|
||||
|
||||
let sys = get_sys_table()
|
||||
|
||||
|
|
@ -392,7 +392,7 @@ proc syscall_get_random*(): uint32 {.exportc, cdecl.} =
|
|||
""".}
|
||||
copyMem(addr mix_data[8], unsafeAddr cycles, 8)
|
||||
|
||||
# Use SipHash with system key (SPEC-401)
|
||||
# Use SipHash with system key (SPEC-805)
|
||||
# TODO: Use actual Monolith key when available
|
||||
var key: array[16, byte]
|
||||
for i in 0..<16:
|
||||
|
|
|
|||
|
|
@ -1071,7 +1071,7 @@ proc nipbox_main*() =
|
|||
# Phase 30: Pledge Safety
|
||||
# NipBox is the Shell, so it needs broad permissions, but we can restrict RPATH/WPATH to specific zones
|
||||
# For now, we PLEDGE_ALL because the shell needs to explore
|
||||
# In future (SPEC-300), we drop PLEDGE_INET unless authorized
|
||||
# In future (SPEC-401), we drop PLEDGE_INET unless authorized
|
||||
discard lb.pledge(PLEDGE_ALL)
|
||||
|
||||
# Initialize the Biosuit
|
||||
|
|
|
|||
Loading…
Reference in New Issue