rumpk/libs/membrane/libc.nim

100 lines
2.8 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) ---
# DISABLED: Using stubs.zig heap for NipBox stability
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
]#