# 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.} # Phase 36.2: Network Membrane s_net_rx*: pointer # Kernel -> User (RX) s_net_tx*: pointer # User -> Kernel (TX) 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.} = when defined(is_membrane): let sys = get_sys_table() 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) proc ion_user_alloc*(out_pkt: ptr IonPacket): bool {.exportc.} = var pkt = ion_alloc() if pkt.data == nil: return false out_pkt[] = pkt return true proc ion_user_free*(pkt: IonPacket) {.exportc.} = ion_free(pkt) 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 # --- 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