axvirtio_common/pci/transport/
state.rs1use alloc::{format, sync::Arc};
2use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
3
4use axdevice_base::{DeviceError, DeviceResult};
5
6use super::VirtioQueueGeneration;
7use crate::{
8 NoGuestMemoryAccessor, VirtioQueue,
9 constants::{
10 VIRTIO_STATUS_ACKNOWLEDGE, VIRTIO_STATUS_DEVICE_NEEDS_RESET, VIRTIO_STATUS_DRIVER,
11 VIRTIO_STATUS_DRIVER_OK, VIRTIO_STATUS_FAILED, VIRTIO_STATUS_FEATURES_OK,
12 },
13};
14
15const DRIVER_PHASE_BITS: u8 = (VIRTIO_STATUS_ACKNOWLEDGE
16 | VIRTIO_STATUS_DRIVER
17 | VIRTIO_STATUS_FEATURES_OK
18 | VIRTIO_STATUS_DRIVER_OK) as u8;
19const DRIVER_STATUS_BITS: u8 = DRIVER_PHASE_BITS | VIRTIO_STATUS_FAILED as u8;
20const KNOWN_STATUS_BITS: u8 = DRIVER_STATUS_BITS | VIRTIO_STATUS_DEVICE_NEEDS_RESET as u8;
21
22#[derive(Debug)]
23pub(super) struct QueueActivity {
24 pub(super) accepting: AtomicBool,
25 pub(super) active: AtomicUsize,
26 pub(super) resetting: AtomicBool,
27}
28
29impl QueueActivity {
30 pub(super) const fn new() -> Self {
31 Self {
32 accepting: AtomicBool::new(true),
33 active: AtomicUsize::new(0),
34 resetting: AtomicBool::new(false),
35 }
36 }
37
38 pub(super) fn begin_reset(&self) -> bool {
39 self.resetting
40 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
41 .is_ok()
42 }
43
44 pub(super) fn acquire(
45 self: &Arc<Self>,
46 generation: VirtioQueueGeneration,
47 ) -> Option<ActivityPermit> {
48 if !self.accepting.load(Ordering::Acquire) {
49 return None;
50 }
51 self.active.fetch_add(1, Ordering::AcqRel);
52 if self.accepting.load(Ordering::Acquire) {
53 Some(ActivityPermit {
54 activity: Arc::clone(self),
55 generation,
56 })
57 } else {
58 self.active.fetch_sub(1, Ordering::AcqRel);
59 None
60 }
61 }
62
63 pub(super) fn close_and_drain(&self) -> bool {
64 self.accepting.store(false, Ordering::Release);
65 for _ in 0..super::RESET_DRAIN_SPIN_LIMIT {
66 if self.active.load(Ordering::Acquire) == 0 {
67 return true;
68 }
69 core::hint::spin_loop();
70 }
71 false
72 }
73
74 pub(super) fn reopen(&self) {
75 self.accepting.store(true, Ordering::Release);
76 }
77
78 pub(super) fn finish_reset(&self) {
79 self.resetting.store(false, Ordering::Release);
80 }
81}
82
83#[derive(Debug)]
85pub struct ActivityPermit {
86 pub(super) activity: Arc<QueueActivity>,
87 pub(super) generation: VirtioQueueGeneration,
88}
89
90impl Drop for ActivityPermit {
91 fn drop(&mut self) {
92 self.activity.active.fetch_sub(1, Ordering::Release);
93 }
94}
95
96#[derive(Debug)]
97pub(super) struct QueueState {
98 pub(super) queue: VirtioQueue<NoGuestMemoryAccessor>,
99 pub(super) enabled: bool,
100 pub(super) processing: bool,
101}
102
103pub(super) struct TransportState {
104 pub(super) device_feature_select: u32,
105 pub(super) driver_feature_select: u32,
106 pub(super) driver_features: u64,
107 pub(super) status: u8,
108 pub(super) queue_select: u16,
109 pub(super) queue_size: u16,
110 pub(super) queues: alloc::vec::Vec<QueueState>,
111 pub(super) queue_generation: u64,
112 pub(super) config_generation: u8,
113 pub(super) fault_reported: bool,
114 pub(super) device_needs_reset: bool,
115 pub(super) reset_pending: bool,
116}
117
118impl TransportState {
119 pub(super) fn new(queue_num_max: u16, queue_size_max: u16) -> Self {
120 let queues = (0..queue_num_max)
121 .map(|index| QueueState {
122 queue: VirtioQueue::new(index, queue_size_max, Arc::new(NoGuestMemoryAccessor)),
123 enabled: false,
124 processing: false,
125 })
126 .collect();
127 Self {
128 device_feature_select: 0,
129 driver_feature_select: 0,
130 driver_features: 0,
131 status: 0,
132 queue_select: 0,
133 queue_size: queue_size_max,
134 queues,
135 queue_generation: 0,
136 config_generation: 0,
137 fault_reported: false,
138 device_needs_reset: false,
139 reset_pending: false,
140 }
141 }
142
143 pub(super) fn reset(&mut self, queue_size_max: u16) {
144 self.device_feature_select = 0;
145 self.driver_feature_select = 0;
146 self.driver_features = 0;
147 self.status = VIRTIO_STATUS_DEVICE_NEEDS_RESET as u8;
148 self.queue_select = 0;
149 self.queue_size = queue_size_max;
150 self.queue_generation = self.queue_generation.wrapping_add(1);
151 self.config_generation = self.config_generation.wrapping_add(1);
152 self.fault_reported = false;
153 self.device_needs_reset = true;
154 self.reset_pending = true;
155 for queue in &mut self.queues {
156 queue.enabled = false;
157 queue.processing = false;
158 queue.queue.reset();
159 }
160 }
161
162 pub(super) fn write_driver_status(
163 &mut self,
164 requested: u8,
165 device_features: u64,
166 ) -> DeviceResult {
167 if requested & !KNOWN_STATUS_BITS != 0 {
168 return Err(DeviceError::InvalidInput {
169 operation: "virtio-pci status",
170 detail: format!("unknown status bits: {requested:#x}"),
171 });
172 }
173
174 let current_driver = self.status & DRIVER_STATUS_BITS;
175 let requested_driver = requested & DRIVER_STATUS_BITS;
176 if current_driver & !requested_driver != 0 {
177 return Err(DeviceError::InvalidState {
178 operation: "update virtio-pci status",
179 detail: format!(
180 "nonzero status writes cannot clear driver bits: {current_driver:#x} -> \
181 {requested_driver:#x}"
182 ),
183 });
184 }
185 if current_driver & VIRTIO_STATUS_FAILED as u8 != 0 && requested_driver != current_driver {
186 return Err(DeviceError::InvalidState {
187 operation: "update virtio-pci status",
188 detail: "FAILED status requires a device reset before further progress".into(),
189 });
190 }
191
192 validate_driver_status_phase(requested_driver)?;
193
194 let device_status = if self.device_needs_reset {
195 VIRTIO_STATUS_DEVICE_NEEDS_RESET as u8
196 } else {
197 0
198 };
199 let mut accepted_driver = requested_driver;
200 if current_driver & VIRTIO_STATUS_FEATURES_OK as u8 == 0
201 && requested_driver & VIRTIO_STATUS_FEATURES_OK as u8 != 0
202 && self.driver_features & !device_features != 0
203 {
204 accepted_driver &= !(VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK) as u8;
207 }
208
209 self.status = accepted_driver | device_status;
210 Ok(())
211 }
212
213 pub(super) fn ensure_feature_negotiation_open(&self) -> DeviceResult {
214 if self.status & (VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_FAILED) as u8 != 0 {
215 Err(DeviceError::InvalidState {
216 operation: "update virtio-pci driver features",
217 detail: "driver features are frozen after feature negotiation closes".into(),
218 })
219 } else {
220 Ok(())
221 }
222 }
223}
224
225fn validate_driver_status_phase(status: u8) -> DeviceResult {
226 let acknowledge = VIRTIO_STATUS_ACKNOWLEDGE as u8;
227 let driver = VIRTIO_STATUS_DRIVER as u8;
228 let features_ok = VIRTIO_STATUS_FEATURES_OK as u8;
229 let driver_ok = VIRTIO_STATUS_DRIVER_OK as u8;
230 let valid = status & driver == 0 || status & acknowledge != 0;
231 let features_valid =
232 status & features_ok == 0 || status & (acknowledge | driver) == acknowledge | driver;
233 let driver_ok_valid = status & driver_ok == 0
234 || status & (acknowledge | driver | features_ok) == acknowledge | driver | features_ok;
235 if valid && features_valid && driver_ok_valid {
236 Ok(())
237 } else {
238 Err(DeviceError::InvalidState {
239 operation: "update virtio-pci status",
240 detail: format!("driver status phase is out of order: {status:#x}"),
241 })
242 }
243}