96 lines
2.7 KiB
Nim
96 lines
2.7 KiB
Nim
import socket
|
|
import ../../core/ion/memory
|
|
import ion_client
|
|
|
|
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
|
|
|
# --- Heap Allocator (Slab Backed) ---
|
|
const HEADER_SIZE = 32
|
|
|
|
proc malloc*(size: csize_t): pointer {.exportc, cdecl.} =
|
|
if size > (2048 - HEADER_SIZE): return nil
|
|
|
|
var pkt: IonPacket
|
|
if not ion_user_alloc(addr pkt): return nil
|
|
|
|
if pkt.data == nil: return nil
|
|
|
|
# Store metadata at the start of the slab
|
|
var header_ptr = cast[ptr IonPacket](pkt.data)
|
|
header_ptr[] = pkt
|
|
|
|
# Return pointer after header
|
|
return cast[pointer](cast[uint](pkt.data) + uint(HEADER_SIZE))
|
|
|
|
proc free*(p: pointer) {.exportc, cdecl.} =
|
|
if p == nil: return
|
|
|
|
# Recover Metadata
|
|
let slab_addr = cast[uint](p) - uint(HEADER_SIZE)
|
|
let header_ptr = cast[ptr IonPacket](slab_addr)
|
|
|
|
# Free using the stored packet (contains correct ID)
|
|
ion_user_free(header_ptr[])
|
|
|
|
proc sleep*(seconds: uint32) {.exportc, cdecl.} =
|
|
# Busy loop sleep
|
|
var i: int = 0
|
|
let limit = int(seconds) * 50_000_000
|
|
while i < limit:
|
|
i += 1
|
|
|
|
# Basic SockAddr struct match (IPv4)
|
|
type
|
|
SockAddrIn = object
|
|
sin_family: uint16
|
|
sin_port: uint16
|
|
sin_addr: uint32
|
|
sin_zero: array[8, char]
|
|
|
|
proc socket*(domain, sock_type, protocol: int): int {.exportc, cdecl.} =
|
|
# Domain=2 (AF_INET), Type=1 (SOCK_STREAM)
|
|
# We ignore them for now and just give a Nexus Socket
|
|
return new_socket()
|
|
|
|
proc connect*(fd: int, sock_addr: pointer, len: int): int {.exportc, cdecl.} =
|
|
if sock_addr == nil: return -1
|
|
|
|
# Cast raw pointer to SockAddrIn
|
|
let sin = cast[ptr SockAddrIn](sock_addr)
|
|
|
|
# Call the Shim
|
|
# Note: Linux sockaddr_in is Big Endian for Port/IP usually
|
|
# NPK is likely running the same endianness as Kernel (Little Endian on RISC-V/x86)
|
|
# But `connect` expects Network Byte Order (Big Endian).
|
|
# We pass it raw to connect_flow, which will store it.
|
|
|
|
return connect_flow(fd, sin.sin_addr, sin.sin_port)
|
|
|
|
proc write*(fd: cint, buf: pointer, count: csize_t): int {.exportc, cdecl.} =
|
|
if fd == 1 or fd == 2:
|
|
when defined(is_kernel):
|
|
# 1. Allocate a Console Slab
|
|
var pkt = ion_alloc()
|
|
if pkt.data == nil: return -1
|
|
|
|
# 2. Copy the string (Cap at SLAB_SIZE)
|
|
let safe_count = min(int(count), SLAB_SIZE)
|
|
copyMem(pkt.data, buf, safe_count)
|
|
pkt.len = uint16(safe_count)
|
|
|
|
# 3. Push to KERNEL CONSOLE (Port 0)
|
|
ion_egress_to_port(0, pkt)
|
|
|
|
return int(safe_count)
|
|
else:
|
|
# Membrane side: Direct to UART for Phase 7
|
|
console_write(buf, count)
|
|
return int(count)
|
|
|
|
# Handle Sockets (fd > 2)
|
|
return send_flow(int(fd), buf, int(count))
|
|
|
|
proc read*(fd: int, buf: pointer, count: int): int {.exportc, cdecl.} =
|
|
# TODO: Lookup socket, check RX ring
|
|
return -1 # EBADF
|