rumpk/libs/membrane/ion_client.nim

288 lines
9.7 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 Membrane: ION High-Level Client
# Copyright (c) 2026 Nexus Foundation
# Licensed under the Libertaria Unbound License (LUL-1.0)
# See legal/LICENSE_UNBOUND.md for details.
#
# core/rumpk/libs/membrane/ion_client.nim
# CRITICAL: Do NOT import ../../core/ion - it transitively imports ion/memory (2MB pool)
# Instead, locally declare only the types we need for userspace
import ../../core/ring
const SYS_TABLE_ADDR* = when defined(arm64): 0x50000000'u64
else: 0x83000000'u64
# Local type declarations (must match core/ion.nim definitions)
type
IonPacket* = object
data*: ptr UncheckedArray[byte]
phys*: uint64
len*: uint16
id*: uint16
CmdType* = enum
CMD_SYS_EXIT = 1
CMD_GPU_MATRIX = 2
CMD_ION_STOP = 3
CMD_ION_START = 4
CMD_NET_TX = 5
CMD_NET_RX = 6
CMD_BLK_READ = 7
CMD_BLK_WRITE = 8
CMD_FS_WRITE = 9
CMD_FS_READ = 10
CMD_ION_FREE = 0x300
CmdPacket* = object
kind*: uint32
pad*: uint32
arg*: uint64
id*: uint64
# Kernel functions (provided at link time, NOT from ion/memory module)
proc ion_alloc*(): IonPacket {.importc, cdecl.}
proc ion_free*(pkt: IonPacket) {.importc, cdecl.}
type
HAL_Ring_Input* = object
head*: uint32
tail*: uint32
mask*: uint32
data*: array[256, IonPacket]
SysTable* = object
magic*: uint32
reserved*: uint32
s_rx*: pointer
s_tx*: pointer
s_event*: pointer
s_cmd*: pointer
s_input*: pointer
fn_vfs_open*: proc(path: cstring, flags: int32): int32 {.cdecl.}
fn_vfs_read*: proc(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.}
fn_vfs_list*: proc(buf: pointer, max_len: uint64): int64 {.cdecl.}
fn_vfs_write*: proc(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.}
fn_vfs_close*: proc(fd: int32): int32 {.cdecl.}
fn_vfs_dup*: proc(fd: int32, min_fd: int32): int32 {.cdecl.}
fn_vfs_dup2*: proc(old_fd, new_fd: int32): int32 {.cdecl.}
fn_log*: pointer
fn_pledge*: proc(promises: uint64): int32 {.cdecl.}
fb_addr*: uint64
fb_width*: uint32
fb_height*: uint32
fb_stride*: uint32
fb_bpp*: uint32
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-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)
s_net_tx*: pointer # User -> Kernel (TX)
# Phase 36.3: Shared ION (16 bytes)
fn_ion_alloc*: proc(out_id: ptr uint16): uint64 {.cdecl.}
fn_ion_free*: proc(id: uint16) {.cdecl.}
# Phase 36.4: I/O Multiplexing (8 bytes)
fn_wait_multi*: proc(mask: uint64): int32 {.cdecl.}
# Phase 36.5: Network Hardware Info (8 bytes)
net_mac*: array[6, byte]
reserved_mac*: array[2, byte]
# Project LibWeb: LWF Sovereign Channel (16 bytes)
s_lwf_rx*: pointer # Kernel -> User (LWF frames)
s_lwf_tx*: pointer # User -> Kernel (LWF frames)
static:
doAssert sizeof(SysTable) == 240
var membrane_rx_ring_ptr*: ptr RingBuffer[IonPacket, 256]
var membrane_tx_ring_ptr*: ptr RingBuffer[IonPacket, 256]
var membrane_cmd_ring_ptr*: ptr RingBuffer[CmdPacket, 256]
var membrane_input_ring_ptr*: ptr HAL_Ring_Input
# Phase 36.2: Network Ring Pointers
var membrane_net_rx_ptr*: ptr HAL_Ring_Input
var membrane_net_tx_ptr*: ptr HAL_Ring_Input
proc get_sys_table*(): ptr SysTable =
return cast[ptr SysTable](SYS_TABLE_ADDR)
proc ion_user_init*() {.exportc.} =
let sys = get_sys_table()
discard sys
# Use raw C write to avoid Nim string issues before init
proc console_write(p: pointer, len: uint) {.importc, cdecl.}
var msg = "[ION-Client] Initializing...\n"
console_write(addr msg[0], uint(msg.len))
when defined(is_membrane) or defined(RUMPK_KERNEL):
if sys.magic != 0x4E585553:
var err = "[ION-Client] ERROR: Invalid SysTable Magic!\n"
console_write(addr err[0], uint(err.len))
return
membrane_rx_ring_ptr = cast[ptr RingBuffer[IonPacket, 256]](sys.s_rx)
membrane_tx_ring_ptr = cast[ptr RingBuffer[IonPacket, 256]](sys.s_tx)
membrane_cmd_ring_ptr = cast[ptr RingBuffer[CmdPacket, 256]](sys.s_cmd)
membrane_input_ring_ptr = cast[ptr HAL_Ring_Input](sys.s_input)
# Phase 36.2: Network rings
membrane_net_rx_ptr = cast[ptr HAL_Ring_Input](sys.s_net_rx)
membrane_net_tx_ptr = cast[ptr HAL_Ring_Input](sys.s_net_tx)
var ok = "[ION-Client] Rings Mapped.\n"
console_write(addr ok[0], uint(ok.len))
else:
var err = "[ION-Client] ERROR: is_membrane NOT DEFINED!\n"
console_write(addr err[0], uint(err.len))
# --- ION CLIENT LOGIC ---
# Pure shared-memory slab allocator - NO kernel function calls!
const
USER_SLAB_BASE = SYS_TABLE_ADDR + 0x10000'u64 # Start of user packet slab in SysTable region
USER_SLAB_COUNT = 512 # Number of packet slots
USER_PKT_SIZE = 2048 # Size of each packet buffer
USER_BITMAP_ADDR = SYS_TABLE_ADDR + 0x100'u64 # Bitmap stored in SysTable region (after SysTable struct)
# Get pointer to shared bitmap (512 bits = 64 bytes for 512 slots)
proc get_user_bitmap(): ptr array[64, byte] =
return cast[ptr array[64, byte]](USER_BITMAP_ADDR)
proc ion_user_alloc*(out_pkt: ptr IonPacket): bool {.exportc.} =
## Allocate packet from shared slab - pure userland, no kernel call
let bitmap = get_user_bitmap()
# Find first free slot
for byteIdx in 0 ..< 64:
if bitmap[byteIdx] != 0xFF: # At least one bit free
for bitIdx in 0 ..< 8:
let slotIdx = byteIdx * 8 + bitIdx
if slotIdx >= USER_SLAB_COUNT:
return false
let mask = byte(1 shl bitIdx)
if (bitmap[byteIdx] and mask) == 0:
# Found free slot - mark as used
bitmap[byteIdx] = bitmap[byteIdx] or mask
let addr_val = USER_SLAB_BASE + uint64(slotIdx) * USER_PKT_SIZE
out_pkt.id = uint16(slotIdx) or 0x8000
out_pkt.phys = addr_val
out_pkt.len = 0
out_pkt.data = cast[ptr UncheckedArray[byte]](addr_val)
return true
return false
proc ion_user_free*(pkt: IonPacket) {.exportc.} =
## Free packet back to shared slab - pure userland, no kernel call
if pkt.data == nil:
return
let slotIdx = pkt.id and 0x7FFF
if slotIdx >= USER_SLAB_COUNT:
return
let bitmap = get_user_bitmap()
let byteIdx = int(slotIdx) div 8
let bitIdx = int(slotIdx) mod 8
let mask = byte(1 shl bitIdx)
bitmap[byteIdx] = bitmap[byteIdx] and (not mask)
proc ion_user_return*(id: uint16) {.exportc.} =
if membrane_cmd_ring_ptr == nil: return
var cmd: CmdPacket
cmd.kind = uint32(CmdType.CMD_ION_FREE)
cmd.arg = uint64(id)
discard membrane_cmd_ring_ptr[].push(cmd)
proc ion_user_tx*(pkt: IonPacket): bool {.exportc.} =
if membrane_tx_ring_ptr == nil: return false
return membrane_tx_ring_ptr[].push(pkt)
proc ion_user_rx*(out_pkt: ptr IonPacket): bool {.exportc.} =
if membrane_rx_ring_ptr == nil: return false
if membrane_rx_ring_ptr[].isEmpty: return false
let (ok, pkt) = membrane_rx_ring_ptr[].pop()
if not ok: return false
out_pkt[] = pkt
return true
proc ion_user_input*(out_pkt: ptr IonPacket): bool {.exportc.} =
if membrane_input_ring_ptr == nil: return false
let head = membrane_input_ring_ptr.head
let tail = membrane_input_ring_ptr.tail
let mask = membrane_input_ring_ptr.mask
if head == tail: return false
let idx = tail and mask
let pkt = membrane_input_ring_ptr.data[idx]
out_pkt[] = pkt
membrane_input_ring_ptr.tail = tail + 1
return true
# --- Phase 36.2: Network Ring Access ---
proc ion_net_rx*(out_pkt: ptr IonPacket): bool {.exportc.} =
if membrane_net_rx_ptr == nil: return false
let head = membrane_net_rx_ptr.head
let tail = membrane_net_rx_ptr.tail
let mask = membrane_net_rx_ptr.mask
if head == tail: return false
let idx = tail and mask
let pkt = membrane_net_rx_ptr.data[idx]
out_pkt[] = pkt
membrane_net_rx_ptr.tail = tail + 1
return true
proc ion_net_tx*(pkt: IonPacket): bool {.exportc.} =
if membrane_net_tx_ptr == nil: return false
let head = membrane_net_tx_ptr.head
let tail = membrane_net_tx_ptr.tail
let mask = membrane_net_tx_ptr.mask
let next_head = (head + 1) and mask
if next_head == tail: return false # Ring full
membrane_net_tx_ptr.data[head and mask] = pkt
membrane_net_tx_ptr.head = next_head
return true
proc ion_net_available*(): bool {.exportc.} =
## Check if network rings are initialized and ready
return membrane_net_rx_ptr != nil and membrane_net_tx_ptr != nil
proc ion_user_wait_multi*(mask: uint64): int32 {.exportc.} =
let sys = get_sys_table()
if sys.fn_wait_multi != nil:
return sys.fn_wait_multi(mask)
return -1
# --- Crypto Wrappers ---
proc crypto_siphash*(key: array[16, byte], data: pointer, len: uint64): array[16, byte] =
let sys = get_sys_table()
if sys.fn_siphash != nil:
var k = key
sys.fn_siphash(addr k, data, len, addr result)
proc crypto_verify*(sig: array[64, byte], msg: pointer, len: uint64, pk: array[32, byte]): bool =
let sys = get_sys_table()
if sys.fn_ed25519_verify != nil:
var s = sig
var p = pk
return sys.fn_ed25519_verify(addr s, msg, len, addr p)
return false
proc crypto_blake3*(data: pointer, len: uint64): array[32, byte] =
let sys = get_sys_table()
if sys.fn_blake3 != nil:
sys.fn_blake3(data, len, addr result)
proc ion_get_mac*(): array[6, byte] =
let sys = get_sys_table()
return sys.net_mac