vmm/devices/virtio/
device.rs1use std::fmt;
9use std::sync::Arc;
10use std::sync::atomic::AtomicU32;
11
12use vmm_sys_util::eventfd::EventFd;
13
14use super::ActivateError;
15use super::queue::{Queue, QueueError};
16use super::transport::VirtioInterrupt;
17use crate::devices::virtio::AsAny;
18use crate::devices::virtio::block::virtio::io::cow_io::CowFileEngine;
19use crate::logger::warn;
20use crate::vstate::memory::GuestMemoryMmap;
21
22#[derive(Debug, Clone)]
24pub struct ActiveState {
25 pub mem: GuestMemoryMmap,
26 pub interrupt: Arc<dyn VirtioInterrupt>,
27}
28
29#[derive(Debug)]
32pub enum DeviceState {
33 Inactive,
34 Activated(ActiveState),
35}
36
37impl DeviceState {
38 pub fn is_activated(&self) -> bool {
40 match self {
41 DeviceState::Inactive => false,
42 DeviceState::Activated(_) => true,
43 }
44 }
45
46 pub fn active_state(&self) -> Option<&ActiveState> {
48 match self {
49 DeviceState::Activated(state) => Some(state),
50 DeviceState::Inactive => None,
51 }
52 }
53}
54
55pub trait VirtioDevice: AsAny + Send {
62 fn avail_features(&self) -> u64;
64
65 fn acked_features(&self) -> u64;
67
68 fn set_acked_features(&mut self, acked_features: u64);
72
73 fn has_feature(&self, feature: u64) -> bool {
75 (self.acked_features() & (1 << feature)) != 0
76 }
77
78 fn const_device_type() -> u32
80 where
81 Self: Sized;
82
83 fn device_type(&self) -> u32;
87
88 fn queues(&self) -> &[Queue];
90
91 fn queues_mut(&mut self) -> &mut [Queue];
93
94 fn queue_events(&self) -> &[EventFd];
96
97 fn interrupt_status(&self) -> Arc<AtomicU32> {
99 self.interrupt_trigger().status()
100 }
101
102 fn interrupt_trigger(&self) -> &dyn VirtioInterrupt;
103
104 fn avail_features_by_page(&self, page: u32) -> u32 {
106 let avail_features = self.avail_features();
107 match page {
108 0 => (avail_features & 0xFFFFFFFF) as u32,
110 1 => (avail_features >> 32) as u32,
112 _ => {
113 warn!("Received request for unknown features page.");
114 0u32
115 }
116 }
117 }
118
119 fn ack_features_by_page(&mut self, page: u32, value: u32) {
121 let mut v = match page {
122 0 => u64::from(value),
123 1 => u64::from(value) << 32,
124 _ => {
125 warn!("Cannot acknowledge unknown features page: {}", page);
126 0u64
127 }
128 };
129
130 let avail_features = self.avail_features();
132 let unrequested_features = v & !avail_features;
133 if unrequested_features != 0 {
134 warn!("Received acknowledge request for unknown feature: {:#x}", v);
135 v &= !unrequested_features;
137 }
138 self.set_acked_features(self.acked_features() | v);
139 }
140
141 fn read_config(&self, offset: u64, data: &mut [u8]);
143
144 fn write_config(&mut self, offset: u64, data: &[u8]);
146
147 fn activate(
149 &mut self,
150 mem: GuestMemoryMmap,
151 interrupt: Arc<dyn VirtioInterrupt>,
152 ) -> Result<(), ActivateError>;
153
154 fn is_activated(&self) -> bool;
156
157 fn reset(&mut self) -> Option<(Arc<dyn VirtioInterrupt>, Vec<EventFd>)> {
160 None
161 }
162
163 fn mark_queue_memory_dirty(&mut self, mem: &GuestMemoryMmap) -> Result<(), QueueError> {
165 for queue in self.queues_mut() {
166 queue.initialize(mem)?
167 }
168 Ok(())
169 }
170
171 fn kick(&mut self) {}
173
174 fn as_cow_file_engine(&self) -> Option<&CowFileEngine> {
176 None
177 }
178
179 fn nyx_handle_queue_event(&mut self, _queue_index: u16) {}
181}
182
183impl fmt::Debug for dyn VirtioDevice {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 write!(f, "VirtioDevice type {}", self.device_type())
186 }
187}
188
189#[macro_export]
191macro_rules! impl_device_type {
192 ($const_type:expr) => {
193 fn const_device_type() -> u32 {
194 $const_type
195 }
196
197 fn device_type(&self) -> u32 {
198 Self::const_device_type()
199 }
200 };
201}
202
203#[cfg(test)]
204pub(crate) mod tests {
205 use super::*;
206
207 #[derive(Debug)]
208 struct MockVirtioDevice {
209 avail_features: u64,
210 acked_features: u64,
211 }
212
213 impl VirtioDevice for MockVirtioDevice {
214 impl_device_type!(0);
215
216 fn avail_features(&self) -> u64 {
217 self.avail_features
218 }
219
220 fn acked_features(&self) -> u64 {
221 self.acked_features
222 }
223
224 fn set_acked_features(&mut self, acked_features: u64) {
225 self.acked_features = acked_features
226 }
227
228 fn queues(&self) -> &[Queue] {
229 todo!()
230 }
231
232 fn queues_mut(&mut self) -> &mut [Queue] {
233 todo!()
234 }
235
236 fn queue_events(&self) -> &[EventFd] {
237 todo!()
238 }
239
240 fn interrupt_trigger(&self) -> &dyn VirtioInterrupt {
241 todo!()
242 }
243
244 fn read_config(&self, _offset: u64, _data: &mut [u8]) {
245 todo!()
246 }
247
248 fn write_config(&mut self, _offset: u64, _data: &[u8]) {
249 todo!()
250 }
251
252 fn activate(
253 &mut self,
254 _mem: GuestMemoryMmap,
255 _interrupt: Arc<dyn VirtioInterrupt>,
256 ) -> Result<(), ActivateError> {
257 todo!()
258 }
259
260 fn is_activated(&self) -> bool {
261 todo!()
262 }
263 }
264
265 #[test]
266 fn test_has_feature() {
267 let mut device = MockVirtioDevice {
268 avail_features: 0,
269 acked_features: 0,
270 };
271
272 let mock_feature_1 = 1u64;
273 assert!(!device.has_feature(mock_feature_1));
274 device.acked_features = 1 << mock_feature_1;
275 assert!(device.has_feature(mock_feature_1));
276
277 let mock_feature_2 = 2u64;
278 assert!(!device.has_feature(mock_feature_2));
279 device.acked_features = (1 << mock_feature_1) | (1 << mock_feature_2);
280 assert!(device.has_feature(mock_feature_1));
281 assert!(device.has_feature(mock_feature_2));
282 }
283
284 #[test]
285 fn test_features() {
286 let features: u64 = 0x11223344_55667788;
287
288 let mut device = MockVirtioDevice {
289 avail_features: features,
290 acked_features: 0,
291 };
292
293 assert_eq!(
294 device.avail_features_by_page(0),
295 (features & 0xFFFFFFFF) as u32,
296 );
297 assert_eq!(device.avail_features_by_page(1), (features >> 32) as u32);
298 for i in 2..10 {
299 assert_eq!(device.avail_features_by_page(i), 0u32);
300 }
301
302 for i in 0..10 {
303 device.ack_features_by_page(i, u32::MAX);
304 }
305
306 assert_eq!(device.acked_features, features);
307 }
308}