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#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub enum DmaOperation {
24 BufferAllocation,
26 DeviceIo,
28}
29
30#[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 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
810pub 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}