Skip to main content

strat9_kernel/syscall/
error.rs

1//! Syscall error codes for Strat9-OS.
2//!
3//! Errors are returned as negative values in RAX, matching Linux errno conventions.
4//! The dispatcher converts `SyscallError` to a negative i64 stored in RAX as u64.
5
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive, thiserror::Error)]
9#[must_use]
10#[repr(i64)]
11pub enum SyscallError {
12    #[error("Operation not permitted")]
13    PermissionDenied = -1,
14    #[error("No such file or directory")]
15    NotFound = -2,
16    #[error("No such process")]
17    NoSuchProcess = -3,
18    #[error("Interrupted system call")]
19    Interrupted = -4,
20    #[error("Input/output error")]
21    IoError = -5,
22    #[error("Argument list too long")]
23    ArgumentListTooLong = -7,
24    #[error("Exec format error")]
25    ExecFormatError = -8,
26    #[error("Bad file descriptor")]
27    BadHandle = -9,
28    #[error("No child processes")]
29    NoChildren = -10,
30    #[error("Resource temporarily unavailable")]
31    Again = -11,
32    #[error("Cannot allocate memory")]
33    OutOfMemory = -12,
34    #[error("Permission denied")]
35    AccessDenied = -13,
36    #[error("Bad address")]
37    Fault = -14,
38    #[error("File exists")]
39    AlreadyExists = -17,
40    #[error("Invalid argument")]
41    InvalidArgument = -22,
42    #[error("Not a typewriter")]
43    NotATty = -25,
44    #[error("Not a directory")]
45    NotADirectory = -20,
46    #[error("Is a directory")]
47    IsADirectory = -21,
48    #[error("No space left on device")]
49    NoSpace = -28,
50    #[error("Broken pipe")]
51    Pipe = -32,
52    #[error("Result too large")]
53    Range = -34,
54    #[error("File name too long")]
55    NameTooLong = -36,
56    #[error("Function not implemented")]
57    NotImplemented = -38,
58    #[error("Directory not empty")]
59    NotEmpty = -39,
60    #[error("Not supported")]
61    NotSupported = -52,
62    #[error("Message too long")]
63    MessageSize = -90,
64    #[error("No buffer space available")]
65    QueueFull = -105,
66    #[error("Connection timed out")]
67    TimedOut = -110,
68}
69
70impl SyscallError {
71    /// Converts this to raw.
72    #[inline]
73    pub fn to_raw(self) -> u64 {
74        (self as i64) as u64
75    }
76
77    /// Builds this from code.
78    pub fn from_code(code: i64) -> Self {
79        Self::try_from(code).unwrap_or(SyscallError::InvalidArgument)
80    }
81
82    /// Returns whether retryable.
83    #[inline]
84    pub fn is_retryable(self) -> bool {
85        matches!(self, SyscallError::Interrupted | SyscallError::Again)
86    }
87
88    /// Performs the name operation.
89    #[inline]
90    pub fn name(self) -> &'static str {
91        match self {
92            SyscallError::PermissionDenied => "EPERM",
93            SyscallError::NotFound => "ENOENT",
94            SyscallError::NoSuchProcess => "ESRCH",
95            SyscallError::Interrupted => "EINTR",
96            SyscallError::IoError => "EIO",
97            SyscallError::ArgumentListTooLong => "E2BIG",
98            SyscallError::ExecFormatError => "ENOEXEC",
99            SyscallError::BadHandle => "EBADF",
100            SyscallError::NoChildren => "ECHILD",
101            SyscallError::Again => "EAGAIN",
102            SyscallError::OutOfMemory => "ENOMEM",
103            SyscallError::AccessDenied => "EACCES",
104            SyscallError::Fault => "EFAULT",
105            SyscallError::AlreadyExists => "EEXIST",
106            SyscallError::InvalidArgument => "EINVAL",
107            SyscallError::NotADirectory => "ENOTDIR",
108            SyscallError::IsADirectory => "EISDIR",
109            SyscallError::NotATty => "ENOTTY",
110            SyscallError::NoSpace => "ENOSPC",
111            SyscallError::Pipe => "EPIPE",
112            SyscallError::Range => "ERANGE",
113            SyscallError::NameTooLong => "ENAMETOOLONG",
114            SyscallError::NotImplemented => "ENOSYS",
115            SyscallError::NotEmpty => "ENOTEMPTY",
116            SyscallError::NotSupported => "ENOTSUP",
117            SyscallError::MessageSize => "EMSGSIZE",
118            SyscallError::QueueFull => "ENOBUFS",
119            SyscallError::TimedOut => "ETIMEDOUT",
120        }
121    }
122}
123
124//  From impls for kernel-internal error types ====================================================================================================
125
126impl From<core::str::Utf8Error> for SyscallError {
127    /// Performs the from operation.
128    #[inline]
129    fn from(_: core::str::Utf8Error) -> Self {
130        SyscallError::InvalidArgument
131    }
132}
133
134impl From<crate::ostd::util::Error> for SyscallError {
135    /// Performs the from operation.
136    fn from(err: crate::ostd::util::Error) -> Self {
137        use crate::ostd::util::Error;
138        match err {
139            Error::OutOfMemory => SyscallError::OutOfMemory,
140            Error::InvalidArgument => SyscallError::InvalidArgument,
141            Error::NotFound => SyscallError::NotFound,
142            Error::AlreadyExists => SyscallError::AlreadyExists,
143            Error::PermissionDenied => SyscallError::PermissionDenied,
144            Error::Busy => SyscallError::Again,
145            Error::PageFault => SyscallError::Fault,
146            Error::ArchError(_) => SyscallError::IoError,
147        }
148    }
149}
150
151impl From<crate::ostd::mm::MapError> for SyscallError {
152    /// Performs the from operation.
153    fn from(err: crate::ostd::mm::MapError) -> Self {
154        use crate::ostd::mm::MapError;
155        match err {
156            MapError::OutOfBounds => SyscallError::InvalidArgument,
157            MapError::NotOwner => SyscallError::PermissionDenied,
158            MapError::AlreadyMapped => SyscallError::AlreadyExists,
159            MapError::InvalidAddress => SyscallError::InvalidArgument,
160            MapError::OutOfMemory => SyscallError::OutOfMemory,
161            MapError::ArchError(_) => SyscallError::IoError,
162        }
163    }
164}
165
166impl From<crate::hardware::storage::virtio_block::BlockError> for SyscallError {
167    /// Performs the from operation.
168    fn from(err: crate::hardware::storage::virtio_block::BlockError) -> Self {
169        use crate::hardware::storage::virtio_block::BlockError;
170        match err {
171            BlockError::IoError => SyscallError::IoError,
172            BlockError::InvalidSector => SyscallError::InvalidArgument,
173            BlockError::BufferTooSmall => SyscallError::InvalidArgument,
174            BlockError::NotReady => SyscallError::Again,
175        }
176    }
177}
178
179impl From<crate::ipc::port::IpcError> for SyscallError {
180    /// Performs the from operation.
181    fn from(err: crate::ipc::port::IpcError) -> Self {
182        use crate::ipc::port::IpcError;
183        match err {
184            IpcError::PortNotFound => SyscallError::NotFound,
185            IpcError::NotOwner => SyscallError::PermissionDenied,
186            IpcError::PortDestroyed => SyscallError::Pipe,
187            IpcError::WouldBlock => SyscallError::Again,
188            IpcError::Interrupted => SyscallError::Interrupted,
189        }
190    }
191}
192
193impl From<net_core::NetError> for SyscallError {
194    /// Performs the from operation.
195    fn from(err: net_core::NetError) -> Self {
196        use net_core::NetError;
197        match err {
198            NetError::NoPacket => SyscallError::Again,
199            NetError::TxQueueFull => SyscallError::QueueFull,
200            NetError::BufferTooSmall => SyscallError::InvalidArgument,
201            NetError::NotReady => SyscallError::Again,
202            NetError::LinkDown => SyscallError::IoError,
203            NetError::DeviceNotFound => SyscallError::NotImplemented,
204        }
205    }
206}
207
208impl From<crate::ipc::channel::ChannelError> for SyscallError {
209    /// Performs the from operation.
210    fn from(err: crate::ipc::channel::ChannelError) -> Self {
211        use crate::ipc::channel::ChannelError;
212        match err {
213            ChannelError::WouldBlock => SyscallError::Again,
214            ChannelError::Disconnected => SyscallError::Pipe,
215            ChannelError::Interrupted => SyscallError::Interrupted,
216        }
217    }
218}