1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! Typed GICv3 failures.
use alloc::string::String;
use axdevice_base::DeviceError;
use axvm_types::AccessWidth;
use crate::IntId;
/// Result returned by GICv3 domain operations.
pub type VgicResult<T = ()> = Result<T, VgicError>;
/// GICv3 register block involved in an access.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RegisterRegion {
/// Distributor register frame.
Distributor,
/// GICv2 memory-mapped CPU-interface frame.
CpuInterface,
/// One Redistributor register frame.
Redistributor,
/// Interrupt Translation Service register frame.
Its,
}
/// Errors reported by the virtual GICv3 model.
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
pub enum VgicError {
/// A raw INTID is reserved or outside the configured range.
#[error("INTID {raw} is not valid for this GICv3 instance")]
InvalidIntId {
/// Rejected architectural INTID.
raw: u32,
},
/// A typed INTID has the wrong class for an operation.
#[error("INTID {intid:?} cannot be used for {operation}")]
WrongIntIdClass {
/// Rejected typed INTID.
intid: IntId,
/// Operation requiring another class.
operation: &'static str,
},
/// Controller configuration violates a GICv3 invariant.
#[error("invalid GICv3 configuration: {detail}")]
InvalidConfig {
/// Configuration invariant that was violated.
detail: String,
},
/// A register access has an invalid address, alignment, or width.
#[error("invalid {region:?} {operation} at offset {offset:#x} with width {width:?}: {detail}")]
InvalidAccess {
/// Register block being accessed.
region: RegisterRegion,
/// Whether the access is a read or write.
operation: &'static str,
/// Offset from the frame base.
offset: u64,
/// Requested access width.
width: AccessWidth,
/// Rejected alignment or register constraint.
detail: String,
},
/// A requested interrupt state transition is not architecturally valid.
#[error("invalid state transition for {intid:?} during {operation}: {detail}")]
InvalidStateTransition {
/// Interrupt being changed.
intid: IntId,
/// Transition operation.
operation: &'static str,
/// Current-state diagnostic.
detail: String,
},
/// A VM-local resource is already owned.
#[error("GICv3 resource conflict for {resource}: {detail}")]
ResourceConflict {
/// Conflicting resource kind.
resource: &'static str,
/// Ownership diagnostic.
detail: String,
},
/// A required mapping or vCPU association does not exist.
#[error("GICv3 resource {resource} was not found during {operation}")]
ResourceNotFound {
/// Missing resource diagnostic.
resource: String,
/// Operation requiring it.
operation: &'static str,
},
/// A hard-IRQ delivery exhausted its preallocated queue capacity.
#[error("vCPU {vcpu} has no preallocated delivery slot for {intid:?}")]
DeliveryQueueFull {
/// Target virtual CPU.
vcpu: usize,
/// Interrupt that could not be queued without allocating.
intid: IntId,
},
/// Guest-memory access for an ITS queue failed.
#[error("ITS guest-memory {operation} at {address:#x} for {length} bytes failed: {detail}")]
GuestMemory {
/// Memory operation.
operation: &'static str,
/// Guest physical address.
address: u64,
/// Byte count.
length: usize,
/// Memory-capability diagnostic.
detail: String,
},
/// An ITS command is malformed or invalid for current mappings.
#[error("invalid ITS command {opcode:#x} at queue offset {offset:#x}: {detail}")]
InvalidItsCommand {
/// Command opcode.
opcode: u8,
/// Command-queue offset.
offset: u64,
/// Command diagnostic.
detail: String,
},
/// One command submission exceeds the configured work budget.
#[error("ITS command submission exceeds budget {budget} at queue offset {offset:#x}")]
ItsCommandBudgetExceeded {
/// Maximum commands processed per submission.
budget: usize,
/// First unprocessed queue offset.
offset: u64,
},
/// A selected mode or backend lacks a requested capability.
#[error("unsupported GICv3 operation {operation}: {detail}")]
Unsupported {
/// Unsupported operation.
operation: &'static str,
/// Capability diagnostic.
detail: String,
},
/// A checked physical GIC/ITS or CPU-interface backend failed.
#[error("GICv3 backend operation {operation} failed: {detail}")]
Backend {
/// Backend operation.
operation: &'static str,
/// Backend diagnostic.
detail: String,
},
}
impl From<VgicError> for DeviceError {
fn from(error: VgicError) -> Self {
let detail = alloc::format!("{error}");
match error {
VgicError::Unsupported { operation, .. } => Self::Unsupported { operation, detail },
VgicError::Backend { operation, .. } => Self::Backend { operation, detail },
VgicError::ResourceConflict { resource, .. } => Self::ResourceBusy {
operation: "access ARM VGIC",
resource: alloc::format!("{resource}: {detail}"),
},
VgicError::ResourceNotFound { operation, .. } => {
Self::InvalidState { operation, detail }
}
VgicError::GuestMemory { operation, .. } => Self::Backend { operation, detail },
_ => Self::InvalidInput {
operation: "access ARM VGIC",
detail,
},
}
}
}