ukernel-sys 0.1.0

System interface types for µKernel — a Rust microkernel with hypervisor and real-time scheduling. Defines kernel operations, submission ring layout, and subsystem registration.
Documentation
//! Submission ring for batched kernel operations.
//!
//! Userspace queues [`SubmitEntry`] operations into the ring and flushes
//! them with a single `SYS_SUBMIT` syscall. The kernel processes all entries,
//! capability-checks each one, and writes [`CompleteEntry`] results.
//!
//! One ring transition for N operations. Security enforcement is per-operation
//! (every capability is checked), but the transition cost is amortized.
//!
//! # Memory layout
//!
//! The ring is a shared page mapped into both kernel and domain address space.
//! Synchronization uses atomic indices with acquire/release ordering.

/// Number of entries in the ring. Sized to fit in a page with completions.
pub const RING_SIZE: usize = 64;

/// Fixed virtual address for the ring in domain address space.
pub const RING_VADDR: u64 = 0x7FFF_0000_0000;

/// Submission entry — a single kernel operation request.
///
/// Written by userspace, read by kernel. Each entry is cache-line aligned
/// to prevent false sharing.
#[repr(C, align(64))]
#[derive(Clone, Copy)]
pub struct SubmitEntry {
    /// Operation code ([`KernelOp`](crate::KernelOp) discriminant).
    pub opcode: u16,
    /// Per-operation flags (see [`submit_flags`]).
    pub flags: u16,
    /// Reserved.
    pub _reserved: u32,
    /// Operation-specific arguments. Meaning depends on opcode.
    pub args: [u64; 5],
    /// Opaque user token, returned in the corresponding [`CompleteEntry`].
    pub user_data: u64,
}

impl Default for SubmitEntry {
    fn default() -> Self {
        Self {
            opcode: 0,
            flags: 0,
            _reserved: 0,
            args: [0; 5],
            user_data: 0,
        }
    }
}

impl SubmitEntry {
    /// Create a submission entry.
    #[inline]
    pub const fn new(opcode: u16, args: [u64; 5], user_data: u64) -> Self {
        Self {
            opcode,
            flags: 0,
            _reserved: 0,
            args,
            user_data,
        }
    }
}

/// Submission entry flags.
pub mod submit_flags {
    /// Request completion notification even on success.
    pub const NEED_COMPLETION: u16 = 1 << 0;
    /// Barrier — flush all pending operations before this one.
    pub const BARRIER: u16 = 1 << 1;
    /// Hint that more operations follow.
    pub const MORE_COMING: u16 = 1 << 2;
}

/// Completion entry — kernel's response to a submission.
///
/// Written by kernel, read by userspace. The `user_data` field matches
/// the value from the corresponding [`SubmitEntry`].
#[repr(C, align(16))]
#[derive(Clone, Copy, Default)]
pub struct CompleteEntry {
    /// Result value. Positive/zero = success, negative = -errno.
    pub result: i64,
    /// User token from the corresponding [`SubmitEntry`].
    pub user_data: u64,
    /// Completion flags (see [`complete_flags`]).
    pub flags: u16,
    /// Reserved.
    pub _reserved: [u8; 6],
}

impl CompleteEntry {
    /// Create a completion entry.
    #[inline]
    pub const fn new(result: i64, user_data: u64) -> Self {
        Self {
            result,
            user_data,
            flags: 0,
            _reserved: [0; 6],
        }
    }

    /// Whether the operation succeeded.
    #[inline]
    pub fn is_ok(&self) -> bool {
        self.result >= 0
    }

    /// Error code if the operation failed.
    #[inline]
    pub fn error(&self) -> Option<i32> {
        if self.result < 0 {
            Some((-self.result) as i32)
        } else {
            None
        }
    }
}

/// Completion flags (kernel → domain notifications).
pub mod complete_flags {
    /// A signal is pending — check signal state after processing.
    pub const SIGNAL_PENDING: u16 = 1 << 0;
    /// A timer expired — check timer state.
    pub const TIMER_EXPIRED: u16 = 1 << 1;
}

/// Shared-memory ring buffer mapped into both kernel and domain.
///
/// This struct defines the memory layout. The actual ring is initialized
/// by the kernel and mapped at [`RING_VADDR`] in the domain's address space.
///
/// Synchronization protocol:
/// 1. Domain writes entries, advances `submit_head` (Release)
/// 2. Domain calls `SYS_SUBMIT`
/// 3. Kernel reads entries from `submit_tail` to `submit_head` (Acquire)
/// 4. Kernel writes completions, advances `complete_head` (Release)
/// 5. Domain reads completions from `complete_tail` to `complete_head` (Acquire)
#[repr(C)]
pub struct SubmitRing {
    /// Next slot for userspace to write (producer).
    pub submit_head: u32,
    /// Next slot for kernel to process (consumer).
    pub submit_tail: u32,
    /// Next completion slot for kernel to write (producer).
    pub complete_head: u32,
    /// Next completion slot for userspace to read (consumer).
    pub complete_tail: u32,
    /// Padding to cache-line boundary.
    pub _pad: [u8; 48],
    // Followed by:
    //   [SubmitEntry; RING_SIZE]    — submission entries
    //   [CompleteEntry; RING_SIZE]  — completion entries
}