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