rumpk/hal/channel.zig

107 lines
3.1 KiB
Zig

// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Sovereign Channels (Lock-Free Ring Buffers)
//!
//! Implements atomic lock-free ring buffers for ION packet communication.
//! Provides the "pipes" between kernel and userspace with invariant protection.
//!
//! SAFETY: All operations use atomic loads/stores with proper memory fences.
const std = @import("std");
pub const IonPacket = extern struct {
data: u64,
phys: u64,
len: u16,
id: u16,
_pad: u32, // Match Nim's 24-byte alignment
};
pub const CmdPacket = extern struct {
kind: u32,
_pad: u32, // Explicit Padding for 8-byte alignment
arg: u64,
id: u128, // SipHash Provenance (16 bytes)
};
// Size: 32 bytes (matches libs/membrane/ion.zig and core/ion.nim)
pub fn Ring(comptime T: type) type {
return extern struct {
head: u32,
tail: u32,
mask: u32,
data: [256]T,
};
}
// INVARIANT 1: The Handle Barrier
fn validate_ring_ptr(ptr: u64) void {
// 0x8000_0000 is kernel base, 0x8300_0000 is ION base.
if (ptr < 0x8000_0000) {
@panic("HAL: Invariant Violation - Invalid Ring Pointer");
}
}
fn pushGeneric(comptime T: type, ring: *Ring(T), pkt: T) bool {
const head = @atomicLoad(u32, &ring.head, .monotonic);
const tail = @atomicLoad(u32, &ring.tail, .monotonic);
// INVARIANT 2: Overflow Protection
const next = (head + 1) & ring.mask;
if (next == tail) {
return false;
}
ring.data[head & ring.mask] = pkt;
@atomicStore(u32, &ring.head, next, .release);
return true;
}
fn popGeneric(comptime T: type, ring: *Ring(T), out_pkt: *T) bool {
const head = @atomicLoad(u32, &ring.head, .monotonic);
const tail = @atomicLoad(u32, &ring.tail, .monotonic);
// INVARIANT 3: Underflow Protection
if (head == tail) {
return false;
}
// Ensure we see data written by producer before reading it
asm volatile ("fence r, rw" ::: .{ .memory = true });
out_pkt.* = ring.data[tail & ring.mask];
const next = (tail + 1) & ring.mask;
@atomicStore(u32, &ring.tail, next, .release);
return true;
}
// Exported ABI Functions (Hardened)
export fn hal_channel_push(handle: u64, pkt: IonPacket) bool {
validate_ring_ptr(handle);
const ring: *Ring(IonPacket) = @ptrFromInt(handle);
return pushGeneric(IonPacket, ring, pkt);
}
export fn hal_channel_pop(handle: u64, out_pkt: *IonPacket) bool {
validate_ring_ptr(handle);
const ring: *Ring(IonPacket) = @ptrFromInt(handle);
return popGeneric(IonPacket, ring, out_pkt);
}
export fn hal_cmd_push(handle: u64, pkt: CmdPacket) bool {
validate_ring_ptr(handle);
const ring: *Ring(CmdPacket) = @ptrFromInt(handle);
return pushGeneric(CmdPacket, ring, pkt);
}
export fn hal_cmd_pop(handle: u64, out_pkt: *CmdPacket) bool {
validate_ring_ptr(handle);
const ring: *Ring(CmdPacket) = @ptrFromInt(handle);
return popGeneric(CmdPacket, ring, out_pkt);
}