612 lines
23 KiB
Nim
612 lines
23 KiB
Nim
# 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 ring, fiber, ion, sched, pty, cspace, ontology, channels
|
|
import fs/vfs, fs/tar, fs/sfs
|
|
import loader/elf
|
|
import ../libs/membrane/term
|
|
import ../libs/membrane/libc as libc_impl
|
|
|
|
const
|
|
MAX_WORKERS* = 8
|
|
MAX_FIBER_STACK* = 128 * 1024
|
|
SYSTABLE_BASE* = 0x83000000'u64
|
|
|
|
# --- EXTERNAL SYMBOLS ---
|
|
proc ion_get_phys(id: uint16): uint64 {.importc, cdecl.}
|
|
proc ion_alloc_raw*(out_id: ptr uint16): uint64 {.importc, cdecl.}
|
|
proc ion_free_raw*(id: uint16) {.importc, cdecl.}
|
|
proc virtio_blk_read(sector: uint64, buf: ptr byte) {.importc, cdecl.}
|
|
proc virtio_blk_write(sector: uint64, buf: ptr byte) {.importc, cdecl.}
|
|
proc fb_kern_get_addr(): uint64 {.importc, cdecl.}
|
|
proc hal_io_init() {.importc, cdecl.}
|
|
proc console_write*(p: pointer, len: csize_t) {.importc, cdecl.}
|
|
proc nexshell_main() {.importc, cdecl.}
|
|
proc ion_get_virt(id: uint16): uint64 {.importc, cdecl.}
|
|
|
|
# InitRD Symbols
|
|
var initrd_start {.importc: "_initrd_start" .}: byte
|
|
var initrd_end {.importc: "_initrd_end" .}: byte
|
|
|
|
# Globals
|
|
var
|
|
fiber_ion, fiber_subject, fiber_child, fiber_compositor, fiber_nexshell, fiber_netswitch: FiberObject
|
|
stack_ion, stack_subject, stack_child, stack_compositor, stack_nexshell, stack_netswitch: array[MAX_FIBER_STACK, byte]
|
|
subject_loading_path: array[64, char] = [ '/', 's', 'y', 's', 'r', 'o', '/', 'b', 'i', 'n', '/', 'm', 'k', 's', 'h', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' ]
|
|
matrix_enabled: bool = false
|
|
active_fibers_arr: array[16, ptr FiberObject]
|
|
|
|
# Trace logic
|
|
proc kprint*(s: cstring) {.exportc, cdecl.} =
|
|
if s != nil:
|
|
var i = 0
|
|
let p = cast[ptr UncheckedArray[char]](s)
|
|
while p[i] != '\0': i += 1
|
|
console_write(cast[pointer](s), csize_t(i))
|
|
|
|
proc kprintln*(s: cstring) {.exportc, cdecl.} =
|
|
kprint(s); kprint("\n")
|
|
|
|
proc kprint_hex*(val: uint64) {.exportc, cdecl.} =
|
|
proc uart_print_hex(val: uint64) {.importc, cdecl.}
|
|
uart_print_hex(val)
|
|
|
|
# ION Unified Memory Manager shim
|
|
proc ion_alloc*(): IonPacket =
|
|
var id: uint16
|
|
let phys = ion_alloc_raw(addr id)
|
|
if phys == 0: return IonPacket()
|
|
let virt = ion_get_virt(id)
|
|
return IonPacket(data: cast[ptr UncheckedArray[byte]](virt), phys: phys, len: 0, id: id)
|
|
|
|
# Helper: Fiber Sleep
|
|
proc fiber_sleep*(ms: uint64) {.exportc, cdecl.} =
|
|
let now = sched_get_now_ns()
|
|
current_fiber.sleep_until = now + (ms * 1_000_000)
|
|
fiber_yield()
|
|
|
|
proc k_starts_with(s, prefix: cstring): bool =
|
|
let ps = cast[ptr UncheckedArray[char]](s)
|
|
let pp = cast[ptr UncheckedArray[char]](prefix)
|
|
var i = 0
|
|
while pp[i] != '\0':
|
|
if ps[i] == '\0' or ps[i] != pp[i]: return false
|
|
i += 1
|
|
return true
|
|
|
|
proc k_zero_mem(p: pointer, size: uint64) =
|
|
var addr_val = cast[uint64](p)
|
|
var remaining = size
|
|
|
|
# 1. Handle unaligned leading bytes
|
|
while (addr_val mod 8 != 0) and (remaining > 0):
|
|
cast[ptr byte](addr_val)[] = 0
|
|
addr_val += 1
|
|
remaining -= 1
|
|
|
|
# 2. Optimized 64-bit stores for the bulk
|
|
let count = remaining div 8
|
|
if count > 0:
|
|
let p64 = cast[ptr UncheckedArray[uint64]](addr_val)
|
|
for i in 0 ..< int(count):
|
|
p64[i] = 0
|
|
|
|
addr_val += uint64(count * 8)
|
|
remaining -= uint64(count * 8)
|
|
|
|
# 3. Handle trailing bytes
|
|
while remaining > 0:
|
|
cast[ptr byte](addr_val)[] = 0
|
|
addr_val += 1
|
|
remaining -= 1
|
|
|
|
proc kload_phys(path: cstring, phys_offset: uint64): uint64 =
|
|
# The Summoner: Load ELF from VFS into isolated physical memory
|
|
let fd = ion_vfs_open(path, 0)
|
|
if fd < 0:
|
|
kprint("[Loader] Error: Could not open '"); kprint(path); kprintln("'")
|
|
return 0
|
|
|
|
var ehdr: Elf64_Ehdr
|
|
if ion_vfs_read(fd, addr ehdr, uint64(sizeof(ehdr))) != int64(sizeof(ehdr)):
|
|
kprintln("[Loader] Error: ELF header read failed")
|
|
discard ion_vfs_close(fd)
|
|
return 0
|
|
|
|
if ehdr.e_ident[0] != 0x7F or ehdr.e_ident[1] != 'E'.uint8:
|
|
kprintln("[Loader] Error: Invalid ELF magic")
|
|
discard ion_vfs_close(fd)
|
|
return 0
|
|
|
|
# Programs are at /sysro in the TAR
|
|
# We need to skip the /sysro prefix for tar.vfs_read_at
|
|
# or better, just use the path as provided but tar.nim expects no leading /
|
|
var tar_path = path
|
|
if path[0] == '/':
|
|
tar_path = cast[cstring](cast[uint64](path) + 1)
|
|
if k_starts_with(path, "/sysro"):
|
|
tar_path = cast[cstring](cast[uint64](path) + 6)
|
|
if tar_path[0] == '/': tar_path = cast[cstring](cast[uint64](tar_path) + 1)
|
|
|
|
for i in 0 ..< int(ehdr.e_phnum):
|
|
var phdr: Elf64_Phdr
|
|
let ph_offset = ehdr.e_phoff + uint64(i * int(ehdr.e_phentsize))
|
|
if tar.vfs_read_at(tar_path, addr phdr, uint64(sizeof(phdr)), ph_offset) != int64(sizeof(phdr)):
|
|
continue
|
|
|
|
if phdr.p_type == PT_LOAD:
|
|
# Enable S-mode access to U-mode pages (SUM=1)
|
|
{.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 = 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
|
|
|
|
# --- FIBER ENTRIES ---
|
|
|
|
proc subject_fiber_entry() {.cdecl.} =
|
|
let fid = current_fiber.id
|
|
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]))
|
|
|
|
# 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) - 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)
|
|
else:
|
|
kprint("[Subject:"); kprint_hex(fid); kprintln("] Loader failed to find/load payload!")
|
|
while true: fiber_sleep(1000)
|
|
|
|
proc compositor_fiber_entry() {.cdecl.} =
|
|
kprintln("[Compositor] Fiber Entry reached.")
|
|
while true:
|
|
if matrix_enabled:
|
|
fiber_sleep(10)
|
|
else:
|
|
term.term_render()
|
|
fiber_sleep(33) # 30Hz
|
|
|
|
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)
|
|
sp = sp and not 15'u64 # Align 16
|
|
|
|
# Term String
|
|
let term_str = "TERM=nexus\0"
|
|
sp -= uint64(term_str.len)
|
|
copyMem(cast[pointer](sp), unsafeAddr term_str[0], term_str.len)
|
|
let term_addr = sp
|
|
|
|
# Path String
|
|
let path_str = "/bin/mksh\0"
|
|
sp -= uint64(path_str.len)
|
|
copyMem(cast[pointer](sp), unsafeAddr path_str[0], path_str.len)
|
|
let path_addr = sp
|
|
|
|
sp = sp and not 15'u64 # Align 16
|
|
|
|
# Auxv (0, 0)
|
|
sp -= 16
|
|
cast[ptr uint64](sp)[] = 0
|
|
cast[ptr uint64](sp+8)[] = 0
|
|
|
|
# Envp (term, NULL)
|
|
sp -= 16
|
|
cast[ptr uint64](sp)[] = term_addr
|
|
cast[ptr uint64](sp+8)[] = 0
|
|
|
|
# Argv (path, NULL)
|
|
sp -= 16
|
|
cast[ptr uint64](sp)[] = path_addr
|
|
cast[ptr uint64](sp+8)[] = 0
|
|
|
|
# Argc (1)
|
|
sp -= 8
|
|
cast[ptr uint64](sp)[] = 1
|
|
|
|
return sp
|
|
|
|
proc ion_fiber_entry() {.cdecl.} =
|
|
kprintln("[ION] Fiber Entry reached.")
|
|
while true:
|
|
var pkt: CmdPacket
|
|
if chan_cmd.recv(pkt):
|
|
case CmdType(pkt.kind):
|
|
of CMD_SYS_EXIT:
|
|
kprintln("[ION] Restarting Subject...")
|
|
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0], sizeof(stack_subject))
|
|
of CMD_ION_FREE:
|
|
ion_free_raw(uint16(pkt.arg))
|
|
of CMD_GPU_MATRIX:
|
|
matrix_enabled = (pkt.arg != 0)
|
|
of CMD_SPAWN_FIBER:
|
|
# Fiber spawn requested
|
|
# Hardcoded for verification to confirm isolation
|
|
let target = "/sysro/bin/mksh"
|
|
kprint("[ION] Spawning child fiber for: "); kprintln(target)
|
|
|
|
# Copy into loading path
|
|
copyMem(addr subject_loading_path[0], unsafeAddr target[0], target.len + 1)
|
|
|
|
# Allocate PTY
|
|
let pid = pty_alloc()
|
|
if pid < 0:
|
|
kprintln("[ION] Failed to allocate PTY for child!")
|
|
|
|
# Re-initialize fiber_child with the requested binary
|
|
init_fiber(addr fiber_child, subject_fiber_entry, addr stack_child[0], sizeof(stack_child))
|
|
|
|
# Phase 40: Set PTY & Stack
|
|
fiber_child.pty_id = pid
|
|
fiber_child.user_sp_init = setup_mksh_stack(addr stack_child[0], sizeof(stack_child))
|
|
|
|
# 🏛️ 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)
|
|
|
|
proc fiber_yield*() {.exportc, cdecl.} =
|
|
proc rumpk_yield_guard() {.importc, cdecl.}
|
|
rumpk_yield_guard()
|
|
|
|
proc rumpk_yield_internal*() {.exportc, cdecl.} =
|
|
# Switch back to the main dispatcher loop
|
|
switch(active_fibers_arr[6])
|
|
|
|
proc fiber_netswitch_entry() {.cdecl.} =
|
|
kprintln("[NetSwitch] Traffic Engine Online")
|
|
while true:
|
|
var pkt: IonPacket
|
|
if chan_netswitch_rx.recv(pkt):
|
|
ion_free_raw(pkt.id)
|
|
else:
|
|
fiber_sleep(2)
|
|
fiber_yield()
|
|
|
|
proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} =
|
|
## Handle packet from Network Driver
|
|
let pkt = IonPacket(id: id, len: len)
|
|
if not chan_netswitch_rx.send(pkt):
|
|
ion_free_raw(id)
|
|
|
|
proc ion_push_stdin*(p: pointer, len: csize_t) {.exportc, cdecl.} =
|
|
if chan_input.ring == nil: return
|
|
var pkt = ion_alloc()
|
|
if pkt.data == nil: return
|
|
let to_copy = if int(len) < 2048: int(len) else: 2048
|
|
copyMem(pkt.data, p, to_copy)
|
|
pkt.len = uint16(to_copy)
|
|
if fiber_subject.sleep_until == 0xFFFFFFFFFFFFFFFF'u64: fiber_subject.sleep_until = 0
|
|
discard chan_input.send(pkt)
|
|
|
|
proc k_check_deferred_yield*() {.exportc, cdecl.} =
|
|
if current_fiber != nil and current_fiber.wants_yield:
|
|
current_fiber.wants_yield = false
|
|
fiber_yield()
|
|
|
|
proc k_handle_exception*(scause, sepc, stval: uint) {.exportc, cdecl.} =
|
|
kprint("[IMMUNE] EXCEPTION: scause="); kprint_hex(scause)
|
|
kprint(" sepc="); kprint_hex(sepc)
|
|
kprint(" stval="); kprint_hex(stval)
|
|
kprintln("")
|
|
kprintln("[IMMUNE] Fiber HALTING.")
|
|
while true: fiber_yield()
|
|
|
|
proc rumpk_yield_guard() {.cdecl.} =
|
|
current_fiber.wants_yield = true
|
|
fiber_yield()
|
|
|
|
proc wrapper_vfs_write(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.} =
|
|
return ion_vfs_write(fd, buf, count)
|
|
|
|
# --- SYSCALL HANDLER ---
|
|
|
|
proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
|
# if nr != 0x100:
|
|
# kprint("[Syscall] NR: "); kprint_hex(nr); kprintln("")
|
|
|
|
case nr:
|
|
of 0x01: # EXIT
|
|
var pkt = CmdPacket(kind: uint32(CmdType.CMD_SYS_EXIT), arg: a0)
|
|
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
|
|
fiber_yield()
|
|
return 0
|
|
of 0x200: # OPEN
|
|
# return uint(libc_impl.libc_impl_open(cast[cstring](a0), int(a1)))
|
|
return 0
|
|
of 0x201: # CLOSE
|
|
# return uint(libc_impl.libc_impl_close(int(a0)))
|
|
return 0
|
|
of 0x202: # LIST
|
|
return uint(ion_vfs_list(cast[pointer](a0), uint64(a1)))
|
|
of 0x203: # READ
|
|
var vres = -2
|
|
if a0 == 0 or vres == -2:
|
|
let pid = if current_fiber.pty_id >= 0: current_fiber.pty_id else: 0
|
|
while true:
|
|
if pty_has_data_for_slave(pid):
|
|
var buf: array[1, byte]
|
|
let n = pty_read_slave(PTY_SLAVE_BASE + pid, addr buf[0], 1)
|
|
if n > 0:
|
|
cast[ptr UncheckedArray[byte]](a1)[0] = buf[0]
|
|
return 1
|
|
var pkt: IonPacket
|
|
if chan_input.recv(pkt):
|
|
let n = if uint64(pkt.len) < a2: uint64(pkt.len) else: a2
|
|
if n > 0:
|
|
# copyMem(cast[pointer](a1), cast[pointer](pkt.data), int(n))
|
|
# console_write(pkt.data, csize_t(n))
|
|
let data = cast[ptr UncheckedArray[byte]](pkt.data)
|
|
for i in 0 ..< int(n): pty_push_input(pid, char(data[i]))
|
|
ion_free_raw(pkt.id)
|
|
# Loop again to read from PTY
|
|
else:
|
|
current_fiber.sleep_until = 0xFFFFFFFFFFFFFFFF'u64
|
|
fiber_yield()
|
|
return uint(vres)
|
|
of 0x204: # WRITE
|
|
if a0 == 1 or a0 == 2:
|
|
console_write(cast[pointer](a1), csize_t(a2))
|
|
let pid = if current_fiber.pty_id >= 0: current_fiber.pty_id else: 0
|
|
discard pty_write_slave(PTY_SLAVE_BASE + pid, cast[ptr byte](a1), int(a2))
|
|
return a2
|
|
# var vres = libc_impl.libc_impl_write(int(a0), cast[pointer](a1), uint64(a2))
|
|
var vres = -1
|
|
return uint(vres)
|
|
of 0x205: return 0 # IOCTL stub
|
|
of 0x600: # EXECV (Legacy - use SYS_SPAWN_FIBER instead)
|
|
# Manual copy path to subject_loading_path
|
|
let p = cast[ptr UncheckedArray[char]](a0)
|
|
var i = 0
|
|
while p[i] != '\0' and i < 63:
|
|
subject_loading_path[i] = p[i]
|
|
i += 1
|
|
subject_loading_path[i] = '\0'
|
|
var pkt = CmdPacket(kind: uint32(CmdType.CMD_SYS_EXIT), arg: 0)
|
|
discard chan_cmd.send(pkt)
|
|
current_fiber.wants_yield = true
|
|
return 0
|
|
of 0x300: # SYS_SPAWN_FIBER - Spawn new fiber with target binary
|
|
# Copy path to subject_loading_path for next spawn
|
|
let p = cast[ptr UncheckedArray[char]](a0)
|
|
var i = 0
|
|
while p[i] != '\0' and i < 63:
|
|
subject_loading_path[i] = p[i]
|
|
i += 1
|
|
subject_loading_path[i] = '\0'
|
|
kprint("[Kernel] Spawning fiber for: ")
|
|
kprintln(cast[cstring](addr subject_loading_path[0]))
|
|
# Re-initialize fiber_subject with new binary
|
|
# The ION fiber will pick this up and restart the Subject fiber
|
|
var pkt = CmdPacket(kind: uint32(CMD_SPAWN_FIBER), arg: 0)
|
|
discard chan_cmd.send(pkt)
|
|
# Return fiber ID (always 4 for Subject currently)
|
|
return 4
|
|
else: return 0
|
|
|
|
# --- KERNEL BOOT ---
|
|
|
|
proc ion_wait_multi*(mask: uint64): int32 {.exportc, cdecl.} =
|
|
## Block the current fiber until data is available on any of the masked slots
|
|
current_fiber.blocked_on_mask = mask
|
|
current_fiber.is_blocked = true
|
|
fiber_yield()
|
|
return 0
|
|
|
|
proc kmain() {.exportc, cdecl.} =
|
|
var next_mmio_addr {.importc: "virtio_pci_next_mmio_addr", nodecl.}: uint32
|
|
kprint("\n[Kernel] next_mmio_addr check: ")
|
|
kprint_hex(uint64(next_mmio_addr))
|
|
kprintln("")
|
|
kprintln("\nNexus Sovereign Core v1.1 Starting...")
|
|
ion_pool_init()
|
|
proc mm_init() {.importc, cdecl.}
|
|
proc mm_enable_kernel_paging() {.importc, 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()
|
|
discard pty_alloc()
|
|
term.term_init()
|
|
|
|
vfs_init(addr initrd_start, addr initrd_end)
|
|
vfs_mount_init()
|
|
|
|
# DEBUG: List Files
|
|
kprintln("[VFS] Boot Inventory:")
|
|
var buf: array[512, byte]
|
|
let n = ion_vfs_list(addr buf[0], 512)
|
|
if n > 0:
|
|
kprintln(cast[cstring](addr buf[0]))
|
|
|
|
# Set initial loading path for Init (Subject)
|
|
let initial_path = "/sysro/init"
|
|
copyMem(addr subject_loading_path[0], unsafeAddr initial_path[0], initial_path.len + 1)
|
|
kprint("[ION] Subject Zero Path: "); kprintln(cast[cstring](addr subject_loading_path[0]))
|
|
|
|
let sys = cast[ptr SysTable](SYSTABLE_BASE)
|
|
sys.fn_vfs_open = ion_vfs_open
|
|
sys.fn_vfs_read = ion_vfs_read
|
|
sys.fn_vfs_list = ion_vfs_list
|
|
sys.fn_vfs_write = wrapper_vfs_write
|
|
sys.fn_wait_multi = ion_wait_multi
|
|
# Shared Rings Setup (SYSTABLE area)
|
|
# Layout: 0x0000=SysTable, 0x2000=RX, 0x4000=TX, 0x6000=Event, 0x8000=CMD, 0xA000=Input
|
|
# Each ring is ~6KB-8KB, so we need 8KB (0x2000) spacing.
|
|
chan_rx.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x2000)
|
|
chan_tx.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x4000)
|
|
let ring_event = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x6000)
|
|
chan_cmd.ring = cast[ptr HAL_Ring[CmdPacket]](SYSTABLE_BASE + 0x8000)
|
|
chan_input.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0xA000)
|
|
|
|
# Initialize Shared Memory Rings
|
|
chan_rx.ring.mask = 255; chan_tx.ring.mask = 255
|
|
ring_event.mask = 255; chan_cmd.ring.mask = 255
|
|
chan_input.ring.mask = 255
|
|
# Force reset pointers to zero
|
|
chan_rx.ring.head = 0; chan_rx.ring.tail = 0
|
|
chan_tx.ring.head = 0; chan_tx.ring.tail = 0
|
|
ring_event.head = 0; ring_event.tail = 0
|
|
chan_cmd.ring.head = 0; chan_cmd.ring.tail = 0
|
|
chan_input.ring.head = 0; chan_input.ring.tail = 0
|
|
|
|
sys.s_rx = chan_rx.ring; sys.s_tx = chan_tx.ring; sys.s_event = ring_event
|
|
sys.s_cmd = chan_cmd.ring; sys.s_input = chan_input.ring
|
|
|
|
sys.magic = 0x4E585553
|
|
sys.fb_addr = fb_kern_get_addr()
|
|
sys.fb_width = 1920; sys.fb_height = 1080; sys.fb_stride = 1920 * 4; sys.fb_bpp = 32
|
|
|
|
# Spawn Fibers
|
|
fiber_ion.id = 1; fiber_nexshell.id = 2; fiber_compositor.id = 3
|
|
fiber_subject.id = 4; fiber_child.id = 5; fiber_netswitch.id = 6
|
|
|
|
init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion))
|
|
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
|
|
|
|
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0], sizeof(stack_subject))
|
|
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")
|
|
|
|
# Grant Network I/O (RX/TX)
|
|
# NetSwitch (Fiber 6): Full access to shuttle packets
|
|
discard fiber_grant_channel(6, 0x500, PERM_READ or PERM_WRITE) # CMD_NET_TX
|
|
discard fiber_grant_channel(6, 0x501, PERM_READ or PERM_WRITE) # CMD_NET_RX
|
|
|
|
# Subject (Fiber 4): Needs to READ RX (0x501) and WRITE TX (0x500)
|
|
discard fiber_grant_channel(4, 0x500, PERM_WRITE) # Can send packets
|
|
discard fiber_grant_channel(4, 0x501, PERM_READ) # Can receive packets
|
|
kprintln("[CSpace] Granted network capabilities to NetSwitch and 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"
|
|
{.emit: "asm volatile(\"csrs sie, %0\" : : \"r\"(1L << 9));".}
|
|
let plic_base = 0x0c000000'u64
|
|
cast[ptr uint32](plic_base + 0x2000 + 0x80)[] = (1'u32 shl 10)
|
|
cast[ptr uint32](plic_base + 0x201000)[] = 0
|
|
cast[ptr uint32](plic_base + 40)[] = 1
|
|
|
|
active_fibers_arr[0] = addr fiber_ion; active_fibers_arr[1] = addr fiber_nexshell
|
|
active_fibers_arr[2] = addr fiber_compositor; active_fibers_arr[3] = addr fiber_netswitch
|
|
active_fibers_arr[4] = addr fiber_subject
|
|
active_fibers_arr[5] = addr fiber_child
|
|
active_fibers_arr[6] = current_fiber
|
|
|
|
# Set Spectrums (Priorities)
|
|
(addr fiber_ion).setSpectrum(Spectrum.Photon)
|
|
(addr fiber_compositor).setSpectrum(Spectrum.Photon)
|
|
(addr fiber_netswitch).setSpectrum(Spectrum.Photon)
|
|
(addr fiber_nexshell).setSpectrum(Spectrum.Matter) # Interactive
|
|
(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)
|
|
while true:
|
|
if not sched_tick_spectrum(active_fibers_arr.toOpenArray(0, 5)):
|
|
# The Silence Doctrine: Wait for Interrupt
|
|
let next_wake = sched_get_next_wakeup(active_fibers_arr.toOpenArray(0, 5))
|
|
if next_wake != 0xFFFFFFFFFFFFFFFF'u64:
|
|
proc sched_arm_timer(ns: uint64) {.importc, cdecl.}
|
|
# kprint("[Sleep] "); kprint_hex(next_wake); kprintln("")
|
|
sched_arm_timer(next_wake)
|
|
|
|
asm "csrsi sstatus, 2"
|
|
asm "wfi"
|
|
# kprintln("[Wake]")
|