Skip to main content

ukernel_sys/
kernel_op.rs

1//! Kernel operation codes for the submission ring.
2//!
3//! Each [`KernelOp`] represents a primitive operation the kernel provides.
4//! Operations are grouped by category:
5//!
6//! - `0x00xx` — Memory (map, unmap, protect)
7//! - `0x01xx` — Scheduling (yield, threads, futex)
8//! - `0x02xx` — Time (clocks, random)
9//! - `0x04xx` — VFS (open, read, write, stat)
10//! - `0x05xx` — Network (TCP, UDP)
11//! - `0x06xx` — Signals
12//! - `0x0Fxx` — Debug
13//! - `0x10xx` — Domain lifecycle
14//!
15//! # Argument conventions
16//!
17//! All operations use the 5-element `args` array in [`SubmitEntry`](crate::SubmitEntry):
18//! - Memory: `[addr, len, prot/flags, 0, 0]`
19//! - VFS: `[handle, user_buf, len, offset, flags]`
20//! - Network: `[handle, user_buf, len, addr_ptr, addrlen]`
21
22/// Kernel operation codes.
23///
24/// Discriminant values are stable across versions for ABI compatibility.
25#[repr(u16)]
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum KernelOp {
28    // Memory (0x00xx)
29    /// Map anonymous memory. Args: `[addr_hint, len, prot, flags, 0]`
30    MapAnonymous = 0x0001,
31    /// Unmap memory. Args: `[addr, len, 0, 0, 0]`
32    Munmap = 0x0002,
33    /// Change protection. Args: `[addr, len, prot, 0, 0]`
34    Mprotect = 0x0003,
35    /// Read from domain memory. Args: `[user_addr, kernel_buf_id, len, 0, 0]`
36    ReadUser = 0x0004,
37    /// Write to domain memory. Args: `[user_addr, kernel_buf_id, len, 0, 0]`
38    WriteUser = 0x0005,
39
40    // Scheduling (0x01xx)
41    /// Yield CPU. Args: `[0, 0, 0, 0, 0]`
42    Yield = 0x0100,
43    /// Block thread. Args: `[timeout_ns, 0, 0, 0, 0]`
44    BlockThread = 0x0101,
45    /// Create thread. Args: `[entry, stack_top, arg, tls, flags]`
46    ThreadCreate = 0x0102,
47    /// Exit thread. Args: `[exit_code, 0, 0, 0, 0]`
48    ThreadExit = 0x0103,
49    /// Wake futex waiters. Args: `[addr, count, 0, 0, 0]`
50    FutexWake = 0x0104,
51
52    // Time (0x02xx)
53    /// Get time in nanoseconds. Args: `[clock_id, 0, 0, 0, 0]`
54    GetTimeNs = 0x0200,
55    /// Fill buffer with random bytes. Args: `[user_buf, len, flags, 0, 0]`
56    GetRandom = 0x0201,
57
58    // VFS (0x04xx)
59    /// Open file. Args: `[path_ptr, path_len, flags, mode, 0]`
60    VfsOpen = 0x0400,
61    /// Read file. Args: `[handle, user_buf, len, offset, 0]`
62    VfsRead = 0x0401,
63    /// Write file. Args: `[handle, user_buf, len, offset, 0]`
64    VfsWrite = 0x0402,
65    /// Stat file. Args: `[handle, statbuf, 0, 0, 0]`
66    VfsStat = 0x0403,
67    /// Close file. Args: `[handle, 0, 0, 0, 0]`
68    VfsClose = 0x0404,
69    /// Seek. Args: `[handle, offset, whence, 0, 0]`
70    VfsSeek = 0x0405,
71    /// Truncate. Args: `[handle, length, 0, 0, 0]`
72    VfsTruncate = 0x0406,
73    /// Sync to storage. Args: `[handle, flags, 0, 0, 0]`
74    VfsSync = 0x0407,
75
76    // Network (0x05xx)
77    /// TCP connect. Args: `[sockaddr_ptr, addrlen, 0, 0, 0]`
78    NetConnect = 0x0500,
79    /// TCP listen. Args: `[sockaddr_ptr, addrlen, backlog, 0, 0]`
80    NetListen = 0x0501,
81    /// Accept connection. Args: `[listener, peer_addr_ptr, peer_addrlen_ptr, 0, 0]`
82    NetAccept = 0x0502,
83    /// Send data. Args: `[handle, user_buf, len, flags, 0]`
84    NetSend = 0x0503,
85    /// Receive data. Args: `[handle, user_buf, len, flags, 0]`
86    NetRecv = 0x0504,
87    /// Close network handle. Args: `[handle, 0, 0, 0, 0]`
88    NetClose = 0x0505,
89    /// Bind UDP socket. Args: `[sockaddr_ptr, addrlen, 0, 0, 0]`
90    NetUdpBind = 0x0510,
91    /// Send UDP datagram. Args: `[handle, user_buf, len, dest_addr_ptr, dest_addrlen]`
92    NetUdpSend = 0x0511,
93    /// Receive UDP datagram. Args: `[handle, user_buf, len, src_addr_ptr, src_addrlen_ptr]`
94    NetUdpRecv = 0x0512,
95
96    // Signals (0x06xx)
97    /// Send signal. Args: `[target_domain, signum, 0, 0, 0]`
98    SendSignal = 0x0600,
99    /// Check pending signals. Args: `[0, 0, 0, 0, 0]`
100    CheckSignals = 0x0601,
101
102    // Debug (0x0Fxx)
103    /// Write to debug console. Args: `[user_buf, len, 0, 0, 0]`
104    DebugPrint = 0x0F00,
105
106    // Domain lifecycle (0x10xx)
107    /// Terminate domain. Args: `[exit_code, 0, 0, 0, 0]`
108    DomainExit = 0x1000,
109    /// Get domain ID. Args: `[0, 0, 0, 0, 0]`
110    GetDomainId = 0x1001,
111    /// Get parent domain ID. Args: `[0, 0, 0, 0, 0]`
112    GetParentId = 0x1002,
113}
114
115impl KernelOp {
116    /// Create from raw opcode. Returns `None` for unrecognized values.
117    pub fn from_u16(value: u16) -> Option<Self> {
118        match value {
119            0x0001 => Some(Self::MapAnonymous),
120            0x0002 => Some(Self::Munmap),
121            0x0003 => Some(Self::Mprotect),
122            0x0004 => Some(Self::ReadUser),
123            0x0005 => Some(Self::WriteUser),
124            0x0100 => Some(Self::Yield),
125            0x0101 => Some(Self::BlockThread),
126            0x0102 => Some(Self::ThreadCreate),
127            0x0103 => Some(Self::ThreadExit),
128            0x0104 => Some(Self::FutexWake),
129            0x0200 => Some(Self::GetTimeNs),
130            0x0201 => Some(Self::GetRandom),
131            0x0400 => Some(Self::VfsOpen),
132            0x0401 => Some(Self::VfsRead),
133            0x0402 => Some(Self::VfsWrite),
134            0x0403 => Some(Self::VfsStat),
135            0x0404 => Some(Self::VfsClose),
136            0x0405 => Some(Self::VfsSeek),
137            0x0406 => Some(Self::VfsTruncate),
138            0x0407 => Some(Self::VfsSync),
139            0x0500 => Some(Self::NetConnect),
140            0x0501 => Some(Self::NetListen),
141            0x0502 => Some(Self::NetAccept),
142            0x0503 => Some(Self::NetSend),
143            0x0504 => Some(Self::NetRecv),
144            0x0505 => Some(Self::NetClose),
145            0x0510 => Some(Self::NetUdpBind),
146            0x0511 => Some(Self::NetUdpSend),
147            0x0512 => Some(Self::NetUdpRecv),
148            0x0600 => Some(Self::SendSignal),
149            0x0601 => Some(Self::CheckSignals),
150            0x0F00 => Some(Self::DebugPrint),
151            0x1000 => Some(Self::DomainExit),
152            0x1001 => Some(Self::GetDomainId),
153            0x1002 => Some(Self::GetParentId),
154            _ => None,
155        }
156    }
157
158    /// Operation name for diagnostics.
159    pub const fn name(&self) -> &'static str {
160        match self {
161            Self::MapAnonymous => "MapAnonymous",
162            Self::Munmap => "Munmap",
163            Self::Mprotect => "Mprotect",
164            Self::ReadUser => "ReadUser",
165            Self::WriteUser => "WriteUser",
166            Self::Yield => "Yield",
167            Self::BlockThread => "BlockThread",
168            Self::ThreadCreate => "ThreadCreate",
169            Self::ThreadExit => "ThreadExit",
170            Self::FutexWake => "FutexWake",
171            Self::GetTimeNs => "GetTimeNs",
172            Self::GetRandom => "GetRandom",
173            Self::VfsOpen => "VfsOpen",
174            Self::VfsRead => "VfsRead",
175            Self::VfsWrite => "VfsWrite",
176            Self::VfsStat => "VfsStat",
177            Self::VfsClose => "VfsClose",
178            Self::VfsSeek => "VfsSeek",
179            Self::VfsTruncate => "VfsTruncate",
180            Self::VfsSync => "VfsSync",
181            Self::NetConnect => "NetConnect",
182            Self::NetListen => "NetListen",
183            Self::NetAccept => "NetAccept",
184            Self::NetSend => "NetSend",
185            Self::NetRecv => "NetRecv",
186            Self::NetClose => "NetClose",
187            Self::NetUdpBind => "NetUdpBind",
188            Self::NetUdpSend => "NetUdpSend",
189            Self::NetUdpRecv => "NetUdpRecv",
190            Self::SendSignal => "SendSignal",
191            Self::CheckSignals => "CheckSignals",
192            Self::DebugPrint => "DebugPrint",
193            Self::DomainExit => "DomainExit",
194            Self::GetDomainId => "GetDomainId",
195            Self::GetParentId => "GetParentId",
196        }
197    }
198
199    /// Whether this operation can be batched (doesn't block or exit).
200    pub const fn is_nonblocking(&self) -> bool {
201        match self {
202            Self::BlockThread | Self::ThreadExit | Self::DomainExit => false,
203            _ => true,
204        }
205    }
206}
207
208/// Memory protection flags (POSIX PROT_*).
209pub mod prot {
210    pub const NONE: u32 = 0;
211    pub const READ: u32 = 1;
212    pub const WRITE: u32 = 2;
213    pub const EXEC: u32 = 4;
214}
215
216/// Memory map flags.
217pub mod map {
218    pub const FIXED: u32 = 1;
219    pub const POPULATE: u32 = 2;
220}
221
222/// File open flags (POSIX O_*).
223pub mod open {
224    pub const RDONLY: u32 = 0;
225    pub const WRONLY: u32 = 1;
226    pub const RDWR: u32 = 2;
227    pub const CREAT: u32 = 0x40;
228    pub const EXCL: u32 = 0x80;
229    pub const TRUNC: u32 = 0x200;
230    pub const APPEND: u32 = 0x400;
231    pub const NONBLOCK: u32 = 0x800;
232    pub const DIRECTORY: u32 = 0x10000;
233    pub const CLOEXEC: u32 = 0x80000;
234}
235
236/// Seek whence values.
237pub mod seek {
238    pub const SET: u32 = 0;
239    pub const CUR: u32 = 1;
240    pub const END: u32 = 2;
241}
242
243/// Clock IDs.
244pub mod clock {
245    pub const REALTIME: u32 = 0;
246    pub const MONOTONIC: u32 = 1;
247}
248
249/// Syscall number for SYS_SUBMIT.
250pub const SYS_SUBMIT: u64 = 500;
251
252/// Maximum operations per SYS_SUBMIT call (bounds WCET for DO-178C).
253pub const MAX_SUBMIT_COUNT: u32 = 64;