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::Signal(SignalError::NoMemory) => Errno::ENOMEM,
204 Self::Mm(error) => mm_errno(*error),
205 Self::Vfs(error) => vfs_errno(*error),
206 Self::Mapping(error) => mapping_errno(error),
207 Self::Paging(error) => match error {
208 PagingError::NoMemory => Errno::ENOMEM,
209 _ => Errno::EINVAL,
210 },
211 Self::TlbShootdown(error) => tlb_errno(*error),
212 Self::Alloc(error) => alloc_errno(*error),
213 Self::Cgroup(error) => cgroup_errno(*error),
214 Self::IoDomain(error) => io_errno(*error),
215 Self::Net(error) => io_errno((*error).into()),
216 Self::Task(error) => task_errno(*error),
217 Self::Runtime(error) => runtime_errno(error),
218 Self::Block(error) => block_errno(error),
219 Self::Driver(_) => Errno::EIO,
220 #[cfg(feature = "sg2002")]
221 Self::Ion(error) => ion_errno(*error),
222 #[cfg(feature = "sg2002")]
223 Self::Tpu(error) => tpu_errno(*error),
224 Self::Format(_) => Errno::EINVAL,
225 Self::Dma { operation, source } => dma_errno(*operation, source),
226 Self::AlreadyExists => Errno::EEXIST,
227 Self::ArgumentListTooLong => Errno::E2BIG,
228 Self::BadAddress | Self::BadState => Errno::EFAULT,
229 Self::BadFileDescriptor => Errno::EBADF,
230 Self::BrokenPipe => Errno::EPIPE,
231 Self::CrossesDevices => Errno::EXDEV,
232 Self::FilesystemLoop => Errno::ELOOP,
233 Self::IllegalBytes => Errno::EILSEQ,
234 Self::InProgress => Errno::EINPROGRESS,
235 Self::Interrupted | Self::InterruptedNoRestart => Errno::EINTR,
236 Self::InvalidData | Self::InvalidInput => Errno::EINVAL,
237 Self::InvalidExecutable | Self::MalformedExecutable => Errno::ENOEXEC,
238 Self::Io | Self::UnexpectedEof | Self::WriteZero => Errno::EIO,
239 Self::IsADirectory => Errno::EISDIR,
240 Self::NameTooLong => Errno::ENAMETOOLONG,
241 Self::NoMemory => Errno::ENOMEM,
242 Self::NoSuchDevice => Errno::ENODEV,
243 Self::NoSuchDeviceOrAddress => Errno::ENXIO,
244 Self::NoSuchProcess => Errno::ESRCH,
245 Self::NotADirectory => Errno::ENOTDIR,
246 Self::NotASocket => Errno::ENOTSOCK,
247 Self::NotATty => Errno::ENOTTY,
248 Self::NotFound => Errno::ENOENT,
249 Self::OperationNotPermitted => Errno::EPERM,
250 Self::OperationNotSupported => Errno::EOPNOTSUPP,
251 Self::OutOfRange => Errno::ERANGE,
252 Self::PermissionDenied => Errno::EACCES,
253 Self::ReadOnlyFilesystem => Errno::EROFS,
254 Self::ResourceBusy => Errno::EBUSY,
255 Self::StorageFull => Errno::ENOSPC,
256 Self::TimedOut => Errno::ETIMEDOUT,
257 Self::TooManyOpenFiles => Errno::EMFILE,
258 Self::Unsupported => Errno::ENOSYS,
259 Self::WouldBlock => Errno::EAGAIN,
260 }
261 }
262}
263
264fn vm_errno(error: VmError) -> Errno {
265 match error {
266 VmError::BadAddress | VmError::AccessDenied => Errno::EFAULT,
267 VmError::TooLong => Errno::ENAMETOOLONG,
268 }
269}
270
271fn mm_errno(error: MmError) -> Errno {
272 match error {
273 MmError::InvalidInput(_) => Errno::EINVAL,
274 MmError::NoMemory => Errno::ENOMEM,
275 MmError::AlreadyExists => Errno::EEXIST,
276 MmError::BadAddress | MmError::BadState(_) => Errno::EFAULT,
277 MmError::Unsupported => Errno::ENOSYS,
278 MmError::TlbShootdown(error) => tlb_errno(error),
279 }
280}
281
282fn mapping_errno(error: &MappingError) -> Errno {
283 match error {
284 MappingError::InvalidParam => Errno::EINVAL,
285 MappingError::AlreadyExists => Errno::EEXIST,
286 MappingError::BadState | MappingError::NeedsRepair => Errno::EFAULT,
287 }
288}
289
290fn tlb_errno(error: TlbShootdownError) -> Errno {
291 match error {
292 TlbShootdownError::CpuOffline | TlbShootdownError::Unsupported => Errno::ENOSYS,
293 TlbShootdownError::Timeout => Errno::ETIMEDOUT,
294 TlbShootdownError::GenerationExhausted => Errno::EOVERFLOW,
295 TlbShootdownError::Platform => Errno::EIO,
296 }
297}
298
299fn alloc_errno(error: AllocError) -> Errno {
300 match error {
301 AllocError::NoMemory => Errno::ENOMEM,
302 AllocError::NotFound => Errno::ENOENT,
303 AllocError::NotInitialized | AllocError::AlreadyInitialized => Errno::EFAULT,
304 AllocError::MemoryOverlap => Errno::EEXIST,
305 AllocError::InvalidParam | AllocError::NotAllocated => Errno::EINVAL,
306 }
307}
308
309fn cgroup_errno(error: CgroupError) -> Errno {
310 match error {
311 CgroupError::NotInitialized | CgroupError::InvalidInput => Errno::EINVAL,
312 CgroupError::NotFound => Errno::ENOENT,
313 CgroupError::AlreadyExists => Errno::EEXIST,
314 CgroupError::ResourceBusy => Errno::EBUSY,
315 CgroupError::LimitExceeded => Errno::EAGAIN,
316 CgroupError::NoSuchProcess => Errno::ESRCH,
317 CgroupError::DirectoryNotEmpty => Errno::ENOTEMPTY,
318 }
319}
320
321fn task_errno(error: TaskError) -> Errno {
322 match error {
323 TaskError::InvalidConfiguration
324 | TaskError::InvalidCpuCount(_)
325 | TaskError::InvalidCpu(_)
326 | TaskError::InvalidNice(_)
327 | TaskError::InvalidRtPriority(_)
328 | TaskError::InvalidRoundRobinQuantum
329 | TaskError::InvalidDeadline { .. }
330 | TaskError::UnsupportedDeadlineFlags(_) => Errno::EINVAL,
331 TaskError::DeadlineAdmission
332 | TaskError::DeadlineAffinity
333 | TaskError::ActiveTimerAffinity
334 | TaskError::ThreadBusy => Errno::EBUSY,
335 TaskError::StaleThreadId => Errno::ESRCH,
336 TaskError::TimerCapacity => Errno::ENOMEM,
337 TaskError::RuntimeFailure(status)
338 if status == ax_runtime::task::runtime::RuntimeStatus::NoMemory as u32 =>
339 {
340 Errno::ENOMEM
341 }
342 TaskError::UnsafeContext => Errno::EPERM,
343 TaskError::CpuOwnerMismatch { .. }
344 | TaskError::CpuOwnerBorrowed
345 | TaskError::CpuAlreadyOnline(_)
346 | TaskError::CpuOffline(_)
347 | TaskError::CpuNotQuiescent(_)
348 | TaskError::LastOnlineCpu(_)
349 | TaskError::ExecutorOwnerMismatch { .. }
350 | TaskError::InvalidTransition { .. }
351 | TaskError::AlreadyQueued
352 | TaskError::NotReady
353 | TaskError::NotExited
354 | TaskError::NoRunnableThread
355 | TaskError::ThreadCapacity
356 | TaskError::NotInitialized
357 | TaskError::InvalidRuntimeHandle
358 | TaskError::InvalidPiState
359 | TaskError::InvalidPiWaitState(_)
360 | TaskError::PiCycle
361 | TaskError::PiChainLimit { .. }
362 | TaskError::RuntimeFailure(_) => Errno::EFAULT,
363 }
364}
365
366fn vfs_error_from_errno(errno: Errno) -> VfsError {
367 match errno {
368 Errno::EEXIST => VfsError::AlreadyExists,
369 Errno::EFAULT => VfsError::BadAddress,
370 Errno::EBADF => VfsError::BadFileDescriptor,
371 Errno::EXDEV => VfsError::CrossesDevices,
372 Errno::ENODATA => VfsError::DataMissing,
373 Errno::ENOTEMPTY => VfsError::DirectoryNotEmpty,
374 Errno::EUCLEAN => VfsError::FilesystemCorrupted,
375 Errno::ELOOP => VfsError::FilesystemLoop,
376 Errno::EFBIG => VfsError::FileTooLarge,
377 Errno::EINVAL => VfsError::InvalidInput,
378 Errno::EINTR => VfsError::Interrupted,
379 Errno::EIO => VfsError::Io,
380 Errno::EISDIR => VfsError::IsADirectory,
381 Errno::ENAMETOOLONG => VfsError::NameTooLong,
382 Errno::ENOMEM => VfsError::NoMemory,
383 Errno::ENODEV => VfsError::NoSuchDevice,
384 Errno::ENXIO => VfsError::NoSuchDeviceOrAddress,
385 Errno::ENOTDIR => VfsError::NotADirectory,
386 Errno::ENOTTY => VfsError::NotATty,
387 Errno::ENOENT => VfsError::NotFound,
388 Errno::EPERM => VfsError::OperationNotPermitted,
389 Errno::EOPNOTSUPP => VfsError::OperationNotSupported,
390 Errno::EACCES => VfsError::PermissionDenied,
391 Errno::EDQUOT => VfsError::QuotaExceeded,
392 Errno::EROFS => VfsError::ReadOnlyFilesystem,
393 Errno::EBUSY => VfsError::ResourceBusy,
394 Errno::ENOSPC => VfsError::StorageFull,
395 Errno::ETIMEDOUT => VfsError::TimedOut,
396 Errno::EMLINK => VfsError::TooManyLinks,
397 Errno::ENOSYS => VfsError::Unsupported,
398 Errno::EOVERFLOW => VfsError::ValueOverflow,
399 Errno::EAGAIN => VfsError::WouldBlock,
400 _ => VfsError::Io,
401 }
402}
403
404fn runtime_errno(error: &RuntimeError) -> Errno {
405 match error {
406 RuntimeError::SerialConfig(error) => match error {
407 ConfigError::InvalidBaudrate
408 | ConfigError::UnsupportedDataBits
409 | ConfigError::UnsupportedStopBits
410 | ConfigError::UnsupportedParity => Errno::EINVAL,
411 ConfigError::Timeout => Errno::ETIMEDOUT,
412 ConfigError::RegisterError => Errno::EIO,
413 },
414 RuntimeError::SerialNotStarted => Errno::EFAULT,
415 RuntimeError::SerialControlBusy => Errno::EBUSY,
416 RuntimeError::Task(error) => task_errno(*error),
417 RuntimeError::WouldBlock => Errno::EAGAIN,
418 RuntimeError::OperationNotSupported => Errno::EOPNOTSUPP,
419 RuntimeError::InvalidCpu { .. } => Errno::EINVAL,
420 _ => Errno::EIO,
421 }
422}
423
424fn block_errno(error: &BlockError) -> Errno {
425 match error {
426 BlockError::InvalidRequest => Errno::EINVAL,
427 BlockError::InvalidState | BlockError::RuntimeUnavailable => Errno::EFAULT,
428 BlockError::WouldBlock => Errno::EAGAIN,
429 BlockError::NoMemory => Errno::ENOMEM,
430 BlockError::Unsupported => Errno::ENOSYS,
431 BlockError::TimedOut => Errno::ETIMEDOUT,
432 BlockError::ResourceBusy => Errno::EBUSY,
433 BlockError::NotFound => Errno::ENOENT,
434 BlockError::Io | BlockError::Irq(_) => Errno::EIO,
435 BlockError::Device { source, .. } => block_errno(&BlockError::from(*source)),
436 }
437}
438
439#[cfg(feature = "sg2002")]
440fn ion_errno(error: IonError) -> Errno {
441 match error {
442 IonError::InvalidArg => Errno::EINVAL,
443 IonError::NoMemory => Errno::ENOMEM,
444 IonError::InvalidBuffer | IonError::BufferNotFound => Errno::ENOENT,
445 IonError::BufferExists => Errno::EEXIST,
446 IonError::InvalidHeap | IonError::NotSupported => Errno::ENOSYS,
447 IonError::Internal => Errno::EINTR,
448 }
449}
450
451#[cfg(feature = "sg2002")]
452fn tpu_errno(error: TpuError) -> Errno {
453 match error {
454 TpuError::Timeout => Errno::ETIMEDOUT,
455 TpuError::InvalidDmabuf | TpuError::PmuBufferNotAligned | TpuError::DmabufNotAligned => {
456 Errno::EINVAL
457 }
458 TpuError::TdmaError(_) | TpuError::TiuError(_) => Errno::EIO,
459 TpuError::NotInitialized => Errno::ENODEV,
460 TpuError::Busy => Errno::EBUSY,
461 TpuError::Interrupted => Errno::EINTR,
462 }
463}
464
465fn dma_errno(operation: DmaOperation, source: &DmaError) -> Errno {
466 match operation {
467 DmaOperation::BufferAllocation => match source {
468 DmaError::LayoutError(_) => Errno::EINVAL,
469 _ => Errno::ENOMEM,
470 },
471 DmaOperation::DeviceIo => match source {
472 DmaError::NoMemory => Errno::ENOMEM,
473 DmaError::LayoutError(_) | DmaError::NullPointer | DmaError::ZeroSizedBuffer => {
474 Errno::EINVAL
475 }
476 _ => Errno::EIO,
477 },
478 }
479}
480
481fn io_errno(error: IoError) -> Errno {
482 match error {
483 IoError::AddrInUse => Errno::EADDRINUSE,
484 IoError::AlreadyConnected => Errno::EISCONN,
485 IoError::AddressFamilyUnsupported => Errno::EAFNOSUPPORT,
486 IoError::AlreadyExists => Errno::EEXIST,
487 IoError::ArgumentListTooLong => Errno::E2BIG,
488 IoError::BadAddress | IoError::BadState => Errno::EFAULT,
489 IoError::BadFileDescriptor => Errno::EBADF,
490 IoError::BrokenPipe => Errno::EPIPE,
491 IoError::ConnectionRefused => Errno::ECONNREFUSED,
492 IoError::ConnectionReset => Errno::ECONNRESET,
493 IoError::CrossesDevices => Errno::EXDEV,
494 IoError::DirectoryNotEmpty => Errno::ENOTEMPTY,
495 IoError::DestAddrRequired => Errno::EDESTADDRREQ,
496 IoError::FilesystemLoop => Errno::ELOOP,
497 IoError::FileTooLarge => Errno::EFBIG,
498 IoError::IllegalBytes => Errno::EILSEQ,
499 IoError::InProgress => Errno::EINPROGRESS,
500 IoError::Interrupted => Errno::EINTR,
501 IoError::InvalidData | IoError::InvalidInput => Errno::EINVAL,
502 IoError::InvalidExecutable => Errno::ENOEXEC,
503 IoError::Io | IoError::UnexpectedEof | IoError::WriteZero => Errno::EIO,
504 IoError::IsADirectory => Errno::EISDIR,
505 IoError::MessageTooLong => Errno::EMSGSIZE,
506 IoError::NameTooLong => Errno::ENAMETOOLONG,
507 IoError::NoMemory => Errno::ENOMEM,
508 IoError::NoSuchDevice => Errno::ENODEV,
509 IoError::NoSuchDeviceOrAddress => Errno::ENXIO,
510 IoError::NoSuchProcess => Errno::ESRCH,
511 IoError::NotADirectory => Errno::ENOTDIR,
512 IoError::NotASocket => Errno::ENOTSOCK,
513 IoError::NotATty => Errno::ENOTTY,
514 IoError::NotConnected => Errno::ENOTCONN,
515 IoError::NotFound => Errno::ENOENT,
516 IoError::OperationNotPermitted => Errno::EPERM,
517 IoError::OperationNotSupported => Errno::EOPNOTSUPP,
518 IoError::OutOfRange => Errno::ERANGE,
519 IoError::PermissionDenied => Errno::EACCES,
520 IoError::ProtocolOptionUnsupported => Errno::ENOPROTOOPT,
521 IoError::ReadOnlyFilesystem => Errno::EROFS,
522 IoError::ResourceBusy => Errno::EBUSY,
523 IoError::StorageFull => Errno::ENOSPC,
524 IoError::TimedOut => Errno::ETIMEDOUT,
525 IoError::TooManyOpenFiles => Errno::EMFILE,
526 IoError::Unsupported => Errno::ENOSYS,
527 IoError::WouldBlock => Errno::EAGAIN,
528 }
529}
530
531fn vfs_errno(error: VfsError) -> Errno {
532 match error {
533 VfsError::AlreadyExists => Errno::EEXIST,
534 VfsError::BadAddress | VfsError::BadState => Errno::EFAULT,
535 VfsError::BadFileDescriptor => Errno::EBADF,
536 VfsError::CrossesDevices => Errno::EXDEV,
537 VfsError::DataMissing => Errno::ENODATA,
538 VfsError::DirectoryNotEmpty => Errno::ENOTEMPTY,
539 VfsError::FilesystemCorrupted => Errno::EUCLEAN,
540 VfsError::FilesystemLoop => Errno::ELOOP,
541 VfsError::FileTooLarge => Errno::EFBIG,
542 VfsError::InvalidData | VfsError::InvalidInput => Errno::EINVAL,
543 VfsError::Interrupted => Errno::EINTR,
544 VfsError::Io => Errno::EIO,
545 VfsError::IsADirectory => Errno::EISDIR,
546 VfsError::NameTooLong => Errno::ENAMETOOLONG,
547 VfsError::NoMemory => Errno::ENOMEM,
548 VfsError::NoSuchDevice => Errno::ENODEV,
549 VfsError::NoSuchDeviceOrAddress => Errno::ENXIO,
550 VfsError::NotADirectory => Errno::ENOTDIR,
551 VfsError::NotATty => Errno::ENOTTY,
552 VfsError::NotFound => Errno::ENOENT,
553 VfsError::OperationNotPermitted => Errno::EPERM,
554 VfsError::OperationNotSupported => Errno::EOPNOTSUPP,
555 VfsError::PermissionDenied => Errno::EACCES,
556 VfsError::QuotaExceeded => Errno::EDQUOT,
557 VfsError::ReadOnlyFilesystem => Errno::EROFS,
558 VfsError::ResourceBusy => Errno::EBUSY,
559 VfsError::StorageFull => Errno::ENOSPC,
560 VfsError::TimedOut => Errno::ETIMEDOUT,
561 VfsError::TooManyLinks => Errno::EMLINK,
562 VfsError::Unsupported => Errno::ENOSYS,
563 VfsError::ValueOverflow => Errno::EOVERFLOW,
564 VfsError::WouldBlock => Errno::EAGAIN,
565 }
566}
567
568#[cfg(all(test, not(axtest)))]
569fn errno_cases_hold<const N: usize>(cases: [(StarryError, Errno); N]) -> bool {
570 cases
571 .into_iter()
572 .all(|(error, expected)| error.linux_errno() == expected)
573}
574
575#[cfg(all(test, not(axtest)))]
576fn memory_errno_mappings_hold() -> bool {
577 errno_cases_hold([
578 (VmError::BadAddress.into(), Errno::EFAULT),
579 (VmError::AccessDenied.into(), Errno::EFAULT),
580 (VmError::TooLong.into(), Errno::ENAMETOOLONG),
581 (
582 SignalError::UserMemory(VmError::BadAddress).into(),
583 Errno::EFAULT,
584 ),
585 (MmError::InvalidInput("test").into(), Errno::EINVAL),
586 (MmError::NoMemory.into(), Errno::ENOMEM),
587 (MmError::AlreadyExists.into(), Errno::EEXIST),
588 (MmError::BadAddress.into(), Errno::EFAULT),
589 (MmError::BadState("test").into(), Errno::EFAULT),
590 (MmError::Unsupported.into(), Errno::ENOSYS),
591 (
592 MmError::TlbShootdown(TlbShootdownError::Timeout).into(),
593 Errno::ETIMEDOUT,
594 ),
595 (MappingError::InvalidParam.into(), Errno::EINVAL),
596 (MappingError::AlreadyExists.into(), Errno::EEXIST),
597 (MappingError::BadState.into(), Errno::EFAULT),
598 (PagingError::NoMemory.into(), Errno::ENOMEM),
599 (PagingError::not_mapped().into(), Errno::EINVAL),
600 (TlbShootdownError::CpuOffline.into(), Errno::ENOSYS),
601 (TlbShootdownError::Timeout.into(), Errno::ETIMEDOUT),
602 (TlbShootdownError::Unsupported.into(), Errno::ENOSYS),
603 (TlbShootdownError::Platform.into(), Errno::EIO),
604 (
605 TlbShootdownError::GenerationExhausted.into(),
606 Errno::EOVERFLOW,
607 ),
608 (AllocError::InvalidParam.into(), Errno::EINVAL),
609 (AllocError::AlreadyInitialized.into(), Errno::EFAULT),
610 (AllocError::MemoryOverlap.into(), Errno::EEXIST),
611 (AllocError::NoMemory.into(), Errno::ENOMEM),
612 (AllocError::NotAllocated.into(), Errno::EINVAL),
613 (AllocError::NotInitialized.into(), Errno::EFAULT),
614 (AllocError::NotFound.into(), Errno::ENOENT),
615 (CgroupError::NotInitialized.into(), Errno::EINVAL),
616 (CgroupError::NotFound.into(), Errno::ENOENT),
617 (CgroupError::AlreadyExists.into(), Errno::EEXIST),
618 (CgroupError::ResourceBusy.into(), Errno::EBUSY),
619 (CgroupError::LimitExceeded.into(), Errno::EAGAIN),
620 (CgroupError::InvalidInput.into(), Errno::EINVAL),
621 (CgroupError::NoSuchProcess.into(), Errno::ESRCH),
622 (CgroupError::DirectoryNotEmpty.into(), Errno::ENOTEMPTY),
623 ])
624}
625
626#[cfg(all(test, not(axtest)))]
627fn vfs_errno_mappings_hold() -> bool {
628 errno_cases_hold([
629 (VfsError::AlreadyExists.into(), Errno::EEXIST),
630 (VfsError::BadAddress.into(), Errno::EFAULT),
631 (VfsError::BadFileDescriptor.into(), Errno::EBADF),
632 (VfsError::BadState.into(), Errno::EFAULT),
633 (VfsError::CrossesDevices.into(), Errno::EXDEV),
634 (VfsError::DataMissing.into(), Errno::ENODATA),
635 (VfsError::DirectoryNotEmpty.into(), Errno::ENOTEMPTY),
636 (VfsError::FilesystemCorrupted.into(), Errno::EUCLEAN),
637 (VfsError::FilesystemLoop.into(), Errno::ELOOP),
638 (VfsError::FileTooLarge.into(), Errno::EFBIG),
639 (VfsError::InvalidData.into(), Errno::EINVAL),
640 (VfsError::InvalidInput.into(), Errno::EINVAL),
641 (VfsError::Interrupted.into(), Errno::EINTR),
642 (VfsError::Io.into(), Errno::EIO),
643 (VfsError::IsADirectory.into(), Errno::EISDIR),
644 (VfsError::NameTooLong.into(), Errno::ENAMETOOLONG),
645 (VfsError::NoMemory.into(), Errno::ENOMEM),
646 (VfsError::NoSuchDevice.into(), Errno::ENODEV),
647 (VfsError::NoSuchDeviceOrAddress.into(), Errno::ENXIO),
648 (VfsError::NotADirectory.into(), Errno::ENOTDIR),
649 (VfsError::NotATty.into(), Errno::ENOTTY),
650 (VfsError::NotFound.into(), Errno::ENOENT),
651 (VfsError::OperationNotPermitted.into(), Errno::EPERM),
652 (VfsError::OperationNotSupported.into(), Errno::EOPNOTSUPP),
653 (VfsError::PermissionDenied.into(), Errno::EACCES),
654 (VfsError::QuotaExceeded.into(), Errno::EDQUOT),
655 (VfsError::ReadOnlyFilesystem.into(), Errno::EROFS),
656 (VfsError::ResourceBusy.into(), Errno::EBUSY),
657 (VfsError::StorageFull.into(), Errno::ENOSPC),
658 (VfsError::TimedOut.into(), Errno::ETIMEDOUT),
659 (VfsError::TooManyLinks.into(), Errno::EMLINK),
660 (VfsError::Unsupported.into(), Errno::ENOSYS),
661 (VfsError::ValueOverflow.into(), Errno::EOVERFLOW),
662 (VfsError::WouldBlock.into(), Errno::EAGAIN),
663 ])
664}
665
666#[cfg(all(test, not(axtest)))]
667fn io_errno_mappings_hold() -> bool {
668 errno_cases_hold([
669 (IoError::AddrInUse.into(), Errno::EADDRINUSE),
670 (IoError::AlreadyConnected.into(), Errno::EISCONN),
671 (
672 IoError::AddressFamilyUnsupported.into(),
673 Errno::EAFNOSUPPORT,
674 ),
675 (IoError::AlreadyExists.into(), Errno::EEXIST),
676 (IoError::ArgumentListTooLong.into(), Errno::E2BIG),
677 (IoError::BadAddress.into(), Errno::EFAULT),
678 (IoError::BadFileDescriptor.into(), Errno::EBADF),
679 (IoError::BadState.into(), Errno::EFAULT),
680 (IoError::BrokenPipe.into(), Errno::EPIPE),
681 (IoError::ConnectionRefused.into(), Errno::ECONNREFUSED),
682 (IoError::ConnectionReset.into(), Errno::ECONNRESET),
683 (IoError::CrossesDevices.into(), Errno::EXDEV),
684 (IoError::DirectoryNotEmpty.into(), Errno::ENOTEMPTY),
685 (IoError::DestAddrRequired.into(), Errno::EDESTADDRREQ),
686 (IoError::FilesystemLoop.into(), Errno::ELOOP),
687 (IoError::FileTooLarge.into(), Errno::EFBIG),
688 (IoError::IllegalBytes.into(), Errno::EILSEQ),
689 (IoError::InProgress.into(), Errno::EINPROGRESS),
690 (IoError::Interrupted.into(), Errno::EINTR),
691 (IoError::InvalidData.into(), Errno::EINVAL),
692 (IoError::InvalidExecutable.into(), Errno::ENOEXEC),
693 (IoError::InvalidInput.into(), Errno::EINVAL),
694 (IoError::Io.into(), Errno::EIO),
695 (IoError::IsADirectory.into(), Errno::EISDIR),
696 (IoError::NameTooLong.into(), Errno::ENAMETOOLONG),
697 (IoError::MessageTooLong.into(), Errno::EMSGSIZE),
698 (IoError::NoMemory.into(), Errno::ENOMEM),
699 (IoError::NoSuchDevice.into(), Errno::ENODEV),
700 (IoError::NoSuchDeviceOrAddress.into(), Errno::ENXIO),
701 (IoError::NoSuchProcess.into(), Errno::ESRCH),
702 (IoError::NotADirectory.into(), Errno::ENOTDIR),
703 (IoError::NotASocket.into(), Errno::ENOTSOCK),
704 (IoError::NotATty.into(), Errno::ENOTTY),
705 (IoError::NotConnected.into(), Errno::ENOTCONN),
706 (IoError::NotFound.into(), Errno::ENOENT),
707 (IoError::OperationNotPermitted.into(), Errno::EPERM),
708 (IoError::OperationNotSupported.into(), Errno::EOPNOTSUPP),
709 (IoError::OutOfRange.into(), Errno::ERANGE),
710 (IoError::PermissionDenied.into(), Errno::EACCES),
711 (
712 IoError::ProtocolOptionUnsupported.into(),
713 Errno::ENOPROTOOPT,
714 ),
715 (IoError::ReadOnlyFilesystem.into(), Errno::EROFS),
716 (IoError::ResourceBusy.into(), Errno::EBUSY),
717 (IoError::StorageFull.into(), Errno::ENOSPC),
718 (IoError::TimedOut.into(), Errno::ETIMEDOUT),
719 (IoError::TooManyOpenFiles.into(), Errno::EMFILE),
720 (IoError::UnexpectedEof.into(), Errno::EIO),
721 (IoError::Unsupported.into(), Errno::ENOSYS),
722 (IoError::WouldBlock.into(), Errno::EAGAIN),
723 (IoError::WriteZero.into(), Errno::EIO),
724 ])
725}
726
727#[cfg(all(test, not(axtest)))]
728fn block_errno_mappings_hold() -> bool {
729 let device_error = |source| {
730 StarryError::from(BlockError::Device {
731 stage: "submit",
732 operation: RequestOp::Read,
733 lba: 9,
734 source,
735 })
736 };
737
738 errno_cases_hold([
739 (BlockError::InvalidRequest.into(), Errno::EINVAL),
740 (BlockError::InvalidState.into(), Errno::EFAULT),
741 (BlockError::RuntimeUnavailable.into(), Errno::EFAULT),
742 (BlockError::WouldBlock.into(), Errno::EAGAIN),
743 (BlockError::NoMemory.into(), Errno::ENOMEM),
744 (BlockError::Unsupported.into(), Errno::ENOSYS),
745 (BlockError::TimedOut.into(), Errno::ETIMEDOUT),
746 (BlockError::Io.into(), Errno::EIO),
747 (BlockError::ResourceBusy.into(), Errno::EBUSY),
748 (BlockError::NotFound.into(), Errno::ENOENT),
749 (device_error(BlkError::NotSupported), Errno::ENOSYS),
750 (device_error(BlkError::Retry), Errno::EAGAIN),
751 (device_error(BlkError::NoMemory), Errno::ENOMEM),
752 (device_error(BlkError::InvalidBlockIndex(9)), Errno::EINVAL),
753 (device_error(BlkError::InvalidRequest), Errno::EINVAL),
754 (device_error(BlkError::TimedOut), Errno::ETIMEDOUT),
755 (device_error(BlkError::Io), Errno::EIO),
756 (device_error(BlkError::Other("device failure")), Errno::EIO),
757 ])
758}
759
760#[cfg(all(test, not(axtest)))]
761fn leaf_errno_mappings_hold() -> bool {
762 errno_cases_hold([
763 (StarryError::AlreadyExists, Errno::EEXIST),
764 (StarryError::ArgumentListTooLong, Errno::E2BIG),
765 (StarryError::BadAddress, Errno::EFAULT),
766 (StarryError::BadFileDescriptor, Errno::EBADF),
767 (StarryError::BadState, Errno::EFAULT),
768 (StarryError::BrokenPipe, Errno::EPIPE),
769 (StarryError::CrossesDevices, Errno::EXDEV),
770 (StarryError::FilesystemLoop, Errno::ELOOP),
771 (StarryError::IllegalBytes, Errno::EILSEQ),
772 (StarryError::InProgress, Errno::EINPROGRESS),
773 (StarryError::Interrupted, Errno::EINTR),
774 (StarryError::InterruptedNoRestart, Errno::EINTR),
775 (StarryError::InvalidData, Errno::EINVAL),
776 (StarryError::InvalidExecutable, Errno::ENOEXEC),
777 (StarryError::MalformedExecutable, Errno::ENOEXEC),
778 (StarryError::InvalidInput, Errno::EINVAL),
779 (StarryError::Io, Errno::EIO),
780 (StarryError::IsADirectory, Errno::EISDIR),
781 (StarryError::NameTooLong, Errno::ENAMETOOLONG),
782 (StarryError::NoMemory, Errno::ENOMEM),
783 (StarryError::NoSuchDevice, Errno::ENODEV),
784 (StarryError::NoSuchDeviceOrAddress, Errno::ENXIO),
785 (StarryError::NoSuchProcess, Errno::ESRCH),
786 (StarryError::NotADirectory, Errno::ENOTDIR),
787 (StarryError::NotASocket, Errno::ENOTSOCK),
788 (StarryError::NotATty, Errno::ENOTTY),
789 (StarryError::NotFound, Errno::ENOENT),
790 (StarryError::OperationNotPermitted, Errno::EPERM),
791 (StarryError::OperationNotSupported, Errno::EOPNOTSUPP),
792 (StarryError::OutOfRange, Errno::ERANGE),
793 (StarryError::PermissionDenied, Errno::EACCES),
794 (StarryError::ReadOnlyFilesystem, Errno::EROFS),
795 (StarryError::ResourceBusy, Errno::EBUSY),
796 (StarryError::StorageFull, Errno::ENOSPC),
797 (StarryError::TimedOut, Errno::ETIMEDOUT),
798 (StarryError::TooManyOpenFiles, Errno::EMFILE),
799 (StarryError::UnexpectedEof, Errno::EIO),
800 (StarryError::Unsupported, Errno::ENOSYS),
801 (StarryError::WouldBlock, Errno::EAGAIN),
802 (StarryError::WriteZero, Errno::EIO),
803 (StarryError::Format(core::fmt::Error), Errno::EINVAL),
804 (StarryError::Task(TaskError::TimerCapacity), Errno::ENOMEM),
805 (
806 StarryError::Runtime(RuntimeError::SerialNotStarted),
807 Errno::EFAULT,
808 ),
809 (
810 StarryError::Runtime(RuntimeError::SerialControlBusy),
811 Errno::EBUSY,
812 ),
813 (
814 StarryError::Runtime(RuntimeError::Task(TaskError::UnsafeContext)),
815 Errno::EPERM,
816 ),
817 (
818 StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::InvalidBaudrate)),
819 Errno::EINVAL,
820 ),
821 (
822 StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::UnsupportedDataBits)),
823 Errno::EINVAL,
824 ),
825 (
826 StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::UnsupportedStopBits)),
827 Errno::EINVAL,
828 ),
829 (
830 StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::UnsupportedParity)),
831 Errno::EINVAL,
832 ),
833 (
834 StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::Timeout)),
835 Errno::ETIMEDOUT,
836 ),
837 (
838 StarryError::Runtime(RuntimeError::SerialConfig(ConfigError::RegisterError)),
839 Errno::EIO,
840 ),
841 (
842 StarryError::Runtime(RuntimeError::WouldBlock),
843 Errno::EAGAIN,
844 ),
845 (
846 StarryError::Runtime(RuntimeError::OperationNotSupported),
847 Errno::EOPNOTSUPP,
848 ),
849 (
850 StarryError::Runtime(RuntimeError::InvalidCpu { cpu: 99 }),
851 Errno::EINVAL,
852 ),
853 (
854 StarryError::Dma {
855 operation: DmaOperation::BufferAllocation,
856 source: DmaError::NoMemory,
857 },
858 Errno::ENOMEM,
859 ),
860 (
861 StarryError::Dma {
862 operation: DmaOperation::DeviceIo,
863 source: DmaError::NullPointer,
864 },
865 Errno::EINVAL,
866 ),
867 ])
868}
869
870#[cfg(all(test, not(axtest)))]
871fn domain_errno_mappings_hold() -> bool {
872 memory_errno_mappings_hold()
873 && vfs_errno_mappings_hold()
874 && io_errno_mappings_hold()
875 && block_errno_mappings_hold()
876 && leaf_errno_mappings_hold()
877 && StarryError::from(Errno::EOWNERDEAD).linux_errno() == Errno::EOWNERDEAD
878 && StarryError::from(Errno::new(4094)).linux_errno().into_raw() == 4094
879}
880
881pub type StarryResult<T = ()> = Result<T, StarryError>;
883
884#[cfg(all(test, not(axtest)))]
885mod tests {
886 use super::*;
887
888 #[test]
889 fn domain_errors_map_to_stable_linux_errno() {
890 assert!(domain_errno_mappings_hold());
891 }
892
893 #[test]
894 fn readiness_retry_recognizes_filesystem_would_block_without_flattening() {
895 assert!(StarryError::WouldBlock.is_would_block());
896 assert!(StarryError::from(VfsError::WouldBlock).is_would_block());
897 assert!(StarryError::from(IoError::WouldBlock).is_would_block());
898 assert!(!StarryError::from(VfsError::Io).is_would_block());
899 assert!(!StarryError::from(IoError::Io).is_would_block());
900 }
901
902 #[test]
903 fn native_linux_errno_is_not_canonicalized() {
904 let error = StarryError::from(Errno::EOWNERDEAD);
905 assert_eq!(error.linux_errno(), Errno::EOWNERDEAD);
906 }
907
908 #[test]
909 fn unknown_linux_errno_is_preserved() {
910 let error = StarryError::from(Errno::new(4094));
911 assert_eq!(error.linux_errno().into_raw(), 4094);
912 }
913
914 #[cfg(feature = "sg2002")]
915 #[test]
916 fn sg2002_tpu_errors_keep_their_linux_errno() {
917 let cases = [
918 (TpuError::Timeout, Errno::ETIMEDOUT),
919 (TpuError::InvalidDmabuf, Errno::EINVAL),
920 (TpuError::TdmaError(1), Errno::EIO),
921 (TpuError::TiuError(1), Errno::EIO),
922 (TpuError::NotInitialized, Errno::ENODEV),
923 (TpuError::Busy, Errno::EBUSY),
924 (TpuError::Interrupted, Errno::EINTR),
925 (TpuError::PmuBufferNotAligned, Errno::EINVAL),
926 (TpuError::DmabufNotAligned, Errno::EINVAL),
927 ];
928 for (error, expected) in cases {
929 assert_eq!(StarryError::from(error).linux_errno(), expected);
930 }
931 }
932}