# 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 fiber, ion, sched, pty, cspace, ontology, fastpath, utcp
import fs/vfs, fs/tar
import loader/elf
import ../libs/membrane/term
import ../libs/membrane/net_glue

const
  MAX_WORKERS* = 8
  MAX_FIBER_STACK* = 128 * 1024
  SYSTABLE_BASE* = when defined(arm64): 0x50000000'u64
                   else: 0x83000000'u64
  # Cellular Memory Architecture (M3.3)
  CELL0_BASE* = when defined(arm64): 0x48000000'u64
                else: 0x88000000'u64
  CELL1_BASE* = when defined(arm64): 0x4C000000'u64
                else: 0x8C000000'u64
  USER_VA_BASE* = when defined(arm64): 0x48000000'u64
                  else: 0x88000000'u64
  USER_SP_FALLBACK* = when defined(arm64): 0x4BFFFFF0'u64
                      else: 0x8BFFFFF0'u64

# Export Nim Timer Handler for HAL (Zig calls this)
proc rumpk_timer_handler() {.exportc, cdecl, used.} =
  discard

# --- EXTERNAL SYMBOLS ---
proc ion_get_phys(id: uint16): uint64 {.importc, cdecl.}
proc rumpk_net_init() {.importc, cdecl.}
proc virtio_net_poll() {.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: "hal_console_write", cdecl.}
proc nexshell_main() {.importc, cdecl.}
proc console_poll() {.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 {.align: 4096.}, stack_subject {.align: 4096.}, stack_child {.align: 4096.}, stack_compositor {.align: 4096.}, stack_nexshell {.align: 4096.}, stack_netswitch {.align: 4096.}: 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)

