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
//! Kernel operation codes for the submission ring.
//!
//! Each [`KernelOp`] represents a primitive operation the kernel provides.
//! Operations are grouped by category:
//!
//! - `0x00xx` — Memory (map, unmap, protect)
//! - `0x01xx` — Scheduling (yield, threads, futex)
//! - `0x02xx` — Time (clocks, random)
//! - `0x04xx` — VFS (open, read, write, stat)
//! - `0x05xx` — Network (TCP, UDP)
//! - `0x06xx` — Signals
//! - `0x0Fxx` — Debug
//! - `0x10xx` — Domain lifecycle
//!
//! # Argument conventions
//!
//! All operations use the 5-element `args` array in [`SubmitEntry`](crate::SubmitEntry):
//! - Memory: `[addr, len, prot/flags, 0, 0]`
//! - VFS: `[handle, user_buf, len, offset, flags]`
//! - Network: `[handle, user_buf, len, addr_ptr, addrlen]`

/// Kernel operation codes.
///
/// Discriminant values are stable across versions for ABI compatibility.
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KernelOp {
    // Memory (0x00xx)
    /// Map anonymous memory. Args: `[addr_hint, len, prot, flags, 0]`
    MapAnonymous = 0x0001,
    /// Unmap memory. Args: `[addr, len, 0, 0, 0]`
    Munmap = 0x0002,
    /// Change protection. Args: `[addr, len, prot, 0, 0]`
    Mprotect = 0x0003,
    /// Read from domain memory. Args: `[user_addr, kernel_buf_id, len, 0, 0]`
    ReadUser = 0x0004,
    /// Write to domain memory. Args: `[user_addr, kernel_buf_id, len, 0, 0]`
    WriteUser = 0x0005,

    // Scheduling (0x01xx)
    /// Yield CPU. Args: `[0, 0, 0, 0, 0]`
    Yield = 0x0100,
    /// Block thread. Args: `[timeout_ns, 0, 0, 0, 0]`
    BlockThread = 0x0101,
    /// Create thread. Args: `[entry, stack_top, arg, tls, flags]`
    ThreadCreate = 0x0102,
    /// Exit thread. Args: `[exit_code, 0, 0, 0, 0]`
    ThreadExit = 0x0103,
    /// Wake futex waiters. Args: `[addr, count, 0, 0, 0]`
    FutexWake = 0x0104,

    // Time (0x02xx)
    /// Get time in nanoseconds. Args: `[clock_id, 0, 0, 0, 0]`
    GetTimeNs = 0x0200,
    /// Fill buffer with random bytes. Args: `[user_buf, len, flags, 0, 0]`
    GetRandom = 0x0201,

    // VFS (0x04xx)
    /// Open file. Args: `[path_ptr, path_len, flags, mode, 0]`
    VfsOpen = 0x0400,
    /// Read file. Args: `[handle, user_buf, len, offset, 0]`
    VfsRead = 0x0401,
    /// Write file. Args: `[handle, user_buf, len, offset, 0]`
    VfsWrite = 0x0402,
    /// Stat file. Args: `[handle, statbuf, 0, 0, 0]`
    VfsStat = 0x0403,
    /// Close file. Args: `[handle, 0, 0, 0, 0]`
    VfsClose = 0x0404,
    /// Seek. Args: `[handle, offset, whence, 0, 0]`
    VfsSeek = 0x0405,
    /// Truncate. Args: `[handle, length, 0, 0, 0]`
    VfsTruncate = 0x0406,
    /// Sync to storage. Args: `[handle, flags, 0, 0, 0]`
    VfsSync = 0x0407,

    // Network (0x05xx)
    /// TCP connect. Args: `[sockaddr_ptr, addrlen, 0, 0, 0]`
    NetConnect = 0x0500,
    /// TCP listen. Args: `[sockaddr_ptr, addrlen, backlog, 0, 0]`
    NetListen = 0x0501,
    /// Accept connection. Args: `[listener, peer_addr_ptr, peer_addrlen_ptr, 0, 0]`
    NetAccept = 0x0502,
    /// Send data. Args: `[handle, user_buf, len, flags, 0]`
    NetSend = 0x0503,
    /// Receive data. Args: `[handle, user_buf, len, flags, 0]`
    NetRecv = 0x0504,
    /// Close network handle. Args: `[handle, 0, 0, 0, 0]`
    NetClose = 0x0505,
    /// Bind UDP socket. Args: `[sockaddr_ptr, addrlen, 0, 0, 0]`
    NetUdpBind = 0x0510,
    /// Send UDP datagram. Args: `[handle, user_buf, len, dest_addr_ptr, dest_addrlen]`
    NetUdpSend = 0x0511,
    /// Receive UDP datagram. Args: `[handle, user_buf, len, src_addr_ptr, src_addrlen_ptr]`
    NetUdpRecv = 0x0512,

    // Signals (0x06xx)
    /// Send signal. Args: `[target_domain, signum, 0, 0, 0]`
    SendSignal = 0x0600,
    /// Check pending signals. Args: `[0, 0, 0, 0, 0]`
    CheckSignals = 0x0601,

    // Debug (0x0Fxx)
    /// Write to debug console. Args: `[user_buf, len, 0, 0, 0]`
    DebugPrint = 0x0F00,

    // Domain lifecycle (0x10xx)
    /// Terminate domain. Args: `[exit_code, 0, 0, 0, 0]`
    DomainExit = 0x1000,
    /// Get domain ID. Args: `[0, 0, 0, 0, 0]`
    GetDomainId = 0x1001,
    /// Get parent domain ID. Args: `[0, 0, 0, 0, 0]`
    GetParentId = 0x1002,
}

