246 lines
8.0 KiB
Nim
246 lines
8.0 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* = 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_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.}
|
|
|
|
static:
|
|
doAssert sizeof(SysTable) == 200
|
|
|
|
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 ---
|
|
|
|
proc ion_user_alloc*(out_pkt: ptr IonPacket): bool {.exportc.} =
|
|
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
|
if sys.magic != 0x4E585553 or sys.fn_ion_alloc == nil:
|
|
return false
|
|
|
|
var id: uint16
|
|
let phys = sys.fn_ion_alloc(addr id)
|
|
if phys == 0: return false
|
|
|
|
out_pkt.id = id
|
|
out_pkt.phys = phys
|
|
out_pkt.len = 0
|
|
# In our identity-mapped unikernel, phys == virt
|
|
out_pkt.data = cast[ptr UncheckedArray[byte]](phys)
|
|
return true
|
|
|
|
proc ion_user_free*(pkt: IonPacket) {.exportc.} =
|
|
let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
|
|
if sys.magic == 0x4E585553 and sys.fn_ion_free != nil:
|
|
sys.fn_ion_free(pkt.id)
|
|
|
|
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)
|