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;