impl KernelOp {
    /// Create from raw opcode. Returns `None` for unrecognized values.
    pub fn from_u16(value: u16) -> Option<Self> {
        match value {
            0x0001 => Some(Self::MapAnonymous),
            0x0002 => Some(Self::Munmap),
            0x0003 => Some(Self::Mprotect),
            0x0004 => Some(Self::ReadUser),
            0x0005 => Some(Self::WriteUser),
            0x0100 => Some(Self::Yield),
            0x0101 => Some(Self::BlockThread),
            0x0102 => Some(Self::ThreadCreate),
            0x0103 => Some(Self::ThreadExit),
            0x0104 => Some(Self::FutexWake),
            0x0200 => Some(Self::GetTimeNs),
            0x0201 => Some(Self::GetRandom),
            0x0400 => Some(Self::VfsOpen),
            0x0401 => Some(Self::VfsRead),
            0x0402 => Some(Self::VfsWrite),
            0x0403 => Some(Self::VfsStat),
            0x0404 => Some(Self::VfsClose),
            0x0405 => Some(Self::VfsSeek),
            0x0406 => Some(Self::VfsTruncate),
            0x0407 => Some(Self::VfsSync),
            0x0500 => Some(Self::NetConnect),
            0x0501 => Some(Self::NetListen),
            0x0502 => Some(Self::NetAccept),
            0x0503 => Some(Self::NetSend),
            0x0504 => Some(Self::NetRecv),
            0x0505 => Some(Self::NetClose),
            0x0510 => Some(Self::NetUdpBind),
            0x0511 => Some(Self::NetUdpSend),
            0x0512 => Some(Self::NetUdpRecv),
            0x0600 => Some(Self::SendSignal),
            0x0601 => Some(Self::CheckSignals),
            0x0F00 => Some(Self::DebugPrint),
            0x1000 => Some(Self::DomainExit),
            0x1001 => Some(Self::GetDomainId),
            0x1002 => Some(Self::GetParentId),
            _ => None,
        }
    }

    /// Operation name for diagnostics.
    pub const fn name(&self) -> &'static str {
        match self {
            Self::MapAnonymous => "MapAnonymous",
            Self::Munmap => "Munmap",
            Self::Mprotect => "Mprotect",
            Self::ReadUser => "ReadUser",
            Self::WriteUser => "WriteUser",
            Self::Yield => "Yield",
            Self::BlockThread => "BlockThread",
            Self::ThreadCreate => "ThreadCreate",
            Self::ThreadExit => "ThreadExit",
            Self::FutexWake => "FutexWake",
            Self::GetTimeNs => "GetTimeNs",
            Self::GetRandom => "GetRandom",
            Self::VfsOpen => "VfsOpen",
            Self::VfsRead => "VfsRead",
            Self::VfsWrite => "VfsWrite",
            Self::VfsStat => "VfsStat",
            Self::VfsClose => "VfsClose",
            Self::VfsSeek => "VfsSeek",
            Self::VfsTruncate => "VfsTruncate",
            Self::VfsSync => "VfsSync",
            Self::NetConnect => "NetConnect",
            Self::NetListen => "NetListen",
            Self::NetAccept => "NetAccept",
            Self::NetSend => "NetSend",
            Self::NetRecv => "NetRecv",
            Self::NetClose => "NetClose",
            Self::NetUdpBind => "NetUdpBind",
            Self::NetUdpSend => "NetUdpSend",
            Self::NetUdpRecv => "NetUdpRecv",
            Self::SendSignal => "SendSignal",
            Self::CheckSignals => "CheckSignals",
            Self::DebugPrint => "DebugPrint",
            Self::DomainExit => "DomainExit",
            Self::GetDomainId => "GetDomainId",
            Self::GetParentId => "GetParentId",
        }
    }

    /// Whether this operation can be batched (doesn't block or exit).
    pub const fn is_nonblocking(&self) -> bool {
        match self {
            Self::BlockThread | Self::ThreadExit | Self::DomainExit => false,
            _ => true,
        }
    }
}

/// Memory protection flags (POSIX PROT_*).
pub mod prot {
    pub const NONE: u32 = 0;
    pub const READ: u32 = 1;
    pub const WRITE: u32 = 2;
    pub const EXEC: u32 = 4;
}

/// Memory map flags.
pub mod map {
    pub const FIXED: u32 = 1;
    pub const POPULATE: u32 = 2;
}

/// File open flags (POSIX O_*).
pub mod open {
    pub const RDONLY: u32 = 0;
    pub const WRONLY: u32 = 1;
    pub const RDWR: u32 = 2;
    pub const CREAT: u32 = 0x40;
    pub const EXCL: u32 = 0x80;
    pub const TRUNC: u32 = 0x200;
    pub const APPEND: u32 = 0x400;
    pub const NONBLOCK: u32 = 0x800;
    pub const DIRECTORY: u32 = 0x10000;
    pub const CLOEXEC: u32 = 0x80000;
}

/// Seek whence values.
pub mod seek {
    pub const SET: u32 = 0;
    pub const CUR: u32 = 1;
    pub const END: u32 = 2;
}

/// Clock IDs.
pub mod clock {
    pub const REALTIME: u32 = 0;
    pub const MONOTONIC: u32 = 1;
}

/// Syscall number for SYS_SUBMIT.
pub const SYS_SUBMIT: u64 = 500;

/// Maximum operations per SYS_SUBMIT call (bounds WCET for DO-178C).
pub const MAX_SUBMIT_COUNT: u32 = 64;