Skip to main content

axvirtio_common/
error.rs

1//! VirtIO error types and runtime error conversion.
2//!
3//! This module defines common error types used across all VirtIO device implementations.
4
5use alloc::format;
6
7use axdevice_base::DeviceError;
8
9/// VirtIO specific error types
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum VirtioError {
12    /// Invalid queue configuration
13    InvalidQueue,
14    /// Queue not ready for operation (not configured yet)
15    QueueNotReady,
16    /// Invalid descriptor
17    InvalidDescriptor,
18    /// Invalid access width for MMIO operation
19    InvalidAccessWidth,
20    /// Device not ready
21    DeviceNotReady,
22    /// Invalid device index
23    InvalidDeviceIndex,
24    /// Backend operation failed
25    BackendError,
26    /// Memory access error
27    MemoryError,
28    /// Invalid configuration
29    InvalidConfig,
30    /// Feature negotiation failed
31    FeatureNegotiationFailed,
32    /// Invalid request
33    InvalidRequest,
34    /// Operation not supported
35    NotSupported,
36    /// Invalid buffer size
37    InvalidBufferSize,
38    /// Invalid sector
39    InvalidSector,
40    /// Invalid register
41    InvalidRegister,
42    /// Invalid address or address translation failed
43    InvalidAddress,
44    /// One or more virtqueue rings are misaligned (desc 16B, avail 2B, used 4B)
45    RingMisaligned,
46    /// The virtqueue ring regions overlap each other
47    RingOverlap,
48    /// The virtqueue ring layout is invalid (zero address, region overflow, or
49    /// a ring region lies outside the guest address space)
50    InvalidRingLayout,
51    /// The queue is faulted after a runtime ring/descriptor failure and must be
52    /// reset before further use. Unlike [`QueueNotReady`](Self::QueueNotReady),
53    /// which is a normal pre-configuration state, a faulted queue has served
54    /// requests and hit a runtime failure; its guest-serving data paths
55    /// (`pop`/`complete`, chain walks and data access) reject with this error
56    /// and write no guest memory until `reset`, while the configuration
57    /// setters remain usable.
58    QueueFaulted,
59    /// Resource not found
60    NotFound,
61    /// The operation is valid but cannot complete until asynchronous backend
62    /// work makes progress.
63    WouldBlock,
64    /// Invalid input
65    InvalidInput,
66}
67
68/// Result type for VirtIO operations
69pub type VirtioResult<T> = Result<T, VirtioError>;
70
71/// Maps a VirtIO error to the runtime category that determines the caller's
72/// recovery action.
73pub fn map_virtio_error(error: VirtioError, operation: &'static str) -> DeviceError {
74    match error {
75        VirtioError::BackendError => DeviceError::Backend {
76            operation,
77            detail: format!("{error:?}"),
78        },
79        VirtioError::QueueFaulted => DeviceError::InvalidState {
80            operation,
81            detail: "queue faulted; guest reset required".into(),
82        },
83        VirtioError::QueueNotReady | VirtioError::DeviceNotReady => DeviceError::InvalidState {
84            operation,
85            detail: format!("{error:?}"),
86        },
87        VirtioError::WouldBlock => DeviceError::ResourceBusy {
88            operation,
89            resource: "VirtIO queue or reset transition".into(),
90        },
91        VirtioError::NotSupported => DeviceError::Unsupported {
92            operation,
93            detail: format!("{error:?}"),
94        },
95        VirtioError::MemoryError | VirtioError::InvalidAddress => DeviceError::InvalidData {
96            operation,
97            detail: format!("{error:?}"),
98        },
99        VirtioError::InvalidAccessWidth
100        | VirtioError::InvalidDeviceIndex
101        | VirtioError::InvalidRegister
102        | VirtioError::InvalidRequest
103        | VirtioError::FeatureNegotiationFailed
104        | VirtioError::InvalidInput => DeviceError::InvalidInput {
105            operation,
106            detail: format!("{error:?}"),
107        },
108        VirtioError::NotFound => DeviceError::NotFound,
109        VirtioError::InvalidQueue
110        | VirtioError::InvalidDescriptor
111        | VirtioError::InvalidConfig
112        | VirtioError::InvalidBufferSize
113        | VirtioError::InvalidSector
114        | VirtioError::RingMisaligned
115        | VirtioError::RingOverlap
116        | VirtioError::InvalidRingLayout => DeviceError::InvalidData {
117            operation,
118            detail: format!("{error:?}"),
119        },
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn preserves_runtime_error_categories() {
129        assert!(matches!(
130            map_virtio_error(VirtioError::BackendError, "test operation"),
131            DeviceError::Backend { .. }
132        ));
133        assert!(matches!(
134            map_virtio_error(VirtioError::QueueFaulted, "test operation"),
135            DeviceError::InvalidState { .. }
136        ));
137        assert!(matches!(
138            map_virtio_error(VirtioError::WouldBlock, "test operation"),
139            DeviceError::ResourceBusy { .. }
140        ));
141        assert!(matches!(
142            map_virtio_error(VirtioError::InvalidAddress, "test operation"),
143            DeviceError::InvalidData { .. }
144        ));
145    }
146}