1use core::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[must_use = "kernel errors must be handled, not silently discarded"]
11pub enum KernelError {
12 OutOfMemory {
14 requested: usize,
15 available: usize,
16 },
17 InvalidAddress {
18 addr: usize,
19 },
20 UnmappedMemory {
21 addr: usize,
22 },
23
24 InvalidCapability {
26 cap_id: u64,
27 reason: CapError,
28 },
29 InsufficientRights {
30 required: u16,
31 actual: u16,
32 },
33 CapabilityRevoked {
34 cap_id: u64,
35 },
36
37 ProcessNotFound {
39 pid: u64,
40 },
41 ThreadNotFound {
42 tid: u64,
43 },
44 InvalidState {
45 expected: &'static str,
46 actual: &'static str,
47 },
48
49 IpcError(IpcError),
51
52 SchedulerError(SchedError),
54
55 SyscallError(SyscallError),
57
58 FsError(FsError),
60
61 HardwareError {
63 device: &'static str,
64 code: u32,
65 },
66
67 InvalidArgument {
69 name: &'static str,
70 value: &'static str,
71 },
72 OperationNotSupported {
73 operation: &'static str,
74 },
75 ResourceExhausted {
76 resource: &'static str,
77 },
78 PermissionDenied {
79 operation: &'static str,
80 },
81 AlreadyExists {
82 resource: &'static str,
83 id: u64,
84 },
85 NotFound {
86 resource: &'static str,
87 id: u64,
88 },
89 Timeout {
90 operation: &'static str,
91 duration_ms: u64,
92 },
93 NotImplemented {
94 feature: &'static str,
95 },
96 WouldBlock,
98 BrokenPipe,
100 NotInitialized {
102 subsystem: &'static str,
103 },
104 LegacyError {
107 message: &'static str,
108 },
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub enum CapError {
114 InvalidCapability,
115 InsufficientRights,
116 CapabilityRevoked,
117 InvalidObject,
118 PermissionDenied,
119 AlreadyExists,
120 NotFound,
121 IdExhausted,
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub enum IpcError {
127 InvalidEndpoint { id: u64 },
128 InvalidChannel { id: u64 },
129 MessageTooLarge { size: usize, max: usize },
130 QueueFull { capacity: usize },
131 QueueEmpty,
132 InvalidCapability,
133 ProcessNotFound { pid: u64 },
134 EndpointNotFound { id: u64 },
135 PermissionDenied,
136 WouldBlock,
137 Timeout,
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
142pub enum SchedError {
143 InvalidPriority { priority: u8 },
144 InvalidCpuId { cpu: usize },
145 TaskNotFound { id: u64 },
146 CpuOffline { cpu: usize },
147 InvalidAffinity,
148 QueueEmpty,
149 AlreadyScheduled,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub enum SyscallError {
155 InvalidSyscall { nr: usize },
156 InvalidArgument { arg: usize },
157 InvalidPointer { addr: usize },
158 BufferTooSmall { required: usize, provided: usize },
159 StringTooLong { max: usize },
160 AccessDenied,
161 NotImplemented,
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166pub enum FsError {
167 NotFound,
169 AlreadyExists,
171 PermissionDenied,
173 NotADirectory,
175 NotAFile,
177 IsADirectory,
179 ReadOnly,
181 InvalidPath,
183 NoRootFs,
185 AlreadyMounted,
187 NotMounted,
189 UnknownFsType,
191 IoError,
193 DirectoryNotEmpty,
195 TooManyOpenFiles,
197 BadFileDescriptor,
199 NotSupported,
201 NotASymlink,
203 FileTooLarge,
205 CorruptedData,
207 SymlinkLoop,
209 NoSpace,
211}
212
213pub type KernelResult<T> = Result<T, KernelError>;
215
216impl fmt::Display for KernelError {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 match self {
219 Self::OutOfMemory {
220 requested,
221 available,
222 } => {
223 write!(
224 f,
225 "Out of memory: requested {} bytes, {} available",
226 requested, available
227 )
228 }
229 Self::InvalidAddress { addr } => write!(f, "Invalid address: 0x{:x}", addr),
230 Self::UnmappedMemory { addr } => write!(f, "Unmapped memory at 0x{:x}", addr),
231 Self::InvalidCapability { cap_id, reason } => {
232 write!(f, "Invalid capability {}: {:?}", cap_id, reason)
233 }
234 Self::InsufficientRights { required, actual } => {
235 write!(
236 f,
237 "Insufficient rights: required 0x{:x}, have 0x{:x}",
238 required, actual
239 )
240 }
241 Self::CapabilityRevoked { cap_id } => {
242 write!(f, "Capability {} has been revoked", cap_id)
243 }
244 Self::ProcessNotFound { pid } => write!(f, "Process {} not found", pid),
245 Self::ThreadNotFound { tid } => write!(f, "Thread {} not found", tid),
246 Self::InvalidState { expected, actual } => {
247 write!(f, "Invalid state: expected {}, got {}", expected, actual)
248 }
249 Self::IpcError(e) => write!(f, "IPC error: {:?}", e),
250 Self::SchedulerError(e) => write!(f, "Scheduler error: {:?}", e),
251 Self::SyscallError(e) => write!(f, "Syscall error: {:?}", e),
252 Self::HardwareError { device, code } => {
253 write!(f, "Hardware error on {}: code 0x{:x}", device, code)
254 }
255 Self::InvalidArgument { name, value } => {
256 write!(f, "Invalid argument '{}': {}", name, value)
257 }
258 Self::OperationNotSupported { operation } => {
259 write!(f, "Operation not supported: {}", operation)
260 }
261 Self::ResourceExhausted { resource } => write!(f, "Resource exhausted: {}", resource),
262 Self::PermissionDenied { operation } => {
263 write!(f, "Permission denied for operation: {}", operation)
264 }
265 Self::AlreadyExists { resource, id } => {
266 write!(f, "{} with id {} already exists", resource, id)
267 }
268 Self::NotFound { resource, id } => write!(f, "{} with id {} not found", resource, id),
269 Self::Timeout {
270 operation,
271 duration_ms,
272 } => {
273 write!(f, "Timeout during {}: {} ms", operation, duration_ms)
274 }
275 Self::NotImplemented { feature } => {
276 write!(f, "Feature not implemented: {}", feature)
277 }
278 Self::WouldBlock => write!(f, "Operation would block"),
279 Self::BrokenPipe => write!(f, "Broken pipe"),
280 Self::FsError(e) => write!(f, "Filesystem error: {:?}", e),
281 Self::NotInitialized { subsystem } => {
282 write!(f, "Subsystem not initialized: {}", subsystem)
283 }
284 Self::LegacyError { message } => write!(f, "{}", message),
285 }
286 }
287}
288
289impl From<CapError> for KernelError {
291 fn from(err: CapError) -> Self {
292 match err {
293 CapError::InvalidCapability => Self::InvalidCapability {
294 cap_id: 0,
295 reason: err,
296 },
297 CapError::InsufficientRights => Self::InsufficientRights {
298 required: 0,
299 actual: 0,
300 },
301 CapError::CapabilityRevoked => Self::CapabilityRevoked { cap_id: 0 },
302 CapError::IdExhausted => Self::ResourceExhausted {
303 resource: "capability IDs",
304 },
305 _ => Self::InvalidCapability {
306 cap_id: 0,
307 reason: err,
308 },
309 }
310 }
311}
312
313impl From<IpcError> for KernelError {
314 fn from(err: IpcError) -> Self {
315 Self::IpcError(err)
316 }
317}
318
319impl From<SchedError> for KernelError {
320 fn from(err: SchedError) -> Self {
321 Self::SchedulerError(err)
322 }
323}
324
325impl From<SyscallError> for KernelError {
326 fn from(err: SyscallError) -> Self {
327 Self::SyscallError(err)
328 }
329}
330
331impl From<FsError> for KernelError {
332 fn from(err: FsError) -> Self {
333 Self::FsError(err)
334 }
335}
336
337impl From<&'static str> for KernelError {
343 fn from(msg: &'static str) -> Self {
344 Self::LegacyError { message: msg }
345 }
346}
347
348#[macro_export]
350macro_rules! kernel_error {
351 (OutOfMemory { requested: $req:expr, available: $avail:expr }) => {
352 $crate::error::KernelError::OutOfMemory {
353 requested: $req,
354 available: $avail,
355 }
356 };
357 (ProcessNotFound { pid: $pid:expr }) => {
358 $crate::error::KernelError::ProcessNotFound { pid: $pid }
359 };
360 (InvalidArgument { $name:expr => $value:expr }) => {
361 $crate::error::KernelError::InvalidArgument {
362 name: $name,
363 value: $value,
364 }
365 };
366 ($variant:ident) => {
367 $crate::error::KernelError::$variant
368 };
369}
370
371#[cfg(test)]
372mod tests {
373 use alloc::string::ToString;
374
375 use super::*;
376
377 #[test]
380 fn test_kernel_error_out_of_memory_equality() {
381 let e1 = KernelError::OutOfMemory {
382 requested: 4096,
383 available: 0,
384 };
385 let e2 = KernelError::OutOfMemory {
386 requested: 4096,
387 available: 0,
388 };
389 assert_eq!(e1, e2);
390 }
391
392 #[test]
393 fn test_kernel_error_out_of_memory_inequality() {
394 let e1 = KernelError::OutOfMemory {
395 requested: 4096,
396 available: 0,
397 };
398 let e2 = KernelError::OutOfMemory {
399 requested: 8192,
400 available: 0,
401 };
402 assert_ne!(e1, e2);
403 }
404
405 #[test]
406 fn test_kernel_error_clone() {
407 let e1 = KernelError::InvalidAddress { addr: 0xDEAD };
408 let e2 = e1;
409 assert_eq!(e1, e2);
410 }
411
412 #[test]
415 fn test_display_out_of_memory() {
416 let e = KernelError::OutOfMemory {
417 requested: 1024,
418 available: 512,
419 };
420 let s = e.to_string();
421 assert!(s.contains("1024"));
422 assert!(s.contains("512"));
423 assert!(s.contains("Out of memory"));
424 }
425
426 #[test]
427 fn test_display_invalid_address() {
428 let e = KernelError::InvalidAddress { addr: 0xCAFE };
429 let s = e.to_string();
430 assert!(s.contains("cafe"));
431 assert!(s.contains("Invalid address"));
432 }
433
434 #[test]
435 fn test_display_process_not_found() {
436 let e = KernelError::ProcessNotFound { pid: 42 };
437 let s = e.to_string();
438 assert!(s.contains("42"));
439 assert!(s.contains("not found"));
440 }
441
442 #[test]
443 fn test_display_would_block() {
444 let e = KernelError::WouldBlock;
445 assert_eq!(e.to_string(), "Operation would block");
446 }
447
448 #[test]
449 fn test_display_broken_pipe() {
450 let e = KernelError::BrokenPipe;
451 assert_eq!(e.to_string(), "Broken pipe");
452 }
453
454 #[test]
455 fn test_display_legacy_error() {
456 let e = KernelError::LegacyError {
457 message: "old error",
458 };
459 assert_eq!(e.to_string(), "old error");
460 }
461
462 #[test]
463 fn test_display_timeout() {
464 let e = KernelError::Timeout {
465 operation: "read",
466 duration_ms: 5000,
467 };
468 let s = e.to_string();
469 assert!(s.contains("read"));
470 assert!(s.contains("5000"));
471 }
472
473 #[test]
476 fn test_from_ipc_error() {
477 let ipc = IpcError::QueueEmpty;
478 let ke: KernelError = ipc.into();
479 assert_eq!(ke, KernelError::IpcError(IpcError::QueueEmpty));
480 }
481
482 #[test]
483 fn test_from_sched_error() {
484 let se = SchedError::QueueEmpty;
485 let ke: KernelError = se.into();
486 assert_eq!(ke, KernelError::SchedulerError(SchedError::QueueEmpty));
487 }
488
489 #[test]
490 fn test_from_syscall_error() {
491 let se = SyscallError::AccessDenied;
492 let ke: KernelError = se.into();
493 assert_eq!(ke, KernelError::SyscallError(SyscallError::AccessDenied));
494 }
495
496 #[test]
497 fn test_from_fs_error() {
498 let fe = FsError::NotFound;
499 let ke: KernelError = fe.into();
500 assert_eq!(ke, KernelError::FsError(FsError::NotFound));
501 }
502
503 #[test]
504 fn test_from_static_str() {
505 let ke: KernelError = "something broke".into();
506 assert_eq!(
507 ke,
508 KernelError::LegacyError {
509 message: "something broke"
510 }
511 );
512 }
513
514 #[test]
515 fn test_from_cap_error_invalid() {
516 let ce = CapError::InvalidCapability;
517 let ke: KernelError = ce.into();
518 match ke {
519 KernelError::InvalidCapability { cap_id, reason } => {
520 assert_eq!(cap_id, 0);
521 assert_eq!(reason, CapError::InvalidCapability);
522 }
523 _ => panic!("Expected InvalidCapability variant"),
524 }
525 }
526
527 #[test]
528 fn test_from_cap_error_revoked() {
529 let ce = CapError::CapabilityRevoked;
530 let ke: KernelError = ce.into();
531 assert_eq!(ke, KernelError::CapabilityRevoked { cap_id: 0 });
532 }
533
534 #[test]
535 fn test_from_cap_error_id_exhausted() {
536 let ce = CapError::IdExhausted;
537 let ke: KernelError = ce.into();
538 assert_eq!(
539 ke,
540 KernelError::ResourceExhausted {
541 resource: "capability IDs"
542 }
543 );
544 }
545
546 #[test]
549 fn test_ipc_error_variants() {
550 assert_ne!(IpcError::QueueEmpty, IpcError::WouldBlock);
551 assert_eq!(IpcError::Timeout, IpcError::Timeout);
552 let e = IpcError::MessageTooLarge { size: 100, max: 64 };
553 assert_eq!(e, IpcError::MessageTooLarge { size: 100, max: 64 });
554 }
555
556 #[test]
557 fn test_fs_error_variants() {
558 assert_ne!(FsError::NotFound, FsError::AlreadyExists);
559 assert_eq!(FsError::IoError, FsError::IoError);
560 assert_ne!(FsError::IsADirectory, FsError::NotADirectory);
561 }
562}