1use crate::QUEUE_MAX_SIZE;
5use crate::QueueResources;
6use crate::Resources;
7use crate::VirtioDevice;
8use crate::VirtioDoorbells;
9use crate::queue::QueueParams;
10use crate::spec::*;
11use chipset_device::ChipsetDevice;
12use chipset_device::io::IoResult;
13use chipset_device::mmio::MmioIntercept;
14use device_emulators::ReadWriteRequestType;
15use device_emulators::read_as_u32_chunks;
16use device_emulators::write_as_u32_chunks;
17use guestmem::DoorbellRegistration;
18use inspect::InspectMut;
19use parking_lot::Mutex;
20use std::fmt;
21use std::ops::RangeInclusive;
22use std::sync::Arc;
23use vmcore::device_state::ChangeDeviceState;
24use vmcore::interrupt::Interrupt;
25use vmcore::line_interrupt::LineInterrupt;
26use vmcore::save_restore::NoSavedState;
27use vmcore::save_restore::RestoreError;
28use vmcore::save_restore::SaveError;
29use vmcore::save_restore::SaveRestore;
30
31pub struct VirtioMmioDevice {
33 fixed_mmio_region: (&'static str, RangeInclusive<u64>),
34
35 device: Box<dyn VirtioDevice>,
36 device_id: u32,
37 vendor_id: u32,
38 device_feature: [u32; 2],
39 device_feature_select: u32,
40 driver_feature: [u32; 2],
41 driver_feature_select: u32,
42 queue_select: u32,
43 events: Vec<pal_event::Event>,
44 queues: Vec<QueueParams>,
45 device_status: u32,
46 config_generation: u32,
47 doorbells: VirtioDoorbells,
48 interrupt_state: Arc<Mutex<InterruptState>>,
49}
50
51struct InterruptState {
52 interrupt: LineInterrupt,
53 status: u32,
54}
55
56impl InterruptState {
57 fn update(&mut self, is_set: bool, bits: u32) {
58 if is_set {
59 self.status |= bits;
60 } else {
61 self.status &= !bits;
62 }
63 self.interrupt.set_level(self.status != 0);
64 }
65}
66
67impl fmt::Debug for VirtioMmioDevice {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 f.debug_struct("VirtioMmioDevice").finish()
71 }
72}
73
74impl InspectMut for VirtioMmioDevice {
75 fn inspect_mut(&mut self, _req: inspect::Request<'_>) {
76 }
78}
79
80impl VirtioMmioDevice {
81 pub fn new(
82 device: Box<dyn VirtioDevice>,
83 interrupt: LineInterrupt,
84 doorbell_registration: Option<Arc<dyn DoorbellRegistration>>,
85 mmio_gpa: u64,
86 mmio_len: u64,
87 ) -> Self {
88 let traits = device.traits();
89 let queues = (0..traits.max_queues)
90 .map(|_| QueueParams {
91 size: QUEUE_MAX_SIZE,
92 ..Default::default()
93 })
94 .collect();
95 let events = (0..traits.max_queues)
96 .map(|_| pal_event::Event::new())
97 .collect();
98 let interrupt_state = Arc::new(Mutex::new(InterruptState {
99 interrupt,
100 status: 0,
101 }));
102
103 Self {
104 fixed_mmio_region: ("virtio-chipset", mmio_gpa..=(mmio_gpa + mmio_len - 1)),
105 device,
106 device_id: traits.device_id as u32,
107 vendor_id: 0x1af4,
108 device_feature: [
109 traits.device_features as u32
110 | VIRTIO_F_RING_EVENT_IDX
111 | VIRTIO_F_RING_INDIRECT_DESC,
112 (traits.device_features >> 32) as u32 | VIRTIO_F_VERSION_1,
113 ],
114 device_feature_select: 0,
115 driver_feature: [0; 2],
116 driver_feature_select: 0,
117 queue_select: 0,
118 events,
119 queues,
120 device_status: 0,
121 config_generation: 0,
122 doorbells: VirtioDoorbells::new(doorbell_registration),
123 interrupt_state,
124 }
125 }
126
127 fn update_config_generation(&mut self) {
128 self.config_generation = self.config_generation.wrapping_add(1);
129 if self.device_status & VIRTIO_DRIVER_OK != 0 {
130 self.interrupt_state
131 .lock()
132 .update(true, VIRTIO_MMIO_INTERRUPT_STATUS_CONFIG_CHANGE);
133 }
134 }
135}
136
137impl Drop for VirtioMmioDevice {
138 fn drop(&mut self) {
139 self.device.disable();
140 }
141}
142
143impl VirtioMmioDevice {
144 pub(crate) fn read_u32(&self, address: u64) -> u32 {
145 let offset = (address & 0xfff) as u16;
146 assert!(offset & 3 == 0);
147 match offset {
148 0 => u32::from_le_bytes(*b"virt"),
150 4 => 2,
152 8 => self.device_id,
154 12 => self.vendor_id,
156 16 => {
158 let feature_select = self.device_feature_select as usize;
159 if feature_select < self.device_feature.len() {
160 self.device_feature[feature_select]
161 } else {
162 0
163 }
164 }
165 20 => self.device_feature_select,
167 32 => {
172 let feature_select = self.driver_feature_select as usize;
173 if feature_select < self.driver_feature.len() {
174 self.driver_feature[feature_select]
175 } else {
176 0
177 }
178 }
179 36 => self.driver_feature_select,
181 48 => self.queue_select,
186 52 => {
188 let queue_select = self.queue_select as usize;
189 if queue_select < self.queues.len() {
190 QUEUE_MAX_SIZE.into()
191 } else {
192 0
193 }
194 }
195 56 => {
197 let queue_select = self.queue_select as usize;
198 if queue_select < self.queues.len() {
199 self.queues[queue_select].size as u32
200 } else {
201 0
202 }
203 }
204 68 => {
209 let queue_select = self.queue_select as usize;
210 if queue_select < self.queues.len() {
211 if self.queues[queue_select].enable {
212 1
213 } else {
214 0
215 }
216 } else {
217 0
218 }
219 }
220 80 => 0,
225 96 => self.interrupt_state.lock().status,
230 100 => 0,
232 112 => self.device_status,
237 128 => {
242 let queue_select = self.queue_select as usize;
243 if queue_select < self.queues.len() {
244 self.queues[queue_select].desc_addr as u32
245 } else {
246 0
247 }
248 }
249 132 => {
251 let queue_select = self.queue_select as usize;
252 if queue_select < self.queues.len() {
253 (self.queues[queue_select].desc_addr >> 32) as u32
254 } else {
255 0
256 }
257 }
258 144 => {
263 let queue_select = self.queue_select as usize;
264 if queue_select < self.queues.len() {
265 self.queues[queue_select].avail_addr as u32
266 } else {
267 0
268 }
269 }
270 148 => {
272 let queue_select = self.queue_select as usize;
273 if queue_select < self.queues.len() {
274 (self.queues[queue_select].avail_addr >> 32) as u32
275 } else {
276 0
277 }
278 }
279 160 => {
284 let queue_select = self.queue_select as usize;
285 if queue_select < self.queues.len() {
286 self.queues[queue_select].used_addr as u32
287 } else {
288 0
289 }
290 }
291 164 => {
293 let queue_select = self.queue_select as usize;
294 if queue_select < self.queues.len() {
295 (self.queues[queue_select].used_addr >> 32) as u32
296 } else {
297 0
298 }
299 }
300 0xfc => self.config_generation,
301 offset if offset >= 0x100 => self.device.read_registers_u32(offset - 0x100),
302 _ => 0xffffffff,
303 }
304 }
305
306 pub(crate) fn write_u32(&mut self, address: u64, val: u32) {
307 let offset = (address & 0xfff) as u16;
308 assert!(offset & 3 == 0);
309 let queue_select = self.queue_select as usize;
310 let queues_locked = self.device_status & VIRTIO_DRIVER_OK != 0;
311 let features_locked = queues_locked || self.device_status & VIRTIO_FEATURES_OK != 0;
312 match offset {
313 20 => self.device_feature_select = val,
315 32 => {
317 let bank = self.driver_feature_select as usize;
318 if !features_locked && bank < self.driver_feature.len() {
319 self.driver_feature[bank] = val & self.device_feature[bank];
320 }
321 }
322 36 => self.driver_feature_select = val,
324 48 => self.queue_select = val,
326 56 => {
328 if !queues_locked && queue_select < self.queues.len() {
329 let val = val as u16;
330 let queue = &mut self.queues[queue_select];
331 if val > QUEUE_MAX_SIZE {
332 queue.size = QUEUE_MAX_SIZE;
333 } else {
334 queue.size = val;
335 }
336 }
337 }
338 68 => {
340 if !queues_locked && queue_select < self.queues.len() {
341 let queue = &mut self.queues[queue_select];
342 queue.enable = val != 0;
343 }
344 }
345 80 => {
347 if (val as usize) < self.events.len() {
348 self.events[val as usize].signal();
349 }
350 }
351 100 => {
353 self.interrupt_state.lock().update(false, val);
354 }
355 112 => {
357 if val == 0 {
358 let started = (self.device_status & VIRTIO_DRIVER_OK) != 0;
359 self.device_status = 0;
360 self.config_generation = 0;
361 if started {
362 self.doorbells.clear();
363 self.device.disable();
364 }
365 self.interrupt_state.lock().update(false, !0);
366 }
367
368 self.device_status |= val & (VIRTIO_ACKNOWLEDGE | VIRTIO_DRIVER | VIRTIO_FAILED);
369
370 if self.device_status & VIRTIO_FEATURES_OK == 0 && val & VIRTIO_FEATURES_OK != 0 {
371 self.device_status |= VIRTIO_FEATURES_OK;
372 self.update_config_generation();
373 }
374
375 if self.device_status & VIRTIO_DRIVER_OK == 0 && val & VIRTIO_DRIVER_OK != 0 {
376 let features =
377 ((self.driver_feature[1] as u64) << 32) | self.driver_feature[0] as u64;
378
379 let notification_address = (address & !0xfff) + 80;
380 for i in 0..self.events.len() {
381 self.doorbells.add(
382 notification_address,
383 Some(i as u64),
384 Some(4),
385 &self.events[i],
386 );
387 }
388 let queues = self
389 .queues
390 .iter()
391 .zip(self.events.iter().cloned())
392 .map(|(queue, event)| {
393 let interrupt_state = self.interrupt_state.clone();
394 let notify = Interrupt::from_fn(move || {
395 interrupt_state
396 .lock()
397 .update(true, VIRTIO_MMIO_INTERRUPT_STATUS_USED_BUFFER);
398 });
399 QueueResources {
400 params: *queue,
401 notify,
402 event,
403 }
404 })
405 .collect();
406
407 self.device.enable(Resources {
408 features,
409 queues,
410 shared_memory_region: None,
411 shared_memory_size: 0,
412 });
413
414 self.device_status |= VIRTIO_DRIVER_OK;
415 self.update_config_generation();
416 }
417 }
418 128 => {
420 if !queues_locked && queue_select < self.queues.len() {
421 let queue = &mut self.queues[queue_select];
422 queue.desc_addr = queue.desc_addr & 0xffffffff00000000 | val as u64;
423 }
424 }
425 132 => {
427 if !queues_locked && queue_select < self.queues.len() {
428 let queue = &mut self.queues[queue_select];
429 queue.desc_addr = (val as u64) << 32 | queue.desc_addr & 0xffffffff;
430 }
431 }
432 144 => {
434 if !queues_locked && queue_select < self.queues.len() {
435 let queue = &mut self.queues[queue_select];
436 queue.avail_addr = queue.avail_addr & 0xffffffff00000000 | val as u64;
437 }
438 }
439 148 => {
441 if !queues_locked && queue_select < self.queues.len() {
442 let queue = &mut self.queues[queue_select];
443 queue.avail_addr = (val as u64) << 32 | queue.avail_addr & 0xffffffff;
444 }
445 }
446 160 => {
448 if !queues_locked && (queue_select) < self.queues.len() {
449 let queue = &mut self.queues[queue_select];
450 queue.used_addr = queue.used_addr & 0xffffffff00000000 | val as u64;
451 }
452 }
453 164 => {
455 if !queues_locked && queue_select < self.queues.len() {
456 let queue = &mut self.queues[queue_select];
457 queue.used_addr = (val as u64) << 32 | queue.used_addr & 0xffffffff;
458 }
459 }
460 offset if offset >= 0x100 => self.device.write_registers_u32(offset - 0x100, val),
461 _ => (),
462 }
463 }
464}
465
466impl ChangeDeviceState for VirtioMmioDevice {
467 fn start(&mut self) {}
468
469 async fn stop(&mut self) {}
470
471 async fn reset(&mut self) {
472 }
474}
475
476impl ChipsetDevice for VirtioMmioDevice {
477 fn supports_mmio(&mut self) -> Option<&mut dyn MmioIntercept> {
478 Some(self)
479 }
480}
481
482impl SaveRestore for VirtioMmioDevice {
483 type SavedState = NoSavedState; fn save(&mut self) -> Result<Self::SavedState, SaveError> {
486 Ok(NoSavedState)
487 }
488
489 fn restore(&mut self, NoSavedState: Self::SavedState) -> Result<(), RestoreError> {
490 Ok(())
491 }
492}
493
494impl MmioIntercept for VirtioMmioDevice {
495 fn mmio_read(&mut self, address: u64, data: &mut [u8]) -> IoResult {
496 read_as_u32_chunks(address, data, |address| self.read_u32(address));
497 IoResult::Ok
498 }
499
500 fn mmio_write(&mut self, address: u64, data: &[u8]) -> IoResult {
501 write_as_u32_chunks(address, data, |address, request_type| match request_type {
502 ReadWriteRequestType::Write(value) => {
503 self.write_u32(address, value);
504 None
505 }
506 ReadWriteRequestType::Read => Some(self.read_u32(address)),
507 });
508 IoResult::Ok
509 }
510
511 fn get_static_regions(&mut self) -> &[(&str, RangeInclusive<u64>)] {
512 std::slice::from_ref(&self.fixed_mmio_region)
513 }
514}