rumpk/core/ion/memory.nim

146 lines
4.3 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.
## Rumpk Layer 1: ION Slab Allocator
# ION Memory Manager
# The "Slab Allocator" for Zero-Copy IO
import ../ring
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
proc dbg(s: string) =
console_write(unsafeAddr s[0], csize_t(s.len))
var nl = "\n"
console_write(unsafeAddr nl[0], csize_t(1))
const
SLAB_SIZE* = 2048 # Max Packet Size (Ethernet Frame + Headroom)
POOL_COUNT* = 1024 # Number of packets in the pool (2MB total RAM)
POOL_ALIGN* = 4096 # VirtIO/Page Alignment
type
# The Physical Token representing a packet
IonPacket* = object
data*: ptr UncheckedArray[byte] # Virtual Address of payload
phys*: uint64 # Physical Address (For VirtIO/DMA)
len*: uint16 # Actual data length
id*: uint16 # The Token ID (Slab Index)
# The Monolithic Memory Pool
PacketPool = object
# We use 'align' to ensure the buffer starts on a page boundary for VirtIO
buffer {.align: POOL_ALIGN.}: array[SLAB_SIZE * POOL_COUNT, byte]
free_ring: RingBuffer[uint16, POOL_COUNT] # Stores IDs of free slabs
base_phys: uint64
var global_pool: PacketPool
proc ion_pool_init*() {.exportc.} =
## Initialize the DMA Pool with REAL Physical Address
dbg("[ION] Initializing Pool...")
# 1. Get the VIRTUAL address of the static buffer
let virt_addr = cast[uint64](addr global_pool.buffer[0])
# 2. Translate to PHYSICAL (Identity Mapped for Phase 7)
global_pool.base_phys = virt_addr
# Tracing for Phase 37
proc kprint_hex(v: uint64) {.importc, cdecl.}
dbg("[ION] Pool Base Phys: ")
kprint_hex(global_pool.base_phys)
dbg("")
dbg("[ION] Ring Init...")
global_pool.free_ring.init()
# Fill the free ring with all indices [0..1023]
dbg("[ION] Filling Slabs...")
var count = 0
for i in 0 ..< POOL_COUNT:
if global_pool.free_ring.push(uint16(i)):
inc count
dbg("[ION] Pool Ready.")
proc ion_alloc*(): IonPacket {.exportc.} =
## O(1) Allocation. Returns an empty packet struct.
## If OOM, returns packet with data = nil
var pkt: IonPacket
let (ok, idx) = global_pool.free_ring.pop()
if not ok:
dbg("[ION] ALLOC FAILED (Empty Ring?)")
pkt.data = nil
return pkt
pkt.id = idx
pkt.len = 0
# Calculate Virtual Address
let offset = int(idx) * SLAB_SIZE
pkt.data = cast[ptr UncheckedArray[byte]](addr global_pool.buffer[offset])
# Calculate Physical Address (1:1 map for Phase 7)
pkt.phys = global_pool.base_phys + uint64(offset)
return pkt
proc ion_free*(pkt: IonPacket) {.exportc.} =
## O(1) Free. Returns the token to the ring.
if pkt.data == nil: return
discard global_pool.free_ring.push(pkt.id)
# Helper for C/Zig Interop (Pure Pointers)
# Return physical address of a allocated block, put ID in out_id
proc ion_alloc_raw*(out_id: ptr uint16): uint64 {.exportc, cdecl.} =
let pkt = ion_alloc()
if pkt.data == nil: return 0
out_id[] = pkt.id
return pkt.phys
proc ion_free_raw*(id: uint16) {.exportc, cdecl.} =
var pkt: IonPacket
pkt.id = id
# We don't reconstruct data/phys for free, just push ID
# But for safety we might check bounds? Ring handles it.
pkt.data = cast[ptr UncheckedArray[byte]](1) # Dummy non-nil
ion_free(pkt)
proc ion_get_virt*(id: uint16): ptr byte {.exportc.} =
let offset = int(id) * SLAB_SIZE
return addr global_pool.buffer[offset]
proc ion_get_phys*(id: uint16): uint64 {.exportc.} =
let offset = int(id) * SLAB_SIZE
return global_pool.base_phys + uint64(offset)
# =========================================================
# The Global TX Ring (Multiplexing)
# =========================================================
var global_tx_ring*: RingBuffer[IonPacket, 256]
proc ion_tx_init*() {.exportc.} =
global_tx_ring.init()
proc ion_tx_push*(pkt: IonPacket): bool {.exportc.} =
global_tx_ring.push(pkt)
proc ion_tx_pop*(out_id: ptr uint16, out_len: ptr uint16): bool {.exportc.} =
if global_tx_ring.isEmpty:
return false
let (ok, pkt) = global_tx_ring.pop()
if not ok: return false
out_id[] = pkt.id
out_len[] = pkt.len
return true