Skip to main content

starry_kernel/
error.rs

1use ax_alloc::AllocError;
2use ax_cgroup::CgroupError;
3use ax_fs_ng::BlockError;
4use ax_hal::{cache::TlbShootdownError, paging::PagingError};
5use ax_io::IoError;
6use ax_memory_set::MappingError;
7use ax_mm::MmError;
8use ax_net::NetError;
9use ax_runtime::{RuntimeError, serial::ConfigError};
10use ax_task::future::{Elapsed, Interrupted, PollIoError, TaskError};
11use axfs_ng_vfs::VfsError;
12use dma_api::DmaError;
13#[cfg(all(test, not(axtest)))]
14use rdif_block::{BlkError, RequestOp};
15#[cfg(feature = "sg2002")]
16use sg2002_tpu::{ion::IonError, tpu::error::TpuError};
17use starry_signal::SignalError;
18use starry_vm::VmError;
19use syscalls::Errno;
20
21/// The operation that gives a DMA-domain failure its Linux ABI meaning.
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub enum DmaOperation {
24    /// Allocate storage for an exported or imported dma-buf.
25    BufferAllocation,
26    /// Program or execute a device DMA transaction.
27    DeviceIo,
28}
29
30/// Errors owned by the Starry kernel below the Linux syscall ABI boundary.
31#[derive(Debug, thiserror::Error)]
32pub enum StarryError {
33    #[error("Linux ABI operation failed: {0}")]
34    Errno(Errno),
35    #[error(transparent)]
36    Vm(#[from] VmError),
37    #[error(transparent)]
38    Signal(#[from] SignalError),
39    #[error(transparent)]
40    Mm(#[from] MmError),
41    #[error(transparent)]
42    Vfs(#[from] VfsError),
43    #[error(transparent)]
44    Mapping(#[from] MappingError),
45    #[error(transparent)]
46    Paging(#[from] PagingError),
47    #[error(transparent)]
48    TlbShootdown(#[from] TlbShootdownError),
49    #[error(transparent)]
50    Alloc(#[from] AllocError),
51    #[error(transparent)]
52    Cgroup(#[from] CgroupError),
53    #[error(transparent)]
54    IoDomain(#[from] IoError),
55    #[error(transparent)]
56    Net(#[from] NetError),
57    #[error(transparent)]
58    Task(#[from] TaskError),
59    #[error(transparent)]
60    Runtime(#[from] RuntimeError),
61    #[error(transparent)]
62    Block(#[from] BlockError),
63    #[error(transparent)]
64    Driver(#[from] ax_driver::Error),
65    #[cfg(feature = "sg2002")]
66    #[error(transparent)]
67    Ion(#[from] IonError),
68    #[cfg(feature = "sg2002")]
69    #[error(transparent)]
70    Tpu(#[from] TpuError),
71    #[error(transparent)]
72    Format(#[from] core::fmt::Error),
73    #[error(transparent)]
74    TaskInterrupted(#[from] Interrupted),
75    #[error(transparent)]
76    TaskElapsed(#[from] Elapsed),
77    #[error("DMA {operation:?} failed: {source}")]
78    Dma {
79        operation: DmaOperation,
80        #[source]
81        source: DmaError,
82    },
83    #[error("kernel object already exists")]
84    AlreadyExists,
85    #[error("argument list is too long")]
86    ArgumentListTooLong,
87    #[error("bad address")]
88    BadAddress,
89    #[error("bad file descriptor")]
90    BadFileDescriptor,
91    #[error("kernel object is in an invalid state")]
92    BadState,
93    #[error("broken pipe")]
94    BrokenPipe,
95    #[error("operation crosses devices")]
96    CrossesDevices,
97    #[error("filesystem traversal loop detected")]
98    FilesystemLoop,
99    #[error("illegal byte sequence")]
100    IllegalBytes,
101    #[error("operation is in progress")]
102    InProgress,
103    #[error("operation was interrupted")]
104    Interrupted,
105    #[error("invalid kernel data")]
106    InvalidData,
107    #[error("invalid executable image")]
108    InvalidExecutable,
109    #[error("malformed executable image")]
110    MalformedExecutable,
111    #[error("invalid kernel input")]
112    InvalidInput,
113    #[error("kernel I/O failed")]
114    Io,
115    #[error("object is a directory")]
116    IsADirectory,
117    #[error("name is too long")]
118    NameTooLong,
119    #[error("kernel allocation failed")]
120    NoMemory,
121    #[error("device does not exist")]
122    NoSuchDevice,
123    #[error("device or address does not exist")]
124    NoSuchDeviceOrAddress,
125    #[error("process does not exist")]
126    NoSuchProcess,
127    #[error("object is not a directory")]
128    NotADirectory,
129    #[error("object is not a socket")]
130    NotASocket,
131    #[error("object is not a tty")]
132    NotATty,
133    #[error("object was not found")]
134    NotFound,
135    #[error("operation is not permitted")]
136    OperationNotPermitted,
137    #[error("operation is not supported by this object")]
138    OperationNotSupported,
139    #[error("result is out of range")]
140    OutOfRange,
141    #[error("permission denied")]
142    PermissionDenied,
143    #[error("filesystem is read-only")]
144    ReadOnlyFilesystem,
145    #[error("kernel resource is busy")]
146    ResourceBusy,
147    #[error("storage is full")]
148    StorageFull,
149    #[error("operation timed out")]
150    TimedOut,
151    #[error("too many files are open")]
152    TooManyOpenFiles,
153    #[error("unexpected end of input")]
154    UnexpectedEof,
155    #[error("kernel capability is unavailable")]
156    Unsupported,
157    #[error("operation would block")]
158    WouldBlock,
159    #[error("write made no progress")]
160    WriteZero,
161}
162
163impl From<Errno> for StarryError {
164    fn from(errno: Errno) -> Self {
165        Self::Errno(errno)
166    }
167}
168
169impl From<StarryError> for VfsError {
170    fn from(error: StarryError) -> Self {
171        match error {
172            StarryError::Vfs(error) => error,
173            StarryError::BadState => Self::BadState,
174            StarryError::InvalidData => Self::InvalidData,
175            error => vfs_error_from_errno(error.linux_errno()),
176        }
177    }
178}
179
180impl StarryError {
181    /// Convert an internal domain failure to its Linux syscall ABI errno.
182    pub fn linux_errno(&self) -> Errno {
183        match self {
184            Self::Errno(errno) => *errno,
185            Self::Vm(error) => vm_errno(*error),
186            Self::Signal(SignalError::UserMemory(error)) => vm_errno(*error),
187            Self::Mm(error) => mm_errno(*error),
188            Self::Vfs(error) => vfs_errno(*error),
189            Self::Mapping(error) => mapping_errno(error),
190            Self::Paging(error) => match error {
191                PagingError::NoMemory => Errno::ENOMEM,
192                _ => Errno::EINVAL,
193            },
194            Self::TlbShootdown(error) => tlb_errno(*error),
195            Self::Alloc(error) => alloc_errno(*error),
196            Self::Cgroup(error) => cgroup_errno(*error),
197            Self::IoDomain(error) => io_errno(*error),
198            Self::Net(error) => io_errno((*error).into()),
199            Self::Task(error) => task_errno(*error),
200            Self::Runtime(error) => runtime_errno(error),
201            Self::Block(error) => block_errno(error),
202            Self::Driver(_) => Errno::EIO,
203            #[cfg(feature = "sg2002")]
204            Self::Ion(error) => ion_errno(*error),
205            #[cfg(feature = "sg2002")]
206            Self::Tpu(error) => tpu_errno(*error),
207            Self::Format(_) => Errno::EINVAL,
208            Self::TaskInterrupted(_) => Errno::EINTR,
209            Self::TaskElapsed(_) => Errno::ETIMEDOUT,
210            Self::Dma { operation, source } => dma_errno(*operation, source),
211            Self::AlreadyExists => Errno::EEXIST,
212            Self::ArgumentListTooLong => Errno::E2BIG,
213            Self::BadAddress | Self::BadState => Errno::EFAULT,
214            Self::BadFileDescriptor => Errno::EBADF,
215            Self::BrokenPipe => Errno::EPIPE,
216            Self::CrossesDevices => Errno::EXDEV,
217            Self::FilesystemLoop => Errno::ELOOP,
218            Self::IllegalBytes => Errno::EILSEQ,
219            Self::InProgress => Errno::EINPROGRESS,
220            Self::Interrupted => Errno::EINTR,
221            Self::InvalidData | Self::InvalidInput => Errno::EINVAL,
222            Self::InvalidExecutable | Self::MalformedExecutable => Errno::ENOEXEC,
223            Self::Io | Self::UnexpectedEof | Self::WriteZero => Errno::EIO,
224            Self::IsADirectory => Errno::EISDIR,
225            Self::NameTooLong => Errno::ENAMETOOLONG,
226            Self::NoMemory => Errno::ENOMEM,
227            Self::NoSuchDevice => Errno::ENODEV,
228            Self::NoSuchDeviceOrAddress => Errno::ENXIO,
229            Self::NoSuchProcess => Errno::ESRCH,
230            Self::NotADirectory => Errno::ENOTDIR,
231            Self::NotASocket => Errno::ENOTSOCK,
232            Self::NotATty => Errno::ENOTTY,
233            Self::NotFound => Errno::ENOENT,
234            Self::OperationNotPermitted => Errno::EPERM,
235            Self::OperationNotSupported => Errno::EOPNOTSUPP,
236            Self::OutOfRange => Errno::ERANGE,
237            Self::PermissionDenied => Errno::EACCES,
238            Self::ReadOnlyFilesystem => Errno::EROFS,
239            Self::ResourceBusy => Errno::EBUSY,
240            Self::StorageFull => Errno::ENOSPC,
241            Self::TimedOut => Errno::ETIMEDOUT,
242            Self::TooManyOpenFiles => Errno::EMFILE,
243            Self::Unsupported => Errno::ENOSYS,
244            Self::WouldBlock => Errno::EAGAIN,
245        }
246    }
247}
248
249impl PollIoError for StarryError {
250    fn is_would_block(&self) -> bool {
251        self.linux_errno() == Errno::EAGAIN
252    }
253
254    fn interrupted(error: Interrupted) -> Self {
255        error.into()
256    }
257}
258
259fn vm_errno(error: VmError) -> Errno {
260    match error {
261        VmError::BadAddress | VmError::AccessDenied => Errno::EFAULT,
262        VmError::TooLong => Errno::ENAMETOOLONG,
263    }
264}
265
266fn mm_errno(error: MmError) -> Errno {
267    match error {
268        MmError::InvalidInput(_) => Errno::EINVAL,
269        MmError::NoMemory => Errno::ENOMEM,
270        MmError::AlreadyExists => Errno::EEXIST,
271        MmError::BadAddress | MmError::BadState(_) => Errno::EFAULT,
272        MmError::Unsupported => Errno::ENOSYS,
273    }
274}
275
276fn mapping_errno(error: &MappingError) -> Errno {
277    match error {
278        MappingError::InvalidParam => Errno::EINVAL,
279        MappingError::AlreadyExists => Errno::EEXIST,
280        MappingError::BadState => Errno::EFAULT,
281    }
282}
283
284fn tlb_errno(error: TlbShootdownError) -> Errno {
285    match error {
286        TlbShootdownError::CpuOffline | TlbShootdownError::Unsupported => Errno::ENOSYS,
287        TlbShootdownError::Timeout => Errno::ETIMEDOUT,
288        TlbShootdownError::Platform => Errno::EIO,
289    }
290}
291
292fn alloc_errno(error: AllocError) -> Errno {
293    match error {
294        AllocError::NoMemory => Errno::ENOMEM,
295        AllocError::NotFound => Errno::ENOENT,
296        AllocError::NotInitialized | AllocError::AlreadyInitialized => Errno::EFAULT,
297        AllocError::MemoryOverlap => Errno::EEXIST,
298        AllocError::InvalidParam | AllocError::NotAllocated => Errno::EINVAL,
299    }
300}
301
302fn cgroup_errno(error: CgroupError) -> Errno {
303    match error {
304        CgroupError::NotInitialized | CgroupError::InvalidInput => Errno::EINVAL,
305        CgroupError::NotFound => Errno::ENOENT,
306        CgroupError::AlreadyExists => Errno::EEXIST,
307        CgroupError::ResourceBusy => Errno::EBUSY,
308        CgroupError::LimitExceeded => Errno::EAGAIN,
309        CgroupError::NoSuchProcess => Errno::ESRCH,
310        CgroupError::DirectoryNotEmpty => Errno::ENOTEMPTY,
311    }
312}
313
314fn task_errno(error: TaskError) -> Errno {
315    match error {
316        TaskError::Interrupted(_) => Errno::EINTR,
317        TaskError::Elapsed(_) => Errno::ETIMEDOUT,
318        TaskError::WouldBlock => Errno::EAGAIN,
319        TaskError::Irq(_) => Errno::EIO,
320    }
321}
322
323fn vfs_error_from_errno(errno: Errno) -> VfsError {
324    match errno {
325        Errno::EEXIST => VfsError::AlreadyExists,
326        Errno::EFAULT => VfsError::BadAddress,
327        Errno::EBADF => VfsError::BadFileDescriptor,
328        Errno::EXDEV => VfsError::CrossesDevices,
329        Errno::ENOTEMPTY => VfsError::DirectoryNotEmpty,
330        Errno::ELOOP => VfsError::FilesystemLoop,
331        Errno::EFBIG => VfsError::FileTooLarge,
332        Errno::EINVAL => VfsError::InvalidInput,
333        Errno::EINTR => VfsError::Interrupted,
334        Errno::EIO => VfsError::Io,
335        Errno::EISDIR => VfsError::IsADirectory,
336        Errno::ENAMETOOLONG => VfsError::NameTooLong,
337        Errno::ENOMEM => VfsError::NoMemory,
338        Errno::ENODEV => VfsError::NoSuchDevice,
339        Errno::ENXIO => VfsError::NoSuchDeviceOrAddress,
340        Errno::ENOTDIR => VfsError::NotADirectory,
341        Errno::ENOTTY => VfsError::NotATty,
342        Errno::ENOENT => VfsError::NotFound,
343        Errno::EPERM => VfsError::OperationNotPermitted,
344        Errno::EOPNOTSUPP => VfsError::OperationNotSupported,
345        Errno::EACCES => VfsError::PermissionDenied,
346        Errno::EROFS => VfsError::ReadOnlyFilesystem,
347        Errno::EBUSY => VfsError::ResourceBusy,
348        Errno::ENOSPC => VfsError::StorageFull,
349        Errno::ETIMEDOUT => VfsError::TimedOut,
350        Errno::ENOSYS => VfsError::Unsupported,
351        Errno::EAGAIN => VfsError::WouldBlock,
352        _ => VfsError::Io,
353    }
354}
355
356fn runtime_errno(error: &RuntimeError) -> Errno {
357    match error {
358        RuntimeError::SerialConfig(error) => match error {
359            ConfigError::InvalidBaudrate
360            | ConfigError::UnsupportedDataBits
361            | ConfigError::UnsupportedStopBits
362            | ConfigError::UnsupportedParity => Errno::EINVAL,
363            ConfigError::Timeout => Errno::ETIMEDOUT,
364            ConfigError::RegisterError => Errno::EIO,
365        },
366        RuntimeError::SerialNotStarted => Errno::EFAULT,
367        RuntimeError::SerialControlBusy => Errno::EBUSY,
368        RuntimeError::WouldBlock => Errno::EAGAIN,
369        RuntimeError::OperationNotSupported => Errno::EOPNOTSUPP,
370        RuntimeError::InvalidCpu { .. } => Errno::EINVAL,
371        _ => Errno::EIO,
372    }
373}
374
375fn block_errno(error: &BlockError) -> Errno {
376    match error {
377        BlockError::InvalidRequest => Errno::EINVAL,
378        BlockError::InvalidState | BlockError::RuntimeUnavailable => Errno::EFAULT,
379        BlockError::WouldBlock => Errno::EAGAIN,
380        BlockError::NoMemory => Errno::ENOMEM,
381        BlockError::Unsupported => Errno::ENOSYS,
382        BlockError::TimedOut => Errno::ETIMEDOUT,
383        BlockError::ResourceBusy => Errno::EBUSY,
384        BlockError::NotFound => Errno::ENOENT,
385        BlockError::Io | BlockError::Irq(_) => Errno::EIO,
386        BlockError::Device { source, .. } => block_errno(&BlockError::from(*source)),
387    }
388}
389
390#[cfg(feature = "sg2002")]
391fn ion_errno(error: IonError) -> Errno {
392    match error {
393        IonError::InvalidArg => Errno::EINVAL,
394        IonError::NoMemory => Errno::ENOMEM,
395        IonError::InvalidBuffer | IonError::BufferNotFound => Errno::ENOENT,
396        IonError::BufferExists => Errno::EEXIST,
397        IonError::InvalidHeap | IonError::NotSupported => Errno::ENOSYS,
398        IonError::Internal => Errno::EINTR,
399    }
400}
401
402#[cfg(feature = "sg2002")]
403fn tpu_errno(error: TpuError) -> Errno {
404    match error {
405        TpuError::Timeout => Errno::ETIMEDOUT,
406        TpuError::InvalidDmabuf | TpuError::PmuBufferNotAligned | TpuError::DmabufNotAligned => {
407            Errno::EINVAL
408        }
409        TpuError::TdmaError(_) | TpuError::TiuError(_) => Errno::EIO,
410        TpuError::NotInitialized => Errno::ENODEV,
411        TpuError::Busy => Errno::EBUSY,
412        TpuError::Interrupted => Errno::EINTR,
413    }
414}
415
416fn dma_errno(operation: DmaOperation, source: &DmaError) -> Errno {
417    match operation {
418        DmaOperation::BufferAllocation => match source {
419            DmaError::LayoutError(_) => Errno::EINVAL,
420            _ => Errno::ENOMEM,
421        },
422        DmaOperation::DeviceIo => match source {
423            DmaError::NoMemory => Errno::ENOMEM,
424            DmaError::LayoutError(_) | DmaError::NullPointer | DmaError::ZeroSizedBuffer => {
425                Errno::EINVAL
426            }
427            _ => Errno::EIO,
428        },
429    }
430}
431
432fn io_errno(error: IoError) -> Errno {
433    match error {
434        IoError::AddrInUse => Errno::EADDRINUSE,
435        IoError::AlreadyConnected => Errno::EISCONN,
436        IoError::AddressFamilyUnsupported => Errno::EAFNOSUPPORT,
437        IoError::AlreadyExists => Errno::EEXIST,
438        IoError::ArgumentListTooLong => Errno::E2BIG,
439        IoError::BadAddress | IoError::BadState => Errno::EFAULT,
440        IoError::BadFileDescriptor => Errno::EBADF,
441        IoError::BrokenPipe => Errno::EPIPE,
442        IoError::ConnectionRefused => Errno::ECONNREFUSED,
443        IoError::ConnectionReset => Errno::ECONNRESET,
444        IoError::CrossesDevices => Errno::EXDEV,
445        IoError::DirectoryNotEmpty => Errno::ENOTEMPTY,
446        IoError::DestAddrRequired => Errno::EDESTADDRREQ,
447        IoError::FilesystemLoop => Errno::ELOOP,
448        IoError::FileTooLarge => Errno::EFBIG,
449        IoError::IllegalBytes => Errno::EILSEQ,
450        IoError::InProgress => Errno::EINPROGRESS,
451        IoError::Interrupted => Errno::EINTR,
452        IoError::InvalidData | IoError::InvalidInput => Errno::EINVAL,
453        IoError::InvalidExecutable => Errno::ENOEXEC,
454        IoError::Io | IoError::UnexpectedEof | IoError::WriteZero => Errno::EIO,
455        IoError::IsADirectory => Errno::EISDIR,
456        IoError::MessageTooLong => Errno::EMSGSIZE,
457        IoError::NameTooLong => Errno::ENAMETOOLONG,
458        IoError::NoMemory => Errno::ENOMEM,
459        IoError::NoSuchDevice => Errno::ENODEV,
460        IoError::NoSuchDeviceOrAddress => Errno::ENXIO,
461        IoError::NoSuchProcess => Errno::ESRCH,
462        IoError::NotADirectory => Errno::ENOTDIR,
463        IoError::NotASocket => Errno::ENOTSOCK,
464        IoError::NotATty => Errno::ENOTTY,
465        IoError::NotConnected => Errno::ENOTCONN,
466        IoError::NotFound => Errno::ENOENT,
467        IoError::OperationNotPermitted => Errno::EPERM,
468        IoError::OperationNotSupported => Errno::EOPNOTSUPP,
469        IoError::OutOfRange => Errno::ERANGE,
470        IoError::PermissionDenied => Errno::EACCES,
471        IoError::ProtocolOptionUnsupported => Errno::ENOPROTOOPT,
472        IoError::ReadOnlyFilesystem => Errno::EROFS,
473        IoError::ResourceBusy => Errno::EBUSY,
474        IoError::StorageFull => Errno::ENOSPC,
475        IoError::TimedOut => Errno::ETIMEDOUT,
476        IoError::TooManyOpenFiles => Errno::EMFILE,
477        IoError::Unsupported => Errno::ENOSYS,
478        IoError::WouldBlock => Errno::EAGAIN,
479    }
480}
481
482fn vfs_errno(error: VfsError) -> Errno {
483    match error {
484        VfsError::AlreadyExists => Errno::EEXIST,
485        VfsError::BadAddress | VfsError::BadState => Errno::EFAULT,
486        VfsError::BadFileDescriptor => Errno::EBADF,
487        VfsError::CrossesDevices => Errno::EXDEV,
488        VfsError::DirectoryNotEmpty => Errno::ENOTEMPTY,
489        VfsError::FilesystemLoop => Errno::ELOOP,
490        VfsError::FileTooLarge => Errno::EFBIG,
491        VfsError::InvalidData | VfsError::InvalidInput => Errno::EINVAL,
492        VfsError::Interrupted => Errno::EINTR,
493        VfsError::Io => Errno::EIO,
494        VfsError::IsADirectory => Errno::EISDIR,
495        VfsError::NameTooLong => Errno::ENAMETOOLONG,
496        VfsError::NoMemory => Errno::ENOMEM,
497        VfsError::NoSuchDevice => Errno::ENODEV,
498        VfsError::NoSuchDeviceOrAddress => Errno::ENXIO,
499        VfsError::NotADirectory => Errno::ENOTDIR,
500        VfsError::NotATty => Errno::ENOTTY,
501        VfsError::NotFound => Errno::ENOENT,
502        VfsError::OperationNotPermitted => Errno::EPERM,
503        VfsError::OperationNotSupported => Errno::EOPNOTSUPP,
504        VfsError::PermissionDenied => Errno::EACCES,
505        VfsError::ReadOnlyFilesystem => Errno::EROFS,
506        VfsError::ResourceBusy => Errno::EBUSY,
507        VfsError::StorageFull => Errno::ENOSPC,
508        VfsError::TimedOut => Errno::ETIMEDOUT,
509        VfsError::Unsupported => Errno::ENOSYS,
510        VfsError::WouldBlock => Errno::EAGAIN,
511    }
512}
513
514#[cfg(all(test, not(axtest)))]
515fn errno_cases_hold<const N: usize>(cases: [(StarryError, Errno); N]) -> bool {
516    cases
517        .into_iter()
518        .all(|(error, expected)| error.linux_errno() == expected)
519}
520
521#[cfg(all(test, not(axtest)))]
522fn memory_errno_mappings_hold() -> bool {
523    errno_cases_hold([
524        (VmError::BadAddress.into(), Errno::EFAULT),
525        (VmError::AccessDenied.into(), Errno::EFAULT),
526        (VmError::TooLong.into(), Errno::ENAMETOOLONG),
527        (
528            SignalError::UserMemory(VmError::BadAddress).into(),
529            Errno::EFAULT,
530        ),
531        (MmError::InvalidInput("test").into(), Errno::EINVAL),
532        (MmError::NoMemory.into(), Errno::ENOMEM),
533        (MmError::AlreadyExists.into(), Errno::EEXIST),
534        (MmError::BadAddress.into(), Errno::EFAULT),
535        (MmError::BadState("test").into(), Errno::EFAULT),
536        (MmError::Unsupported.into(), Errno::ENOSYS),
537        (MappingError::InvalidParam.into(), Errno::EINVAL),
538        (MappingError::AlreadyExists.into(), Errno::EEXIST),
539        (MappingError::BadState.into(), Errno::EFAULT),
540        (PagingError::NoMemory.into(), Errno::ENOMEM),
541        (PagingError::not_mapped().into(), Errno::EINVAL),
542        (TlbShootdownError::CpuOffline.into(), Errno::ENOSYS),
543        (TlbShootdownError::Timeout.into(), Errno::ETIMEDOUT),
544        (TlbShootdownError::Unsupported.into(), Errno::ENOSYS),
545        (TlbShootdownError::Platform.into(), Errno::EIO),
546        (AllocError::InvalidParam.into(), Errno::EINVAL),
547        (AllocError::AlreadyInitialized.into(), Errno::EFAULT),
548        (AllocError::MemoryOverlap.into(), Errno::EEXIST),
549        (AllocError::NoMemory.into(), Errno::ENOMEM),
550        (AllocError::NotAllocated.into(), Errno::EINVAL),
551        (AllocError::NotInitialized.into(), Errno::EFAULT),
552        (AllocError::NotFound.into(), Errno::ENOENT),
553        (CgroupError::NotInitialized.into(), Errno::EINVAL),
554        (CgroupError::NotFound.into(), Errno::ENOENT),
555        (CgroupError::AlreadyExists.into(), Errno::EEXIST),
556        (CgroupError::ResourceBusy.into(), Errno::EBUSY),
557        (CgroupError::LimitExceeded.into(), Errno::EAGAIN),
558        (CgroupError::InvalidInput.into(), Errno::EINVAL),
559        (CgroupError::NoSuchProcess.into(), Errno::ESRCH),
560        (CgroupError::DirectoryNotEmpty.into(), Errno::ENOTEMPTY),
561    ])
562}
563
564#[cfg(all(test, not(axtest)))]
565fn vfs_errno_mappings_hold() -> bool {
566    errno_cases_hold([
567        (VfsError::AlreadyExists.into(), Errno::EEXIST),
568        (VfsError::BadAddress.into(), Errno::EFAULT),
569        (VfsError::BadFileDescriptor.into(), Errno::EBADF),
570        (VfsError::BadState.into(), Errno::EFAULT),
571        (VfsError::CrossesDevices.into(), Errno::EXDEV),
572        (VfsError::DirectoryNotEmpty.into(), Errno::ENOTEMPTY),
573        (VfsError::FilesystemLoop.into(), Errno::ELOOP),
574        (VfsError::FileTooLarge.into(), Errno::EFBIG),
575        (VfsError::InvalidData.into(), Errno::EINVAL),
576        (VfsError::InvalidInput.into(), Errno::EINVAL),
577        (VfsError::Interrupted.into(), Errno::EINTR),
578        (VfsError::Io.into(), Errno::EIO),
579        (VfsError::IsADirectory.into(), Errno::EISDIR),
580        (VfsError::NameTooLong.into(), Errno::ENAMETOOLONG),
581        (VfsError::NoMemory.into(), Errno::ENOMEM),
582        (VfsError::NoSuchDevice.into(), Errno::ENODEV),
583        (VfsError::NoSuchDeviceOrAddress.into(), Errno::ENXIO),
584        (VfsError::NotADirectory.into(), Errno::ENOTDIR),
585        (VfsError::NotATty.into(), Errno::ENOTTY),
586        (VfsError::NotFound.into(), Errno::ENOENT),
587        (VfsError::OperationNotPermitted.into(), Errno::EPERM),
588        (VfsError::OperationNotSupported.into(), Errno::EOPNOTSUPP),
589        (VfsError::PermissionDenied.into(), Errno::EACCES),
590        (VfsError::ReadOnlyFilesystem.into(), Errno::EROFS),
591        (VfsError::ResourceBusy.into(), Errno::EBUSY),
592        (VfsError::StorageFull.into(), Errno::ENOSPC),
593        (VfsError::TimedOut.into(), Errno::ETIMEDOUT),
594        (VfsError::Unsupported.into(), Errno::ENOSYS),
595        (VfsError::WouldBlock.into(), Errno::EAGAIN),
596    ])
597}
598
599#[cfg(all(test, not(axtest)))]
600fn io_errno_mappings_hold() -> bool {
601    errno_cases_hold([
602        (IoError::AddrInUse.into(), Errno::EADDRINUSE),
603        (IoError::AlreadyConnected.into(), Errno::EISCONN),
604        (
605            IoError::AddressFamilyUnsupported.into(),
606            Errno::EAFNOSUPPORT,
607        ),
608        (IoError::AlreadyExists.into(), Errno::EEXIST),
609        (IoError::ArgumentListTooLong.into(), Errno::E2BIG),
610        (IoError::BadAddress.into(), Errno::EFAULT),
611        (IoError::BadFileDescriptor.into(), Errno::EBADF),
612        (IoError::BadState.into(), Errno::EFAULT),
613        (IoError::BrokenPipe.into(), Errno::EPIPE),
614        (IoError::ConnectionRefused.into(), Errno::ECONNREFUSED),
615        (IoError::ConnectionReset.into(), Errno::ECONNRESET),
616        (IoError::CrossesDevices.into(), Errno::EXDEV),
617        (IoError::DirectoryNotEmpty.into(), Errno::ENOTEMPTY),
618        (IoError::DestAddrRequired.into(), Errno::EDESTADDRREQ),
619        (IoError::FilesystemLoop.into(), Errno::ELOOP),
620        (IoError::FileTooLarge.into(), Errno::EFBIG),
621        (IoError::IllegalBytes.into(), Errno::EILSEQ),
622        (IoError::InProgress.into(), Errno::EINPROGRESS),
623        (IoError::Interrupted.into(), Errno::EINTR),
624        (IoError::InvalidData.into(), Errno::EINVAL),
625        (IoError::InvalidExecutable.into(), Errno::ENOEXEC),
626        (IoError::InvalidInput.into(), Errno::EINVAL),
627        (IoError::Io.into(), Errno::EIO),
628        (IoError::IsADirectory.into(), Errno::EISDIR),
629        (IoError::NameTooLong.into(), Errno::ENAMETOOLONG),
630        (IoError::MessageTooLong.into(), Errno::EMSGSIZE),
631        (IoError::NoMemory.into(), Errno::ENOMEM),
632        (IoError::NoSuchDevice.into(), Errno::ENODEV),
633        (IoError::NoSuchDeviceOrAddress.into(), Errno::ENXIO),
634        (IoError::NoSuchProcess.into(), Errno::ESRCH),
635        (IoError::NotADirectory.into(), Errno::ENOTDIR),
636        (IoError::NotASocket.into(), Errno::ENOTSOCK),
637        (IoError::NotATty.into(), Errno::ENOTTY),
638        (IoError::NotConnected.into(), Errno::ENOTCONN),
639        (IoError::NotFound.into(), Errno::ENOENT),
640        (IoError::OperationNotPermitted.into(), Errno::EPERM),
641        (IoError::OperationNotSupported.into(), Errno::EOPNOTSUPP),
642        (IoError::OutOfRange.into(), Errno::ERANGE),
643        (IoError::PermissionDenied.into(), Errno::EACCES),
644        (
645            IoError::ProtocolOptionUnsupported.into(),
646            Errno::ENOPROTOOPT,
647        ),
648        (IoError::ReadOnlyFilesystem.into(), Errno::EROFS),
649        (IoError::ResourceBusy.into(), Errno::EBUSY),
650        (IoError::StorageFull.into(), Errno::ENOSPC),
651        (IoError::TimedOut.into(), Errno::ETIMEDOUT),
652        (IoError::TooManyOpenFiles.into(), Errno::EMFILE),
653        (IoError::UnexpectedEof.into(), Errno::EIO),
654        (IoError::Unsupported.into(), Errno::ENOSYS),
655        (IoError::WouldBlock.into(), Errno::EAGAIN),
656        (IoError::WriteZero.into(), Errno::EIO),
657    ])
658}
659
660#[cfg(all(test, not(axtest)))]
661fn block_errno_mappings_hold() -> bool {
662    let device_error = |source| {
663        StarryError::from(BlockError::Device {
664            stage: "submit",
665            operation: RequestOp::Read,
666            lba: 9,
667            source,
668        })
669    };
670
671    errno_cases_hold([
672        (BlockError::InvalidRequest.into(), Errno::EINVAL),
673        (BlockError::InvalidState.into(), Errno::EFAULT),
674        (BlockError::RuntimeUnavailable.into(), Errno::EFAULT),
675        (BlockError::WouldBlock.into(), Errno::EAGAIN),
676        (BlockError::NoMemory.into(), Errno::ENOMEM),
677        (BlockError::Unsupported.into(), Errno::ENOSYS),
678        (BlockError::TimedOut.into(), Errno::ETIMEDOUT),
679        (BlockError::Io.into(), Errno::EIO),
680        (BlockError::ResourceBusy.into(), Errno::EBUSY),
681        (BlockError::NotFound.into(), Errno::ENOENT),
682        (device_error(BlkError::NotSupported), Errno::ENOSYS),
683        (device_error(BlkError::Retry), Errno::EAGAIN),
684        (device_error(BlkError::NoMemory), Errno::ENOMEM),
685        (device_error(BlkError::InvalidBlockIndex(9)), Errno::EINVAL),
686        (device_error(BlkError::InvalidRequest), Errno::EINVAL),
687        (device_error(BlkError::TimedOut), Errno::ETIMEDOUT),
688        (device_error(BlkError::Io), Errno::EIO),
689        (device_error(BlkError::Other("device failure")), Errno::EIO),
690    ])
691}
692
693#[cfg(all(test, not(axtest)))]
694fn leaf_errno_mappings_hold() -> bool {
695    errno_cases_hold([
696        (StarryError::AlreadyExists, Errno::EEXIST),
697        (StarryError::ArgumentListTooLong, Errno::E2BIG),
698        (StarryError::BadAddress, Errno::EFAULT),
699        (StarryError::BadFileDescriptor, Errno::EBADF),
700        (StarryError::BadState, Errno::EFAULT),
701        (StarryError::BrokenPipe, Errno::EPIPE),
702        (StarryError::CrossesDevices, Errno::EXDEV),
703        (StarryError::FilesystemLoop, Errno::ELOOP),
704        (StarryError::IllegalBytes, Errno::EILSEQ),
705        (StarryError::InProgress, Errno::EINPROGRESS),
706        (StarryError::Interrupted, Errno::EINTR),
707        (StarryError::InvalidData, Errno::EINVAL),
708        (StarryError::InvalidExecutable, Errno::ENOEXEC),
709        (StarryError::MalformedExecutable, Errno::ENOEXEC),
710        (StarryError::InvalidInput, Errno::EINVAL),
711        (StarryError::Io, Errno::EIO),
712        (StarryError::IsADirectory, Errno::EISDIR),
713        (StarryError::NameTooLong, Errno::ENAMETOOLONG),
714        (StarryError::NoMemory, Errno::ENOMEM),
715        (StarryError::NoSuchDevice, Errno::ENODEV),
716        (StarryError::NoSuchDeviceOrAddress, Errno::ENXIO),
717        (StarryError::NoSuchProcess, Errno::ESRCH),
718        (StarryError::NotADirectory, Errno::ENOTDIR),
719        (StarryError::NotASocket, Errno::ENOTSOCK),
720        (StarryError::NotATty, Errno::ENOTTY),
721        (StarryError::NotFound, Errno::ENOENT),
722        (StarryError::OperationNotPermitted, Errno::EPERM),
723        (StarryError::OperationNotSupported, Errno::EOPNOTSUPP),
724        (StarryError::OutOfRange, Errno::ERANGE),
725        (StarryError::PermissionDenied, Errno::EACCES),
726        (StarryError::ReadOnlyFilesystem, Errno::EROFS),
727        (StarryError::ResourceBusy, Errno::EBUSY),
728        (StarryError::StorageFull, Errno::ENOSPC),
729        (StarryError::TimedOut, Errno::ETIMEDOUT),
730        (StarryError::TooManyOpenFiles, Errno::EMFILE),
731        (StarryError::UnexpectedEof, Errno::EIO),
732        (StarryError::Unsupported, Errno::ENOSYS),
733        (StarryError::WouldBlock, Errno::EAGAIN),
734        (StarryError::WriteZero, Errno::EIO),
735        (StarryError::Format(core::fmt::Error), Errno::EINVAL),
736        (StarryError::TaskInterrupted(Interrupted), Errno::EINTR),
737        (StarryError::Task(TaskError::WouldBlock), Errno::EAGAIN),
738        (
739            StarryError::Runtime(RuntimeError::SerialNotStarted),
740            Errno::EFAULT,
741        ),
742        (
743            StarryError::Runtime(RuntimeError::SerialControlBusy),
744            Errno::EBUSY,
745        ),
746        (
747            StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::InvalidBaudrate)),
748            Errno::EINVAL,
749        ),
750        (
751            StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::UnsupportedDataBits)),
752            Errno::EINVAL,
753        ),
754        (
755            StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::UnsupportedStopBits)),
756            Errno::EINVAL,
757        ),
758        (
759            StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::UnsupportedParity)),
760            Errno::EINVAL,
761        ),
762        (
763            StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::Timeout)),
764            Errno::ETIMEDOUT,
765        ),
766        (
767            StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::RegisterError)),
768            Errno::EIO,
769        ),
770        (
771            StarryError::Runtime(RuntimeError::WouldBlock),
772            Errno::EAGAIN,
773        ),
774        (
775            StarryError::Runtime(RuntimeError::OperationNotSupported),
776            Errno::EOPNOTSUPP,
777        ),
778        (
779            StarryError::Runtime(RuntimeError::InvalidCpu { cpu: 99 }),
780            Errno::EINVAL,
781        ),
782        (
783            StarryError::Dma {
784                operation: DmaOperation::BufferAllocation,
785                source: DmaError::NoMemory,
786            },
787            Errno::ENOMEM,
788        ),
789        (
790            StarryError::Dma {
791                operation: DmaOperation::DeviceIo,
792                source: DmaError::NullPointer,
793            },
794            Errno::EINVAL,
795        ),
796    ])
797}
798
799#[cfg(all(test, not(axtest)))]
800fn domain_errno_mappings_hold() -> bool {
801    memory_errno_mappings_hold()
802        && vfs_errno_mappings_hold()
803        && io_errno_mappings_hold()
804        && block_errno_mappings_hold()
805        && leaf_errno_mappings_hold()
806        && StarryError::from(Errno::EOWNERDEAD).linux_errno() == Errno::EOWNERDEAD
807        && StarryError::from(Errno::new(4094)).linux_errno().into_raw() == 4094
808}
809
810/// A result returned by Starry-owned kernel operations.
811pub type StarryResult<T = ()> = Result<T, StarryError>;
812
813#[cfg(all(test, not(axtest)))]
814mod tests {
815    use super::*;
816
817    #[test]
818    fn domain_errors_map_to_stable_linux_errno() {
819        assert!(domain_errno_mappings_hold());
820    }
821
822    #[test]
823    fn native_linux_errno_is_not_canonicalized() {
824        let error = StarryError::from(Errno::EOWNERDEAD);
825        assert_eq!(error.linux_errno(), Errno::EOWNERDEAD);
826    }
827
828    #[test]
829    fn unknown_linux_errno_is_preserved() {
830        let error = StarryError::from(Errno::new(4094));
831        assert_eq!(error.linux_errno().into_raw(), 4094);
832    }
833
834    #[cfg(feature = "sg2002")]
835    #[test]
836    fn sg2002_tpu_errors_keep_their_linux_errno() {
837        let cases = [
838            (TpuError::Timeout, Errno::ETIMEDOUT),
839            (TpuError::InvalidDmabuf, Errno::EINVAL),
840            (TpuError::TdmaError(1), Errno::EIO),
841            (TpuError::TiuError(1), Errno::EIO),
842            (TpuError::NotInitialized, Errno::ENODEV),
843            (TpuError::Busy, Errno::EBUSY),
844            (TpuError::Interrupted, Errno::EINTR),
845            (TpuError::PmuBufferNotAligned, Errno::EINVAL),
846            (TpuError::DmabufNotAligned, Errno::EINVAL),
847        ];
848        for (error, expected) in cases {
849            assert_eq!(StarryError::from(error).linux_errno(), expected);
850        }
851    }
852}