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