proc kprint_hex8*(val: uint8) {.exportc, cdecl.} =
  proc uart_print_hex8(val: uint8) {.importc, cdecl.}
  uart_print_hex8(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)
        when defined(riscv64):
          {.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
  when defined(riscv64):
    {.emit: """asm volatile ("fence.i" : : : "memory");""" .}
  elif defined(arm64):
    {.emit: """asm volatile ("ic iallu; dsb ish; isb" : : : "memory");""" .}

  discard ion_vfs_close(fd)
  return ehdr.e_entry

# --- M4.4: MANIFEST-DRIVEN CAPABILITY LOADING ---

proc set_pledge*(f: var FiberObject, pledge: uint64) =
  ## Set fiber pledge mask, preserving Spectrum bits [63:62]
  f.promises = (f.promises and 0xC000000000000000'u64) or (pledge and 0x3FFFFFFFFFFFFFFF'u64)

proc kload_manifest_tar(path: cstring): ManifestResult =
  ## Scan ELF section headers via TAR for .nexus.manifest containing BKDL data.
  ## Uses tar.vfs_read_at() for selective reads (same approach as kload_phys).
  result.header = nil
  result.caps = nil
  result.count = 0

  # Strip /sysro prefix for TAR paths (same logic as kload_phys)
  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)

  # 1. Read ELF header
  var ehdr: Elf64_Ehdr
  if tar.vfs_read_at(tar_path, addr ehdr, uint64(sizeof(ehdr)), 0) != int64(sizeof(ehdr)):
    return
  if ehdr.e_ident[0] != 0x7F or ehdr.e_ident[1] != 'E'.uint8:
    return
  if ehdr.e_shoff == 0 or ehdr.e_shnum == 0 or ehdr.e_shstrndx >= ehdr.e_shnum:
    return

  # 2. Read shstrtab section header to get string table location
  let strtab_offset = ehdr.e_shoff + uint64(ehdr.e_shstrndx) * uint64(ehdr.e_shentsize)
  var strtab_shdr: Elf64_Shdr
  if tar.vfs_read_at(tar_path, addr strtab_shdr, uint64(sizeof(Elf64_Shdr)), strtab_offset) != int64(sizeof(Elf64_Shdr)):
    return

  # 3. Read the string table itself (cap at 512 bytes — section names are short)
  var strtab_buf: array[512, byte]
  let strtab_read_size = min(strtab_shdr.sh_size, 512'u64)
  if tar.vfs_read_at(tar_path, addr strtab_buf[0], strtab_read_size, strtab_shdr.sh_offset) != int64(strtab_read_size):
    return

  # 4. Scan section headers for .nexus.manifest
  let target = cstring(".nexus.manifest")
  for i in 0 ..< int(ehdr.e_shnum):
    var shdr: Elf64_Shdr
    let sh_offset = ehdr.e_shoff + uint64(i) * uint64(ehdr.e_shentsize)
    if tar.vfs_read_at(tar_path, addr shdr, uint64(sizeof(Elf64_Shdr)), sh_offset) != int64(sizeof(Elf64_Shdr)):
      continue

    if shdr.sh_name < uint32(strtab_read_size):

      # Compare section name against ".nexus.manifest"
      var match = true
      var j = 0
      while j < 16:  # len(".nexus.manifest") + null = 16
        let ch = target[j]
        let idx = int(shdr.sh_name) + j
        if idx >= int(strtab_read_size):
          match = false
          break
        if ch == '\0':
          break  # End of target string — all matched
        if strtab_buf[idx] != byte(ch):
          match = false
          break
        j += 1

      if match and shdr.sh_size >= uint64(sizeof(BkdlHeader)):
        # 5. Read the manifest section data into a static buffer
        # Max manifest size: BkdlHeader (118) + 16 caps * CapDescriptor (12) = 310 bytes
        var manifest_buf {.global.}: array[512, byte]
        let read_size = min(shdr.sh_size, 512'u64)
        if tar.vfs_read_at(tar_path, addr manifest_buf[0], read_size, shdr.sh_offset) != int64(read_size):
          return

        let hdr = cast[ptr BkdlHeader](addr manifest_buf[0])
        if hdr.magic != BKDL_MAGIC or hdr.version != BKDL_VERSION:
          kprintln("[Manifest] Invalid BKDL magic/version")
          return

        let expected = uint64(sizeof(BkdlHeader)) + uint64(hdr.cap_count) * uint64(sizeof(CapDescriptor))
        if expected > read_size:
          kprintln("[Manifest] BKDL cap_count exceeds section size")
          return

        kprint("[Manifest] WARNING: Signature unchecked (dev mode)")
        kprintln("")
        discard emit_access_denied(0, 0xB0D1, 0, 0)  # STL: signature skip event

        result.header = hdr
        result.caps = cast[ptr UncheckedArray[CapDescriptor]](addr manifest_buf[sizeof(BkdlHeader)])
        result.count = int(hdr.cap_count)
        return

proc apply_manifest*(fiber_id: uint64, manifest: ManifestResult, pledge_out: var uint64) =
  ## Apply BKDL manifest capabilities to fiber's CSpace.
  ## Derives pledge mask from requested capability types.
  var derived_pledge: uint64 = PLEDGE_STDIO  # Always grant basic I/O

  for i in 0 ..< manifest.count:
    let cap = manifest.caps[i]
    let slot = fiber_grant_channel(fiber_id, cap.resource_id, cap.perms)
    if slot >= 0:
      discard emit_capability_grant(fiber_id, cap.cap_type, cap.resource_id, uint8(slot), 0)
      kprint("[Manifest] Granted cap "); kprint_hex(cap.resource_id)
      kprint(" perms="); kprint_hex(uint64(cap.perms))
      kprint(" to fiber "); kprint_hex(fiber_id); kprintln("")
    else:
      discard emit_access_denied(fiber_id, cap.resource_id, cap.perms, 0)
      kprint("[Manifest] DENIED cap "); kprint_hex(cap.resource_id)
      kprint(" for fiber "); kprint_hex(fiber_id); kprintln(" (CSpace full)")

    # Derive pledge bits from capability types
    if cap.resource_id == 0x2000:  # VFS
      derived_pledge = derived_pledge or PLEDGE_RPATH
      if (cap.perms and PERM_WRITE) != 0:
        derived_pledge = derived_pledge or PLEDGE_WPATH
    elif cap.resource_id == 0x500 or cap.resource_id == 0x501:  # NET_TX / NET_RX
      derived_pledge = derived_pledge or PLEDGE_INET
    elif cap.resource_id == 0x1000 or cap.resource_id == 0x1001:  # Console
      discard  # PLEDGE_STDIO already set

  pledge_out = derived_pledge

# --- 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)

  # M4.4: Scan ELF for BKDL manifest and apply capabilities
  let loading_path = cast[cstring](addr subject_loading_path[0])
  let manifest = kload_manifest_tar(loading_path)
  if manifest.header != nil:
    kprint("[Manifest] Found BKDL manifest: "); kprint_hex(uint64(manifest.count)); kprintln(" capabilities")
    var pledge: uint64 = 0
    apply_manifest(current_fiber.id, manifest, pledge)
    set_pledge(current_fiber[], pledge)
    kprint("[Manifest] Pledge mask: "); kprint_hex(pledge); kprintln("")
  else:
    kprintln("[Manifest] No BKDL manifest — default policy (STDIO only)")
    set_pledge(current_fiber[], PLEDGE_STDIO)

  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 = USER_SP_FALLBACK

    kprintln("╔════════════════════════════════════════════════════╗")
    kprintln("║  PRE-FLIGHT: USERLAND TRANSITION                  ║")
    kprintln("╚════════════════════════════════════════════════════╝")
    kprint("  Entry:    "); kprint_hex(entry_addr); kprintln("")
    kprint("  SysTable: "); kprint_hex(SYSTABLE_BASE); kprintln("")
    kprint("  Stack:    "); kprint_hex(sp); kprintln("")
    kprint("  SATP:     "); kprint_hex(current_fiber.satp_value); kprintln("")
    kprint("  Phys Off: "); kprint_hex(current_fiber.phys_offset); kprintln("")
    kprintln("")

    # 🔥 CRITICAL: Activate worker page table BEFORE entering userland!
    # Without this, userland executes with kernel identity map → instant page fault
    if current_fiber.satp_value != 0:
      proc mm_activate_satp(satp_val: uint64) {.importc, cdecl.}
      kprint("[Subject:"); kprint_hex(fid); kprint("] Activating worker page table: "); kprint_hex(current_fiber.satp_value); kprintln("")
      mm_activate_satp(current_fiber.satp_value)

    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 nexshell_fiber_entry() {.cdecl.} =
  kprintln("[NexShell] Interactive Fiber Online")
  while true:
    console_poll()
    fiber_sleep(10)

proc compositor_fiber_entry() {.cdecl.} =
  kprintln("[Compositor] Fiber Entry reached.")
  while true:
    if matrix_enabled:
      fiber_sleep(100)
    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_cellular_stack(phys_base: uint64, slot_size: uint64, user_base: uint64): uint64 =
  # Stack grows down from the top of the cell
  var phys_top = phys_base + slot_size
  var user_sp = user_base + slot_size

  # Align 16
  phys_top = phys_top and not 15'u64
  user_sp = user_sp and not 15'u64

  # Helper to push data
  template push_str(s: string): uint64 =
    let s_val = s
    let l = uint64(s_val.len) + 1 # + null terminator
    phys_top -= l
    user_sp -= l
    # Zero the memory first (for null safety)
    k_zero_mem(cast[pointer](phys_top), l)
    copyMem(cast[pointer](phys_top), unsafeAddr s_val[0], s_val.len)
    user_sp # Return USER address

  # Environment strings
  let home_addr = push_str("HOME=/")
  let term_addr = push_str("TERM=vt100")
  let path_addr = push_str("/bin/mksh")

  kprint("[Stack] HOME env at: "); kprint_hex(home_addr); kprint("\n")
  kprint("[Stack] TERM env at: "); kprint_hex(term_addr); kprint("\n")
  kprint("[Stack] argv[0] at: "); kprint_hex(path_addr); kprint("\n")

  # Align 16 before pointer arrays
  phys_top = phys_top and not 15'u64
  user_sp = user_sp and not 15'u64

  # Helper to push uint64
  template push_u64(val: uint64) =
    phys_top -= 8
    user_sp -= 8
    cast[ptr uint64](phys_top)[] = val

  # Auxv (0, 0)
  push_u64(0)
  push_u64(0)

  # Envp (NULL, TERM, HOME) - Reverse order of push
  push_u64(0)
  push_u64(term_addr)
  push_u64(home_addr)

  # Argv (NULL, path)
  push_u64(0)
  push_u64(path_addr)

  # Argc (1)
  push_u64(1)

  kprint("[Stack] Final SP: "); kprint_hex(user_sp); kprint("\n")

  return user_sp

proc ion_fiber_entry() {.cdecl.} =
  kprintln("[ION] Fiber Entry reached.")
  while true:
    var pkt: CmdPacket
    if chan_cmd.recv(pkt):
      kprint("[ION] Received Packet Kind: "); kprint_hex(uint64(pkt.kind)); kprintln("")
      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
         # Note: stack_child is used for KERNEL context switching, not user stack.
         init_fiber(addr fiber_child, subject_fiber_entry, addr stack_child[0], sizeof(stack_child))

         # 🏛️ CELLULAR ALLOCATION (SPEC-202 Rev 2)
         # Sentinel (Init) takes Cell 0, Mksh (First Child) takes Cell 1
         let cell_base = CELL1_BASE
         let user_base = USER_VA_BASE
         let cell_size = 64 * 1024 * 1024'u64

         # Phase 40: Set PTY & User Stack
         fiber_child.pty_id = pid
         fiber_child.phys_offset = cell_base

         # Setup User Stack in CELLULAR Memory (User Top)
         # We write to Physical Address (cell_base + size), but Mksh sees (user_base + size)
         fiber_child.user_sp_init = setup_cellular_stack(cell_base, cell_size, user_base)

         # Create Map avoiding Kernel Stack exposure
         # We pass 0 as stack_base to skip mapping stack_child into user space.
         fiber_child.satp_value = mm_create_worker_map(0, 0, SYSTABLE_BASE, cell_base, cell_size)

         # M4.4: Child capabilities are applied in subject_fiber_entry via BKDL manifest.
         # No hardcoded grants needed here — manifest drives CSpace + pledge.
         # M4.5: Set budget based on child's Spectrum tier
         fiber_child.budget_ns = default_budget_for_spectrum((addr fiber_child).getSpectrum())
         kprintln("[ION] Child fiber spawned successfully")
      else: discard
    else:
      # No pending commands - yield to scheduler (short sleep to avoid busy spin)
      fiber_sleep(1) # 1ms

proc rumpk_yield_internal*() {.exportc, cdecl.} =
  # Switch back to the main dispatcher loop
  switch(active_fibers_arr[6])

proc fiber_yield*() {.exportc, cdecl.} =
  # Return to the dispatcher context (main_fiber)
  # kprint("[Y"); kprint_hex(current_fiber.id); kprint("]")
  switch(addr main_fiber)
  # The `ld_internal()` part from the instruction was syntactically incorrect
  # and likely a typo or incomplete instruction.
  # Assuming the intent was to replace the previous yield mechanism with a direct switch.

proc fiber_netswitch_entry() {.cdecl.} =
  kprintln("[NetSwitch] Traffic Engine Online")

  # Iron Firewall: Verify channel sovereignty before operation
  if chan_netswitch_rx.ring == nil:
    kprintln("[CRITICAL] NetSwitch RX channel uninitialized - HALTING")
    while true: fiber_yield()

  if chan_net_rx.ring == nil or chan_net_tx.ring == nil:
    kprintln("[CRITICAL] Global net rings uninitialized - HALTING")
    while true: fiber_yield()

  kprintln("[NetSwitch] Channels verified. Sovereignty confirmed.")

  # Initialize LwIP Membrane (DHCP, Netif, DNS)
  membrane_init()
  kprintln("[NetSwitch] Membrane initialized — DHCP running")

  while true:
     var pkt: IonPacket

     # INGRESS: Driver -> NetSwitch -> Fast Path Filter
     if chan_netswitch_rx.recv(pkt):
        # SPEC-700: Fast Path Bypass for UTCP Tunnel (UDP/9999)
        if is_utcp_tunnel(pkt.data, pkt.len):
           # FAST PATH: Bypass LwIP entirely
           var utcp_len = pkt.len
           let utcp_data = strip_tunnel_headers(pkt.data, utcp_len)
           if utcp_data != nil:
              utcp_handle_packet(utcp_data, utcp_len)
              ion_free_raw(pkt.id)
           else:
              kprintln("[FastPath] Strip failed - dropping")
              ion_free_raw(pkt.id)
        else:
           # SLOW PATH: Route to LwIP via chan_net_rx
           if not chan_net_rx.send(pkt):
              ion_free_raw(pkt.id)

     # EGRESS: Subject (chan_net_tx) -> NetSwitch -> Driver (ion_tx_push)
     if chan_net_tx.recv(pkt):
        kprintln("[NetSwitch] Forwarding Egress")
        var res = ion_tx_push(pkt)
        if not res: kprintln("[NetSwitch] Drop (TX Full)")

     # Drive LwIP timers + RX ingestion (DHCP, ARP, TCP, ICMP)
     pump_membrane_stack()

     # Poll Network
     virtio_net_poll()

     # Poll UART (Backup/Primary Polling Mode)
     {.emit: "extern void uart_poll_input(void); uart_poll_input();".}

     # Prevent Starvation
     fiber_sleep(10)  # 10ms - allow DHCP state machine to execute

proc ion_ingress*(id: uint16, len: uint16, offset: uint16) {.exportc, cdecl.} =
  ## Handle packet from Network Driver
  # Get actual physical address and apply driver offset
  let base_phys = ion_get_phys(id)
  let base_virt = ion_get_virt(id)

  # Create packet with pointers pointing DIRECTLY to the Ethernet frame
  let pkt = IonPacket(
    id: id,
    len: len,
    phys: base_phys + uint64(offset),
    data: cast[ptr UncheckedArray[byte]](cast[uint64](base_virt) + uint64(offset))
  )

  if not chan_netswitch_rx.send(pkt):
    ion_free_raw(id)


# --- SCHEDULER STATE ---
# --- SCHEDULER STATE ---

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:
    # kprintln("[ION Push] CRITICAL: Slab allocation failed!")
    return

  pkt.data[0] = cast[ptr byte](p)[]
  pkt.len = 1

  var wake_count = 0
  if chan_input.send(pkt):
    # Wake up any fibers waiting for terminal input
    for i in 0..<16:
      let f = active_fibers_arr[i]
      if f != nil and f.is_blocked and (f.blocked_on_mask and 0x1000) != 0:
        f.is_blocked = false
        f.blocked_on_mask = 0
        f.sleep_until = 0 # Wake immediately
        wake_count += 1

    if wake_count > 0:
      # kprint("[ION] Woke "); kprint_hex(uint64(wake_count)); kprintln(" fibers")
      discard

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.} =
  kprintln("")
  kprintln("╔════════════════════════════════════════════════════╗")
  kprintln("║  KERNEL IMMUNE SYSTEM: EXCEPTION DETECTED         ║")
  kprintln("╚════════════════════════════════════════════════════╝")

  # Decode scause
  let cause_code = scause and 0x7FFFFFFFFFFFFFFF'u64
  kprint("  SCAUSE: "); kprint_hex(scause); kprint(" (")
  case cause_code:
    of 0: kprint("Instruction address misaligned")
    of 1: kprint("Instruction access fault")
    of 2: kprint("Illegal instruction")
    of 3: kprint("Breakpoint")
    of 4: kprint("Load address misaligned")
    of 5: kprint("Load access fault")
    of 6: kprint("Store/AMO address misaligned")
    of 7: kprint("Store/AMO access fault")
    of 8: kprint("Environment call from U-mode")
    of 9: kprint("Environment call from S-mode")
    of 12: kprint("Instruction page fault")
    of 13: kprint("Load page fault")
    of 15: kprint("Store/AMO page fault")
    else: kprint("Unknown exception")
  kprintln(")")

  kprint("  SEPC:   "); kprint_hex(sepc); kprintln(" (Faulting PC)")
  kprint("  STVAL:  "); kprint_hex(stval); kprintln(" (Fault address/info)")

  # Dump current fiber context
  if current_fiber != nil:
    kprint("  Fiber:  "); kprint_hex(current_fiber.id)
    kprint(" SATP: "); kprint_hex(current_fiber.satp_value)
    kprintln("")

  kprintln("")
  kprintln("[IMMUNE] System HALTING (Trap Loop Prevention).")
  when defined(riscv64):
    while true:
      {.emit: "asm volatile(\"wfi\");".}
  elif defined(arm64):
    while true:
      {.emit: "asm volatile(\"wfe\");".}
  else:
    while true: discard

proc k_get_current_satp*(): uint64 {.exportc, cdecl.} =
  if current_fiber != nil:
    return current_fiber.satp_value
  return 0

proc wrapper_vfs_write(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.} =
  return ion_vfs_write(fd, buf, count)

# --- M4: PLEDGE ENFORCEMENT ---

proc check_pledge(nr: uint, f: Fiber): bool =
  ## Returns true if syscall is allowed by fiber's pledge mask
  let pledges = f.promises and 0x3FFFFFFFFFFFFFFF'u64
  if pledges == PLEDGE_ALL: return true  # Unrestricted

  case nr:
  of 0x01, 0x65, 0x66, 0x100, 0x101, 0x102:
    # exit, nanosleep, get_time, yield, pledge, wait_multi — always allowed
    return true
  of 0x203, 0x204:  # READ, WRITE
    return (pledges and PLEDGE_STDIO) != 0
  of 0x200, 0x202:  # OPEN, LIST
    return (pledges and PLEDGE_RPATH) != 0
  of 0x201, 0x205, 0x206, 0x207:  # CLOSE, IOCTL, FCNTL, DUP2
    return (pledges and PLEDGE_STDIO) != 0
  of 0x600, 0x300:  # EXECV, SPAWN_FIBER
    return (pledges and PLEDGE_EXEC) != 0
  of 0x905:  # SYS_SOCK_RESOLVE
    return (pledges and PLEDGE_INET) != 0
  else:
    return true  # Unknown syscalls pass through

# --- SYSCALL HANDLER ---

proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
  # M4: Pledge enforcement gate
  if current_fiber != nil and not check_pledge(nr, current_fiber):
    kprint("[DENIED] Fiber "); kprint_hex(current_fiber.id)
    kprint(" pledge violation: syscall "); kprint_hex(uint64(nr)); kprintln("")
    discard emit_access_denied(current_fiber.id, uint64(nr), 0, 0)
    return 0xFFFFFFFFFFFFFFFF'u  # -1 EPERM

  if nr != 0x100 and nr != 0x205 and nr != 0x204 and nr != 0x203:
    kprint("[Syscall] NR: "); kprint_hex(uint64(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()
    kprint("Slp: "); kprint_hex(now); kprint(" "); kprint_hex(a0); kprint("\n")
    current_fiber.sleep_until = now + a0
    fiber_yield()
    kprint("Woke\n")
    return 0
  of 0x66: # SYS_GET_TIME
    return uint(sched_get_now_ns())
  of 0x100: # YIELD
    fiber_yield()
    return 0
  of 0x101: # SYS_PLEDGE (OpenBSD semantics: can only narrow, never widen)
    let current = current_fiber.promises and 0x3FFFFFFFFFFFFFFF'u64
    let requested = a0 and 0x3FFFFFFFFFFFFFFF'u64
    if (requested and (not current)) != 0:
      kprint("[DENIED] Fiber "); kprint_hex(current_fiber.id); kprintln(" pledge widen attempt")
      discard emit_access_denied(current_fiber.id, 0x101, 0, 0)
      return 0xFFFFFFFFFFFFFFFF'u  # -1 EPERM
    current_fiber.promises = (current_fiber.promises and 0xC000000000000000'u64) or requested
    return 0
  of 0x102: # SYS_WAIT_MULTI (Silence Doctrine)
    current_fiber.blocked_on_mask = a0
    current_fiber.is_blocked = true
    fiber_yield()
    return 0
  of 0x200: # OPEN
    # M4: Check VFS capability (channel 0x2000)
    if current_fiber != nil and current_fiber.cspace_id < 16:
      let write_mode = (a1 and 1) != 0  # O_WRONLY or O_RDWR
      let needed_perm = if write_mode: PERM_WRITE else: PERM_READ
      if not cspace_check_channel(current_fiber.cspace_id, 0x2000, needed_perm):
        discard emit_access_denied(current_fiber.id, 0x2000, needed_perm, 0)
        return 0xFFFFFFFFFFFFFFFF'u
    let path = cast[cstring](a0)
    let result = ion_vfs_open(path, int32(a1))
    kprint("[OPEN] path="); kprint(path); kprint(" result="); kprint_hex(uint64(result)); kprint(" returning...\n")
    let ret_val = uint(result)
    kprint("[OPEN] About to return value: "); kprint_hex(ret_val); kprint("\n")
    return ret_val
  of 0x201: # CLOSE
    kprint("[CLOSE] fd="); kprint_hex(a0); kprint("\n")
    return uint(ion_vfs_close(int32(a0)))
  of 0x202: # LIST
    # M4: Check VFS read capability (channel 0x2000)
    if current_fiber != nil and current_fiber.cspace_id < 16:
      if not cspace_check_channel(current_fiber.cspace_id, 0x2000, PERM_READ):
        discard emit_access_denied(current_fiber.id, 0x2000, PERM_READ, 0)
        return 0xFFFFFFFFFFFFFFFF'u
    return uint(ion_vfs_list(cast[pointer](a0), uint64(a1)))
  of 0x205: # IOCTL
    kprint("[IOCTL] fd="); kprint_hex(a0); kprint(" request="); kprint_hex(a1); kprint("\n")
    return 0  # stub
  of 0x206: # FCNTL
    kprint("[FCNTL] fd="); kprint_hex(a0); kprint(" cmd="); kprint_hex(a1); kprint("\n")
    if a1 == 0: # F_DUPFD
      return uint(ion_vfs_dup(int32(a0), int32(a2)))
    return 0
  of 0x207: # DUP2
    return uint(ion_vfs_dup2(int32(a0), int32(a1)))
  of 0x905: # SYS_SOCK_RESOLVE
    # TODO: Implement getaddrinfo kernel integration
    return 0  # Not implemented yet
  of 0x203: # READ
    # M4: Check console.input capability for stdin (fd 0)
    if a0 == 0 and current_fiber != nil and current_fiber.cspace_id < 16:
      if not cspace_check_channel(current_fiber.cspace_id, 0x1000, PERM_READ):
        discard emit_access_denied(current_fiber.id, 0x1000, PERM_READ, 0)
        return 0xFFFFFFFFFFFFFFFF'u
    # M4: Check VFS capability for file reads (fd >= 3)
    if a0 >= 3 and current_fiber != nil and current_fiber.cspace_id < 16:
      if not cspace_check_channel(current_fiber.cspace_id, 0x2000, PERM_READ):
        discard emit_access_denied(current_fiber.id, 0x2000, PERM_READ, 0)
        return 0xFFFFFFFFFFFFFFFF'u
    var vres: int64 = -2
    if a0 >= 3:
       vres = ion_vfs_read(int32(a0), cast[pointer](a1), uint64(a2))

    # Fallback to PTY if FD=0 or VFS returned TTY mode (-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(int(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):
          for i in 0..<int(pkt.len):
            pty_push_input(pid, char(pkt.data[i]))
          ion_free(pkt)
        else:
          current_fiber.is_blocked = true
          current_fiber.blocked_on_mask = 0x1000 # Terminal Input
          current_fiber.sleep_until = 0xFFFFFFFFFFFFFFFF'u64 # Infinite
          fiber_yield()
    return uint(vres)
  of 0x204: # WRITE
    if a0 == 1 or a0 == 2:
       # M4: Check console.output capability (channel 0x1001)
       if current_fiber != nil and current_fiber.cspace_id < 16:
         if not cspace_check_channel(current_fiber.cspace_id, 0x1001, PERM_WRITE):
           discard emit_access_denied(current_fiber.id, 0x1001, PERM_WRITE, 0)
           return 0xFFFFFFFFFFFFFFFF'u
       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
    elif a0 >= 3:
       # M4: Check VFS write capability (channel 0x2000)
       if current_fiber != nil and current_fiber.cspace_id < 16:
         if not cspace_check_channel(current_fiber.cspace_id, 0x2000, PERM_WRITE):
           discard emit_access_denied(current_fiber.id, 0x2000, PERM_WRITE, 0)
           return 0xFFFFFFFFFFFFFFFF'u
       return uint(ion_vfs_write(int32(a0), cast[pointer](a1), uint64(a2)))
    return 0xFFFFFFFFFFFFFFFF'u # -1
  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)

    # DEBUG: Check if send works
    if chan_cmd.send(pkt):
       kprintln("[Kernel] CMD_SPAWN_FIBER sent to ION.")
    else:
       kprintln("[Kernel] CRITICAL: Failed to send CMD_SPAWN_FIBER to ION!")

    # 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
  kprintln("\nNexus Sovereign Core v1.1.2 Starting...")

  # HAL Hardware Inits
  # rumpk_net_init() -- Moved below

  ion_pool_init()
  proc mm_init() {.importc, cdecl.}
  proc mm_enable_kernel_paging() {.importc, cdecl.}
  mm_init()
  mm_enable_kernel_paging()

  # HAL Hardware Inits (Moved after ION/MM init)
  rumpk_net_init()

  # 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()
  ion_init_network() # Initialize net rings early
  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_vfs_dup = ion_vfs_dup
  sys.fn_vfs_dup2 = ion_vfs_dup2
  sys.fn_wait_multi = ion_wait_multi
  # Point to user slab allocator (shared memory) instead of kernel pool
  sys.fn_ion_alloc = ion_user_alloc_systable
  sys.fn_ion_free = ion_user_free_systable

  # Populate Network MAC
  proc virtio_net_get_mac(out_mac: ptr byte) {.importc, cdecl.}
  virtio_net_get_mac(addr sys.net_mac[0])
  kprint("[Kernel] MAC Address: ")
  for i in 0 ..< 6:
    kprint_hex8(sys.net_mac[i])
    if i < 5: kprint(":")
  kprintln("")

  # Initialize user slab bitmap (at offset 0x100, 16 bytes for 128 slots)
  let bitmap = cast[ptr array[16, byte]](SYSTABLE_BASE + 0x100)
  for i in 0 ..< 16:
    bitmap[i] = 0  # All slots free

  # Shared Rings Setup (SYSTABLE area)
  # Layout: 0x0000=SysTable, 0x0100=Bitmap, 0x2000=RX, 0x4000=TX, 0x6000=Event, 0x8000=CMD, 0xA000=Input
  # 0xC000=Net_RX, 0xE000=Net_TX, 0x10000=User_Slab
  # 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)

  # Network Rings (Shared with Userland)
  chan_net_rx.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0xC000)
  chan_net_tx.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0xE000)

  # Project LibWeb: LWF Rings (after user slab at 0x110000)
  chan_lwf_rx.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x110000)
  chan_lwf_tx.ring = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x112000)

  # 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
  chan_net_rx.ring.mask = 255; chan_net_tx.ring.mask = 255
  chan_lwf_rx.ring.mask = 255; chan_lwf_tx.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
  chan_net_rx.ring.head = 0; chan_net_rx.ring.tail = 0
  chan_net_tx.ring.head = 0; chan_net_tx.ring.tail = 0
  chan_lwf_rx.ring.head = 0; chan_lwf_rx.ring.tail = 0
  chan_lwf_tx.ring.head = 0; chan_lwf_tx.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

  # Map Network Rings (Now in shared memory)
  sys.s_net_rx = chan_net_rx.ring
  sys.s_net_tx = chan_net_tx.ring

  # Project LibWeb: Map LWF Rings
  sys.s_lwf_rx = chan_lwf_rx.ring
  sys.s_lwf_tx = chan_lwf_tx.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_fiber_entry, addr stack_nexshell[0], sizeof(stack_nexshell))
  let shell_spawn_id = emit_fiber_spawn(2, 0, boot_id)  # NexShell fiber

  # NetSwitch Spawn
  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")

  # M4.4: Subject (fiber 4) capabilities are now manifest-driven.
  # The BKDL manifest in the ELF binary declares what it needs.
  # Grants are applied in subject_fiber_entry via kload_manifest_tar + apply_manifest.
  kprintln("[CSpace] Subject capabilities deferred to BKDL manifest")

  # Grant Network I/O (RX/TX) — kernel fibers only
  # 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
  kprintln("[CSpace] Granted network capabilities to NetSwitch")

  # M4: Grant VFS capabilities — kernel fibers only
  discard fiber_grant_channel(1, 0x2000, PERM_READ or PERM_WRITE)  # ION: VFS (ELF loading)
  discard fiber_grant_channel(1, 0x1000, PERM_READ or PERM_WRITE)  # ION: console.input
  discard fiber_grant_channel(1, 0x1001, PERM_READ or PERM_WRITE)  # ION: console.output
  discard fiber_grant_channel(2, 0x2000, PERM_READ or PERM_WRITE)  # NexShell: VFS
  kprintln("[CSpace] Granted VFS capabilities to kernel fibers")

  # Init (Subject) lives in Cell 0 — Needs 64MB for large BSS
  fiber_subject.phys_offset = CELL0_BASE
  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 (Architecture-specific)
  when defined(riscv64):
    asm "csrsi sstatus, 2"
    {.emit: "asm volatile(\"csrs sie, %0\" : : \"r\"(1L << 9));".}
    let plic_base = 0x0c000000'u64
    # Priority (each IRQ has a 4-byte priority register)
    cast[ptr uint32](plic_base + 40)[] = 1 # UART (IRQ 10: 10*4 = 40)

    # Enable (Supervisor Context 1)
    # IRQs 0-31 (Enable IRQ 10 = UART)
    cast[ptr uint32](plic_base + 0x2000 + 0x80)[] = (1'u32 shl 10)

    # Threshold
    cast[ptr uint32](plic_base + 0x201000)[] = 0

    let en_addr = plic_base + 0x2000 + 0x80
    let en_val = cast[ptr uint32](en_addr)[]
    kprint("[PLIC] UART Enable Register at "); kprint_hex(en_addr)
    kprint(" is "); kprint_hex(uint64(en_val)); kprintln("")
  elif defined(arm64):
    # GICv2 is initialized in aarch64_init() before Nim entry
    kprintln("[GIC] Interrupts configured by HAL")

  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.Matter)    # Elevated from Void
  (addr fiber_child).setSpectrum(Spectrum.Matter)      # Elevated from Void
  current_fiber.setSpectrum(Spectrum.Void)           # Main loop (dispatcher)

  # M4.5: Kinetic Economy — default budgets per Spectrum tier
  (addr fiber_ion).budget_ns = default_budget_for_spectrum(Spectrum.Photon)
  (addr fiber_compositor).budget_ns = default_budget_for_spectrum(Spectrum.Photon)
  (addr fiber_netswitch).budget_ns = default_budget_for_spectrum(Spectrum.Photon)
  (addr fiber_nexshell).budget_ns = default_budget_for_spectrum(Spectrum.Matter)
  (addr fiber_subject).budget_ns = default_budget_for_spectrum(Spectrum.Matter)
  (addr fiber_child).budget_ns = default_budget_for_spectrum(Spectrum.Matter)
  # Void (main loop): budget_ns = 0 → unlimited (already default)

  # M4: Set initial pledge masks (using top-level set_pledge)
  fiber_ion.set_pledge(PLEDGE_ALL)
  fiber_compositor.set_pledge(PLEDGE_ALL)
  fiber_netswitch.set_pledge(PLEDGE_ALL)
  fiber_nexshell.set_pledge(PLEDGE_STDIO or PLEDGE_RPATH or PLEDGE_WPATH or PLEDGE_EXEC)
  # M4.4: Subject/child pledge is set by BKDL manifest in subject_fiber_entry.
  # Start with PLEDGE_STDIO as safe default (manifest will override).
  fiber_subject.set_pledge(PLEDGE_STDIO)
  fiber_child.set_pledge(PLEDGE_STDIO)
  kprintln("[M4] Pledge masks applied (Subject/child: manifest-driven)")

  # Ground Zero Phase 2: Introspection
  stl_print_summary()

  kprintln("[Rumpk] Multi-Fiber Dispatcher starting...")
  switch(addr fiber_ion)
  # Exported from Zig
  proc uart_poll_input() {.importc, cdecl.}

  while true:
    # ⌨️ Hardware Input Driver (Polling fallback)
    uart_poll_input()

    if not sched_tick_spectrum(active_fibers_arr):
      # Wait for data or timeout
      fiber_sleep(1)
