1use self::capabilities::*;
7use super::StalledIo;
8use super::core::TransportOps;
9use super::core::VirtioTransportCore;
10use super::task::ConfigReadCompletion;
11use super::task::defer_config_read;
12use super::task::defer_config_write;
13use crate::DynVirtioDevice;
14use crate::MAX_QUEUE_SIZE;
15use crate::spec::VirtioDeviceType;
16use crate::spec::pci::VIRTIO_PCI_COMMON_CFG_SIZE;
17use crate::spec::pci::VIRTIO_PCI_DEVICE_ID_BASE;
18use crate::spec::pci::VIRTIO_VENDOR_ID;
19use crate::spec::pci::VirtioPciCapType;
20use crate::spec::pci::VirtioPciCommonCfg;
21use chipset_device::ChipsetDevice;
22use chipset_device::io::IoError;
23use chipset_device::io::IoResult;
24use chipset_device::io::deferred::defer_read;
25use chipset_device::io::deferred::defer_write;
26use chipset_device::mmio::MmioIntercept;
27use chipset_device::mmio::RegisterMmioIntercept;
28use chipset_device::pci::ByteEnabledDwordRead;
29use chipset_device::pci::ByteEnabledDwordWrite;
30use chipset_device::pci::PciConfigSpace;
31use chipset_device::poll_device::PollDevice;
32use device_emulators::ReadWriteRequestType;
33use device_emulators::read_as_u32_chunks;
34use device_emulators::write_as_u32_chunks;
35use guestmem::DoorbellRegistration;
36use guestmem::GuestMemory;
37use guestmem::MemoryMapper;
38use inspect::Inspect;
39use inspect::InspectMut;
40use pal_async::task::Spawn;
41use parking_lot::Mutex;
42use pci_core::PciInterruptPin;
43use pci_core::capabilities::PciCapability;
44use pci_core::capabilities::ReadOnlyCapability;
45use pci_core::capabilities::msix::MsixEmulator;
46use pci_core::cfg_space_emu::BarMemoryKind;
47use pci_core::cfg_space_emu::ConfigSpaceType0Emulator;
48use pci_core::cfg_space_emu::DeviceBars;
49use pci_core::cfg_space_emu::IntxInterrupt;
50use pci_core::msi::MsiTarget;
51use pci_core::spec::caps::COMMON_HEADER_END;
52use pci_core::spec::caps::CapabilityId;
53use pci_core::spec::hwid::ClassCode;
54use pci_core::spec::hwid::HardwareIds;
55use pci_core::spec::hwid::ProgrammingInterface;
56use pci_core::spec::hwid::Subclass;
57use std::io;
58use std::sync::Arc;
59use vmcore::device_state::ChangeDeviceState;
60use vmcore::interrupt::Interrupt;
61use vmcore::line_interrupt::LineInterrupt;
62use vmcore::save_restore::RestoreError;
63use vmcore::save_restore::SaveError;
64
65pub enum PciInterruptModel<'a> {
67 Msix(&'a MsiTarget),
68 IntX(PciInterruptPin, LineInterrupt),
69}
70
71enum InterruptKind {
72 Msix(MsixEmulator),
73 IntX(Arc<IntxInterrupt>),
74}
75
76const BAR0_NOTIFY_OFFSET: u16 = VIRTIO_PCI_COMMON_CFG_SIZE;
79const BAR0_NOTIFY_SIZE: u16 = 4;
80const BAR0_ISR_OFFSET: u16 = BAR0_NOTIFY_OFFSET + BAR0_NOTIFY_SIZE;
81const BAR0_ISR_SIZE: u16 = 4;
82const BAR0_DEVICE_CFG_OFFSET: u16 = BAR0_ISR_OFFSET + BAR0_ISR_SIZE;
83
84fn virtio_class_code(device_id: VirtioDeviceType) -> (ClassCode, Subclass) {
90 match device_id {
91 VirtioDeviceType::NET => (
92 ClassCode::NETWORK_CONTROLLER,
93 Subclass::NETWORK_CONTROLLER_ETHERNET,
94 ),
95 VirtioDeviceType::BLK => (
96 ClassCode::MASS_STORAGE_CONTROLLER,
97 Subclass::MASS_STORAGE_CONTROLLER_SCSI,
98 ),
99 VirtioDeviceType::CONSOLE => (
100 ClassCode::SIMPLE_COMMUNICATION_CONTROLLER,
101 Subclass::SIMPLE_COMMUNICATION_CONTROLLER_OTHER,
102 ),
103 VirtioDeviceType::RNG
106 | VirtioDeviceType::P9
107 | VirtioDeviceType::VSOCK
108 | VirtioDeviceType::FS
109 | VirtioDeviceType::PMEM => (
110 ClassCode::BASE_SYSTEM_PERIPHERAL,
111 Subclass::BASE_SYSTEM_PERIPHERAL_OTHER,
112 ),
113 _ => {
114 tracelimit::warn_ratelimited!(
115 device_id = device_id.0,
116 "unknown virtio device type; reporting generic class code"
117 );
118 (
119 ClassCode::BASE_SYSTEM_PERIPHERAL,
120 Subclass::BASE_SYSTEM_PERIPHERAL_OTHER,
121 )
122 }
123 }
124}
125
126#[derive(Inspect)]
128struct PciTransport {
129 config_space: ConfigSpaceType0Emulator,
130 #[inspect(skip)]
131 interrupt_kind: InterruptKind,
132 #[inspect(skip)]
133 interrupt_status: Arc<Mutex<u32>>,
134 msix_config_vector: u16,
135 #[inspect(hex)]
136 shared_memory_size: u64,
137 #[inspect(skip)]
139 pci_cfg_access: Arc<Mutex<PciCfgAccessState>>,
140 #[inspect(hex)]
142 pci_cfg_data_offset: u16,
143 #[inspect(hex)]
146 device_register_length: u32,
147}
148
149impl TransportOps for PciTransport {
150 fn create_queue_interrupt(&mut self, _idx: usize, msix_vector: u16) -> Interrupt {
151 match &self.interrupt_kind {
152 InterruptKind::Msix(msix) => {
153 if let Some(interrupt) = msix.interrupt(msix_vector) {
154 interrupt
155 } else {
156 tracelimit::warn_ratelimited!(msix_vector, "invalid MSIx vector specified");
157 Interrupt::null()
158 }
159 }
160 InterruptKind::IntX(line) => {
161 let interrupt_status = self.interrupt_status.clone();
162 let line = line.clone();
163 Interrupt::from_fn(move || {
164 *interrupt_status.lock() |= 1;
165 line.set_level(true);
166 })
167 }
168 }
169 }
170
171 fn signal_config_change(&mut self) {
172 *self.interrupt_status.lock() |= 2;
173 match &self.interrupt_kind {
174 InterruptKind::Msix(msix) => {
175 if let Some(interrupt) = msix.interrupt(self.msix_config_vector) {
176 interrupt.deliver();
177 }
178 }
179 InterruptKind::IntX(line) => line.set_level(true),
180 }
181 }
182
183 fn reset_interrupts(&mut self) {
184 *self.interrupt_status.lock() = 0;
185 if let InterruptKind::IntX(line) = &self.interrupt_kind {
186 line.set_level(false);
187 }
188 self.msix_config_vector = 0;
189 }
190
191 fn doorbell_region(&mut self) -> Option<(u64, u32)> {
192 self.config_space
193 .bar_address(0)
194 .map(|base| (base + BAR0_NOTIFY_OFFSET as u64, 2))
195 }
196}
197
198#[derive(InspectMut)]
200pub struct VirtioPciDevice {
201 #[inspect(flatten)]
202 core: VirtioTransportCore,
203 #[inspect(flatten)]
204 pci: PciTransport,
205}
206
207impl VirtioPciDevice {
208 pub fn new(
209 mut device: Box<dyn DynVirtioDevice>,
210 driver: &impl Spawn,
211 guest_memory: GuestMemory,
212 interrupt_model: PciInterruptModel<'_>,
213 doorbell_registration: Option<Arc<dyn DoorbellRegistration>>,
214 mmio_registration: &mut dyn RegisterMmioIntercept,
215 shared_mem_mapper: Option<&dyn MemoryMapper>,
216 ) -> io::Result<Self> {
217 let traits = device.traits();
218
219 let (base_class, sub_class) = virtio_class_code(traits.device_id);
220 let hardware_ids = HardwareIds {
221 vendor_id: VIRTIO_VENDOR_ID,
222 device_id: VIRTIO_PCI_DEVICE_ID_BASE + traits.device_id.0,
223 revision_id: 1,
224 prog_if: ProgrammingInterface::NONE,
225 base_class,
226 sub_class,
227 type0_sub_vendor_id: pci_core::microsoft::VENDOR_ID,
228 type0_sub_system_id: pci_core::microsoft::DEFAULT_SUBSYSTEM_ID,
229 };
230
231 let mut caps: Vec<Box<dyn PciCapability>> = vec![
232 Box::new(ReadOnlyCapability::new(
233 "virtio-common",
234 VirtioCapability::new(
235 VirtioPciCapType::COMMON_CFG.0,
236 0,
237 0,
238 0,
239 VIRTIO_PCI_COMMON_CFG_SIZE as u32,
240 ),
241 )),
242 Box::new(ReadOnlyCapability::new(
243 "virtio-notify",
244 VirtioNotifyCapability::new(
245 0,
246 0,
247 BAR0_NOTIFY_OFFSET as u32,
248 BAR0_NOTIFY_SIZE as u32,
249 ),
250 )),
251 Box::new(ReadOnlyCapability::new(
252 "virtio-pci-isr",
253 VirtioCapability::new(
254 VirtioPciCapType::ISR_CFG.0,
255 0,
256 0,
257 BAR0_ISR_OFFSET as u32,
258 BAR0_ISR_SIZE as u32,
259 ),
260 )),
261 ];
262
263 if traits.device_register_length > 0 {
270 caps.push(Box::new(ReadOnlyCapability::new(
271 "virtio-pci-device",
272 VirtioCapability::new(
273 VirtioPciCapType::DEVICE_CFG.0,
274 0,
275 0,
276 BAR0_DEVICE_CFG_OFFSET as u32,
277 traits.device_register_length,
278 ),
279 )));
280 }
281
282 let mut bars = DeviceBars::new().bar0(
283 BAR0_DEVICE_CFG_OFFSET as u64 + traits.device_register_length as u64,
284 BarMemoryKind::Intercept(mmio_registration.new_io_region(
285 "config",
286 BAR0_DEVICE_CFG_OFFSET as u64 + traits.device_register_length as u64,
287 )),
288 );
289
290 let msix: Option<MsixEmulator> = if let PciInterruptModel::Msix(msi_target) =
291 interrupt_model
292 {
293 let (msix, msix_capability) = MsixEmulator::new(2, 64, msi_target);
294 caps.insert(0, Box::new(msix_capability));
295 bars = bars.bar2(
296 msix.bar_len(),
297 BarMemoryKind::Intercept(mmio_registration.new_io_region("msix", msix.bar_len())),
298 );
299 Some(msix)
300 } else {
301 None
302 };
303
304 let shared_memory_size = traits.shared_memory.size;
305 if shared_memory_size > 0 {
306 let (control, region) = shared_mem_mapper
307 .expect("must provide mapper for shmem")
308 .new_region(
309 shared_memory_size.try_into().expect("region too big"),
310 "virtio-pci-shmem".into(),
311 )?;
312
313 caps.push(Box::new(ReadOnlyCapability::new(
314 "virtio-pci-shm",
315 VirtioCapability64::new(
316 VirtioPciCapType::SHARED_MEMORY_CFG.0,
317 4, traits.shared_memory.id,
319 0,
320 shared_memory_size,
321 ),
322 )));
323
324 bars = bars.bar4(shared_memory_size, BarMemoryKind::SharedMem(control));
325
326 device
327 .set_shared_memory_region(®ion)
328 .map_err(io::Error::other)?;
329 }
330
331 let pci_cfg_access = Arc::new(Mutex::new(PciCfgAccessState::default()));
336 caps.push(Box::new(VirtioPciCfgCapability {
337 state: pci_cfg_access.clone(),
338 }));
339 let pci_cfg_cap_offset = COMMON_HEADER_END
344 + caps[..caps.len() - 1]
345 .iter()
346 .map(|c| c.len() as u16)
347 .sum::<u16>();
348 let pci_cfg_data_offset = pci_cfg_cap_offset + VIRTIO_PCI_CFG_DATA_OFFSET;
349
350 let mut config_space = ConfigSpaceType0Emulator::new(hardware_ids, caps, Vec::new(), bars);
351 let interrupt_kind = match interrupt_model {
352 PciInterruptModel::Msix(_) => InterruptKind::Msix(msix.unwrap()),
353 PciInterruptModel::IntX(pin, line) => {
354 InterruptKind::IntX(config_space.set_interrupt_pin(pin, line))
355 }
356 };
357
358 let core = VirtioTransportCore::new(device, driver, guest_memory, doorbell_registration)?;
359
360 Ok(VirtioPciDevice {
361 core,
362 pci: PciTransport {
363 config_space,
364 interrupt_kind,
365 interrupt_status: Arc::new(Mutex::new(0)),
366 msix_config_vector: 0,
367 shared_memory_size,
368 pci_cfg_access,
369 pci_cfg_data_offset,
370 device_register_length: traits.device_register_length,
371 },
372 })
373 }
374
375 fn read_u32_local(&mut self, offset: u16) -> u32 {
377 assert!(offset & 3 == 0);
378 let queue_select = self.core.queue_select as usize;
379 match VirtioPciCommonCfg(offset) {
380 VirtioPciCommonCfg::DEVICE_FEATURE_SELECT => self.core.device_feature_select,
381 VirtioPciCommonCfg::DEVICE_FEATURE => self
382 .core
383 .device_feature
384 .bank(self.core.device_feature_select as usize),
385 VirtioPciCommonCfg::DRIVER_FEATURE_SELECT => self.core.driver_feature_select,
386 VirtioPciCommonCfg::DRIVER_FEATURE => self
387 .core
388 .driver_feature
389 .bank(self.core.driver_feature_select as usize),
390 VirtioPciCommonCfg::MSIX_CONFIG => {
391 (self.core.queues.len() as u32) << 16 | self.pci.msix_config_vector as u32
392 }
393 VirtioPciCommonCfg::DEVICE_STATUS => {
394 self.core.queue_select << 16
395 | self.core.config_generation << 8
396 | self.core.device_status.as_u32()
397 }
398 VirtioPciCommonCfg::QUEUE_SIZE => {
399 let size = self
400 .core
401 .queues
402 .get(queue_select)
403 .map_or(0, |qd| qd.params.size);
404 let msix_vector = self
405 .core
406 .queues
407 .get(queue_select)
408 .map_or(0, |qd| qd.msix_vector);
409 (msix_vector as u32) << 16 | size as u32
410 }
411 VirtioPciCommonCfg::QUEUE_ENABLE => {
412 self.core
413 .queues
414 .get(queue_select)
415 .is_some_and(|qd| qd.params.enable) as u32
416 }
417 VirtioPciCommonCfg::QUEUE_DESC_LO => self
418 .core
419 .queues
420 .get(queue_select)
421 .map_or(0, |qd| qd.params.desc_addr as u32),
422 VirtioPciCommonCfg::QUEUE_DESC_HI => self
423 .core
424 .queues
425 .get(queue_select)
426 .map_or(0, |qd| (qd.params.desc_addr >> 32) as u32),
427 VirtioPciCommonCfg::QUEUE_AVAIL_LO => self
428 .core
429 .queues
430 .get(queue_select)
431 .map_or(0, |qd| qd.params.avail_addr as u32),
432 VirtioPciCommonCfg::QUEUE_AVAIL_HI => self
433 .core
434 .queues
435 .get(queue_select)
436 .map_or(0, |qd| (qd.params.avail_addr >> 32) as u32),
437 VirtioPciCommonCfg::QUEUE_USED_LO => self
438 .core
439 .queues
440 .get(queue_select)
441 .map_or(0, |qd| qd.params.used_addr as u32),
442 VirtioPciCommonCfg::QUEUE_USED_HI => self
443 .core
444 .queues
445 .get(queue_select)
446 .map_or(0, |qd| (qd.params.used_addr >> 32) as u32),
447 VirtioPciCommonCfg(BAR0_NOTIFY_OFFSET) => 0,
448 VirtioPciCommonCfg(BAR0_ISR_OFFSET) => {
449 let mut interrupt_status = self.pci.interrupt_status.lock();
450 let status = *interrupt_status;
451 *interrupt_status = 0;
452 if let InterruptKind::IntX(line) = &self.pci.interrupt_kind {
453 line.set_level(false)
454 }
455 status
456 }
457 _ => {
458 tracelimit::warn_ratelimited!(offset, "unknown bar read");
459 0xffffffff
460 }
461 }
462 }
463
464 fn write_u32_local(&mut self, offset: u16, val: u32) {
466 assert!(offset & 3 == 0);
467 let queues_locked = self.core.device_status.driver_ok();
468 let features_locked = queues_locked || self.core.device_status.features_ok();
469 let queue_select = self.core.queue_select as usize;
470 match VirtioPciCommonCfg(offset) {
471 VirtioPciCommonCfg::DEVICE_FEATURE_SELECT => self.core.device_feature_select = val,
472 VirtioPciCommonCfg::DRIVER_FEATURE_SELECT => self.core.driver_feature_select = val,
473 VirtioPciCommonCfg::DRIVER_FEATURE => {
474 let bank = self.core.driver_feature_select as usize;
475 if !features_locked && bank < 2 {
476 self.core
477 .driver_feature
478 .set_bank(bank, val & self.core.device_feature.bank(bank));
479 }
480 }
481 VirtioPciCommonCfg::MSIX_CONFIG => self.pci.msix_config_vector = val as u16,
482 VirtioPciCommonCfg::DEVICE_STATUS => {
483 self.core.queue_select = val >> 16;
484 self.core.write_device_status(&mut self.pci, val as u8);
485 }
486 VirtioPciCommonCfg::QUEUE_SIZE => {
487 let msix_vector = (val >> 16) as u16;
488 if !queues_locked && queue_select < self.core.queues.len() {
489 let val = val as u16;
490 let qd = &mut self.core.queues[queue_select];
491 if val > MAX_QUEUE_SIZE {
492 qd.params.size = MAX_QUEUE_SIZE;
493 } else {
494 qd.params.size = val;
495 }
496 qd.msix_vector = msix_vector;
497 }
498 }
499 VirtioPciCommonCfg::QUEUE_ENABLE => {
500 let val = val & 0xffff;
501 if !queues_locked && queue_select < self.core.queues.len() {
502 self.core.queues[queue_select].params.enable = val != 0;
503 }
504 }
505 VirtioPciCommonCfg::QUEUE_DESC_LO => {
506 if !queues_locked && queue_select < self.core.queues.len() {
507 let queue = &mut self.core.queues[queue_select].params;
508 queue.desc_addr = queue.desc_addr & 0xffffffff00000000 | val as u64;
509 }
510 }
511 VirtioPciCommonCfg::QUEUE_DESC_HI => {
512 if !queues_locked && queue_select < self.core.queues.len() {
513 let queue = &mut self.core.queues[queue_select].params;
514 queue.desc_addr = (val as u64) << 32 | queue.desc_addr & 0xffffffff;
515 }
516 }
517 VirtioPciCommonCfg::QUEUE_AVAIL_LO => {
518 if !queues_locked && queue_select < self.core.queues.len() {
519 let queue = &mut self.core.queues[queue_select].params;
520 queue.avail_addr = queue.avail_addr & 0xffffffff00000000 | val as u64;
521 }
522 }
523 VirtioPciCommonCfg::QUEUE_AVAIL_HI => {
524 if !queues_locked && queue_select < self.core.queues.len() {
525 let queue = &mut self.core.queues[queue_select].params;
526 queue.avail_addr = (val as u64) << 32 | queue.avail_addr & 0xffffffff;
527 }
528 }
529 VirtioPciCommonCfg::QUEUE_USED_LO => {
530 if !queues_locked && queue_select < self.core.queues.len() {
531 let queue = &mut self.core.queues[queue_select].params;
532 queue.used_addr = queue.used_addr & 0xffffffff00000000 | val as u64;
533 }
534 }
535 VirtioPciCommonCfg::QUEUE_USED_HI => {
536 if !queues_locked && queue_select < self.core.queues.len() {
537 let queue = &mut self.core.queues[queue_select].params;
538 queue.used_addr = (val as u64) << 32 | queue.used_addr & 0xffffffff;
539 }
540 }
541 VirtioPciCommonCfg(BAR0_NOTIFY_OFFSET) => {
542 self.core.notify_queue(val);
543 }
544 _ => {
545 tracelimit::warn_ratelimited!(offset, "unknown bar write at offset");
546 }
547 }
548 }
549
550 fn read_transport(&mut self, offset: u16, data: &mut [u8]) {
552 read_as_u32_chunks(offset, data, |offset| self.read_u32_local(offset));
553 }
554
555 fn write_transport(&mut self, offset: u16, data: &[u8]) {
557 write_as_u32_chunks(offset, data, |offset, request_type| match request_type {
558 ReadWriteRequestType::Write(value) => {
559 self.write_u32_local(offset, value);
560 None
561 }
562 ReadWriteRequestType::Read => Some(self.read_u32_local(offset)),
563 });
564 }
565
566 fn pci_cfg_bar_offset(&self, bar: u8, offset: u32, length: u32) -> Option<u16> {
570 let bar_len = match bar {
571 0 => u32::from(BAR0_DEVICE_CFG_OFFSET) + self.pci.device_register_length,
572 2 => match &self.pci.interrupt_kind {
573 InterruptKind::Msix(msix) => msix.bar_len() as u32,
574 _ => return None,
575 },
576 _ => return None,
577 };
578 if offset.checked_add(length)? > bar_len {
582 return None;
583 }
584 u16::try_from(offset).ok()
585 }
586
587 fn read_pci_cfg_data(&mut self, value: &mut u32) -> IoResult {
596 let (bar, offset, length) = {
597 let state = self.pci.pci_cfg_access.lock();
598 (state.bar, state.offset, state.length)
599 };
600 if !matches!(length, 1 | 2 | 4) {
603 return IoResult::Err(IoError::InvalidAccessSize);
604 }
605 if !offset.is_multiple_of(length) {
606 return IoResult::Err(IoError::UnalignedAccess);
607 }
608 let Some(offset) = self.pci_cfg_bar_offset(bar, offset, length) else {
611 return IoResult::Err(IoError::InvalidRegister);
612 };
613 let len = length as usize;
614 if bar == 0 && offset >= BAR0_DEVICE_CFG_OFFSET {
615 let dev_offset = offset - BAR0_DEVICE_CFG_OFFSET;
621 return defer_config_read(
622 &self.core.device_sender,
623 dev_offset,
624 len as u8,
625 ConfigReadCompletion::LeftAlignedDword,
626 );
627 }
628 let mut buf = [0u8; 4];
631 let result = self.read_pci_cfg_bar(bar, offset, &mut buf[..len]);
632 if let IoResult::Ok = result {
633 *value = u32::from_le_bytes(buf);
634 }
635 result
636 }
637
638 fn write_pci_cfg_data(&mut self, value: u32) -> IoResult {
640 let (bar, offset, length) = {
641 let state = self.pci.pci_cfg_access.lock();
642 (state.bar, state.offset, state.length)
643 };
644 if !matches!(length, 1 | 2 | 4) {
645 return IoResult::Err(IoError::InvalidAccessSize);
646 }
647 if !offset.is_multiple_of(length) {
648 return IoResult::Err(IoError::UnalignedAccess);
649 }
650 let Some(offset) = self.pci_cfg_bar_offset(bar, offset, length) else {
653 return IoResult::Err(IoError::InvalidRegister);
654 };
655 let len = length as usize;
656 let bytes = value.to_le_bytes();
659 let data = &bytes[..len];
660 if bar == 0 && offset >= BAR0_DEVICE_CFG_OFFSET {
661 return defer_config_write(
662 &self.core.device_sender,
663 offset - BAR0_DEVICE_CFG_OFFSET,
664 data,
665 );
666 }
667 self.write_pci_cfg_bar(bar, offset, data)
668 }
669
670 fn read_pci_cfg_bar(&mut self, bar: u8, offset: u16, data: &mut [u8]) -> IoResult {
674 match bar {
675 0 => self.read_transport(offset, data),
676 2 => read_as_u32_chunks(offset, data, |offset| {
677 if let InterruptKind::Msix(msix) = &self.pci.interrupt_kind {
678 msix.read_u32(offset as u64)
679 } else {
680 !0
681 }
682 }),
683 _ => return IoResult::Err(IoError::InvalidRegister),
684 }
685 IoResult::Ok
686 }
687
688 fn write_pci_cfg_bar(&mut self, bar: u8, offset: u16, data: &[u8]) -> IoResult {
692 match bar {
693 0 => self.write_transport(offset, data),
694 2 => {
695 write_as_u32_chunks(offset, data, |offset, request_type| match request_type {
696 ReadWriteRequestType::Write(value) => {
697 if let InterruptKind::Msix(msix) = &mut self.pci.interrupt_kind {
698 msix.write_u32(offset as u64, value)
699 }
700 None
701 }
702 ReadWriteRequestType::Read => {
703 if let InterruptKind::Msix(msix) = &self.pci.interrupt_kind {
704 Some(msix.read_u32(offset as u64))
705 } else {
706 Some(!0)
707 }
708 }
709 });
710 }
711 _ => return IoResult::Err(IoError::InvalidRegister),
712 }
713 IoResult::Ok
714 }
715
716 fn replay_stalled_io(&mut self) {
718 let stalled = std::mem::take(&mut self.core.stalled_io);
719 let mut iter = stalled.into_iter();
720 for io in &mut iter {
721 match io {
722 StalledIo::Read {
723 address,
724 len,
725 deferred,
726 } => {
727 if let Some((_, offset)) = self.pci.config_space.find_bar(address) {
728 let mut buf = vec![0u8; len];
729 self.read_transport(offset as u16, &mut buf);
730 deferred.complete(&buf);
731 } else {
732 deferred.complete_error(IoError::InvalidRegister);
735 }
736 }
737 StalledIo::Write {
738 address,
739 data,
740 len,
741 deferred,
742 } => {
743 if let Some((_, offset)) = self.pci.config_space.find_bar(address) {
744 self.write_transport(offset as u16, &data[..len]);
745 if self.core.state.is_busy() {
746 self.core.pending_status_deferred = Some(deferred);
747 break;
748 }
749 deferred.complete();
750 } else {
751 deferred.complete_error(IoError::InvalidRegister);
752 }
753 }
754 }
755 }
756 self.core.stalled_io = iter.collect();
757 }
758
759 #[cfg(test)]
760 pub(crate) fn read_u32(&mut self, offset: u16) -> u32 {
761 self.read_u32_local(offset)
762 }
763
764 #[cfg(test)]
765 pub(crate) fn write_u32(&mut self, offset: u16, val: u32) {
766 self.write_u32_local(offset, val);
767 }
768}
769
770impl ChangeDeviceState for VirtioPciDevice {
771 fn start(&mut self) {
772 self.core.start(&mut self.pci);
773 }
774
775 async fn stop(&mut self) {
776 self.core.stop(&mut self.pci).await;
777 }
778
779 async fn reset(&mut self) {
780 self.core.reset(&mut self.pci).await;
781 self.pci.config_space.reset();
782 }
783}
784
785impl PollDevice for VirtioPciDevice {
786 fn poll_device(&mut self, cx: &mut std::task::Context<'_>) {
787 self.core.poll_device(&mut self.pci, cx);
788 if !self.core.stalled_io.is_empty() && !self.core.state.is_busy() {
790 self.replay_stalled_io();
791 }
792 }
793}
794
795impl ChipsetDevice for VirtioPciDevice {
796 fn supports_mmio(&mut self) -> Option<&mut dyn MmioIntercept> {
797 Some(self)
798 }
799
800 fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> {
801 Some(self)
802 }
803
804 fn supports_poll_device(&mut self) -> Option<&mut dyn PollDevice> {
805 Some(self)
806 }
807}
808
809mod saved_state {
810 mod state {
811 use crate::transport::saved_state::state::CommonQueueState;
812 use crate::transport::saved_state::state::CommonSavedState;
813 use mesh::payload::Protobuf;
814 use pci_core::cfg_space_emu::ConfigSpaceType0Emulator;
815 use vmcore::save_restore::SaveRestore;
816 use vmcore::save_restore::SavedStateRoot;
817
818 #[derive(Protobuf)]
819 #[mesh(package = "virtio.transport.pci")]
820 pub struct SavedQueueState {
821 #[mesh(1)]
822 pub common: CommonQueueState,
823 #[mesh(2)]
824 pub msix_vector: u16,
825 }
826
827 #[derive(Protobuf, SavedStateRoot)]
828 #[mesh(package = "virtio.transport.pci")]
829 pub struct SavedState {
830 #[mesh(1)]
831 pub common: CommonSavedState,
832 #[mesh(2)]
833 pub msix_config_vector: u16,
834 #[mesh(3)]
835 pub queues: Vec<SavedQueueState>,
836 #[mesh(4)]
837 pub interrupt_status: u32,
838 #[mesh(5)]
842 pub cfg_space: <ConfigSpaceType0Emulator as SaveRestore>::SavedState,
843 }
844
845 #[derive(Protobuf, SavedStateRoot)]
846 #[mesh(package = "virtio.transport.pci")]
847 pub struct CfgCapSavedState {
848 #[mesh(1)]
849 pub bar: u8,
850 #[mesh(2)]
851 pub offset: u32,
852 #[mesh(3)]
853 pub length: u32,
854 }
855 }
856
857 use super::*;
858 use vmcore::save_restore::SaveRestore;
859
860 impl SaveRestore for VirtioPciDevice {
861 type SavedState = state::SavedState;
862
863 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
864 Ok(state::SavedState {
865 common: self.core.save_common()?,
866 msix_config_vector: self.pci.msix_config_vector,
867 queues: self
868 .core
869 .queues
870 .iter()
871 .enumerate()
872 .map(|(i, qd)| state::SavedQueueState {
873 common: self.core.save_queue_common(i),
874 msix_vector: qd.msix_vector,
875 })
876 .collect(),
877 interrupt_status: *self.pci.interrupt_status.lock(),
878 cfg_space: self.pci.config_space.save()?,
879 })
880 }
881
882 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
883 let saved_queue_count = state.queues.len();
884
885 self.pci.config_space.restore(state.cfg_space)?;
899
900 self.core.restore_common(
901 &mut self.pci,
902 &state.common,
903 state
904 .queues
905 .into_iter()
906 .map(|sq| (sq.common, sq.msix_vector)),
907 saved_queue_count,
908 )?;
909
910 *self.pci.interrupt_status.lock() = state.interrupt_status;
912 if let InterruptKind::IntX(line) = &self.pci.interrupt_kind {
913 line.set_level(state.interrupt_status != 0);
914 }
915 self.pci.msix_config_vector = state.msix_config_vector;
916
917 Ok(())
918 }
919 }
920
921 impl SaveRestore for VirtioPciCfgCapability {
922 type SavedState = state::CfgCapSavedState;
923
924 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
925 let state = self.state.lock();
926 Ok(state::CfgCapSavedState {
927 bar: state.bar,
928 offset: state.offset,
929 length: state.length,
930 })
931 }
932
933 fn restore(&mut self, saved_state: Self::SavedState) -> Result<(), RestoreError> {
934 let state::CfgCapSavedState {
935 bar,
936 offset,
937 length,
938 } = saved_state;
939 let mut state = self.state.lock();
940 state.bar = bar;
941 state.offset = offset;
942 state.length = length;
943 Ok(())
944 }
945 }
946}
947
948impl MmioIntercept for VirtioPciDevice {
949 fn mmio_read(&mut self, address: u64, data: &mut [u8]) -> IoResult {
950 let Some((bar, offset)) = self.pci.config_space.find_bar(address) else {
951 return IoResult::Err(IoError::InvalidRegister);
952 };
953 let offset = offset as u16;
954 if bar == 0 && offset >= BAR0_DEVICE_CFG_OFFSET {
955 return defer_config_read(
956 &self.core.device_sender,
957 offset - BAR0_DEVICE_CFG_OFFSET,
958 data.len() as u8,
959 ConfigReadCompletion::Exact,
960 );
961 }
962 if bar == 0 && self.core.state.is_busy() {
963 let (deferred, token) = defer_read();
964 self.core.stalled_io.push(StalledIo::Read {
965 address,
966 len: data.len(),
967 deferred,
968 });
969 return IoResult::Defer(token);
970 }
971 match bar {
972 0 => self.read_transport(offset, data),
973 2 => read_as_u32_chunks(offset, data, |offset| {
974 if let InterruptKind::Msix(msix) = &self.pci.interrupt_kind {
975 msix.read_u32(offset as u64)
976 } else {
977 !0
978 }
979 }),
980 _ => return IoResult::Err(IoError::InvalidRegister),
981 }
982 IoResult::Ok
983 }
984
985 fn mmio_write(&mut self, address: u64, data: &[u8]) -> IoResult {
986 let Some((bar, offset)) = self.pci.config_space.find_bar(address) else {
987 return IoResult::Err(IoError::InvalidRegister);
988 };
989 let offset = offset as u16;
990 if bar == 0 && offset >= BAR0_DEVICE_CFG_OFFSET {
991 return defer_config_write(
992 &self.core.device_sender,
993 offset - BAR0_DEVICE_CFG_OFFSET,
994 data,
995 );
996 }
997 if bar == 0 && self.core.state.is_busy() {
998 let (deferred, token) = defer_write();
999 let mut buf = [0u8; 8];
1000 buf[..data.len()].copy_from_slice(data);
1001 self.core.stalled_io.push(StalledIo::Write {
1002 address,
1003 data: buf,
1004 len: data.len(),
1005 deferred,
1006 });
1007 return IoResult::Defer(token);
1008 }
1009 match bar {
1010 0 => self.write_transport(offset, data),
1011 2 => {
1012 write_as_u32_chunks(offset, data, |offset, request_type| match request_type {
1013 ReadWriteRequestType::Write(value) => {
1014 if let InterruptKind::Msix(msix) = &mut self.pci.interrupt_kind {
1015 msix.write_u32(offset as u64, value)
1016 }
1017 None
1018 }
1019 ReadWriteRequestType::Read => {
1020 if let InterruptKind::Msix(msix) = &self.pci.interrupt_kind {
1021 Some(msix.read_u32(offset as u64))
1022 } else {
1023 Some(!0)
1024 }
1025 }
1026 });
1027 }
1028 _ => return IoResult::Err(IoError::InvalidRegister),
1029 }
1030 if bar == 0 && self.core.state.is_busy() {
1031 let (deferred, token) = defer_write();
1032 self.core.pending_status_deferred = Some(deferred);
1033 return IoResult::Defer(token);
1034 }
1035 IoResult::Ok
1036 }
1037}
1038
1039impl PciConfigSpace for VirtioPciDevice {
1040 fn pci_cfg_read(&mut self, offset: u16, mut value: ByteEnabledDwordRead<'_>) -> IoResult {
1041 if offset == self.pci.pci_cfg_data_offset {
1042 let mut dword = 0;
1043 let result = self.read_pci_cfg_data(&mut dword);
1044 if let IoResult::Ok = result {
1045 value.set(dword);
1046 }
1047 return result;
1048 }
1049 self.pci.config_space.read_byte_enabled(offset, value)
1050 }
1051
1052 fn pci_cfg_write(&mut self, offset: u16, value: ByteEnabledDwordWrite) -> IoResult {
1053 if offset == self.pci.pci_cfg_data_offset {
1054 return self.write_pci_cfg_data(value.merge(0));
1055 }
1056 self.pci.config_space.write_byte_enabled(offset, value)
1057 }
1058}
1059
1060const VIRTIO_PCI_CFG_CAP_LEN: u8 = 20;
1063const VIRTIO_PCI_CFG_DATA_OFFSET: u16 = 16;
1065
1066#[derive(Debug, Default, Inspect)]
1074struct PciCfgAccessState {
1075 bar: u8,
1076 #[inspect(hex)]
1077 offset: u32,
1078 #[inspect(hex)]
1079 length: u32,
1080}
1081
1082struct VirtioPciCfgCapability {
1091 state: Arc<Mutex<PciCfgAccessState>>,
1092}
1093
1094impl Inspect for VirtioPciCfgCapability {
1095 fn inspect(&self, req: inspect::Request<'_>) {
1096 let state = self.state.lock();
1097 req.respond()
1098 .field("label", "virtio-pci-cfg")
1099 .field("bar", state.bar)
1100 .hex("offset", state.offset)
1101 .hex("length", state.length);
1102 }
1103}
1104
1105impl PciCapability for VirtioPciCfgCapability {
1106 fn label(&self) -> &str {
1107 "virtio-pci-cfg"
1108 }
1109
1110 fn capability_id(&self) -> CapabilityId {
1111 CapabilityId::VENDOR_SPECIFIC
1112 }
1113
1114 fn len(&self) -> usize {
1115 VIRTIO_PCI_CFG_CAP_LEN as usize
1116 }
1117
1118 fn read(&self, offset: u16, mut value: ByteEnabledDwordRead<'_>) {
1119 let state = self.state.lock();
1120 let dword = match offset {
1121 0 => {
1124 CapabilityId::VENDOR_SPECIFIC.0 as u32
1125 | (VIRTIO_PCI_CFG_CAP_LEN as u32) << 16
1126 | (VirtioPciCapType::PCI_CFG.0 as u32) << 24
1127 }
1128 4 => state.bar as u32,
1131 8 => state.offset,
1132 12 => state.length,
1133 _ => 0,
1135 };
1136 value.set(dword);
1137 }
1138
1139 fn write(&mut self, offset: u16, val: ByteEnabledDwordWrite) {
1140 let mut state = self.state.lock();
1141 match offset {
1142 0 => {}
1145 4 => state.bar = val.merge(state.bar.into()) as u8,
1148 8 => state.offset = val.merge(state.offset),
1149 12 => state.length = val.merge(state.length),
1150 _ => {}
1152 }
1153 }
1154
1155 fn reset(&mut self) {
1156 *self.state.lock() = PciCfgAccessState::default();
1157 }
1158}
1159
1160pub(crate) mod capabilities {
1161 use crate::spec::pci::VirtioPciCapType;
1162 use pci_core::spec::caps::CapabilityId;
1163
1164 use zerocopy::Immutable;
1165 use zerocopy::IntoBytes;
1166 use zerocopy::KnownLayout;
1167
1168 #[repr(C)]
1169 #[derive(Debug, IntoBytes, Immutable, KnownLayout)]
1170 pub struct VirtioCapabilityCommon {
1171 cap_id: u8,
1172 cap_next: u8,
1173 len: u8,
1174 typ: u8,
1175 bar: u8,
1176 unique_id: u8,
1177 padding: [u8; 2],
1178 offset: u32,
1179 length: u32,
1180 }
1181
1182 impl VirtioCapabilityCommon {
1183 pub fn new(len: u8, typ: u8, bar: u8, unique_id: u8, addr_off: u32, addr_len: u32) -> Self {
1184 Self {
1185 cap_id: CapabilityId::VENDOR_SPECIFIC.0,
1186 cap_next: 0,
1187 len,
1188 typ,
1189 bar,
1190 unique_id,
1191 padding: [0; 2],
1192 offset: addr_off,
1193 length: addr_len,
1194 }
1195 }
1196 }
1197
1198 #[repr(C)]
1199 #[derive(Debug, IntoBytes, Immutable, KnownLayout)]
1200 pub struct VirtioCapability {
1201 common: VirtioCapabilityCommon,
1202 }
1203
1204 impl VirtioCapability {
1205 pub fn new(typ: u8, bar: u8, unique_id: u8, addr_off: u32, addr_len: u32) -> Self {
1206 Self {
1207 common: VirtioCapabilityCommon::new(
1208 size_of::<Self>() as u8,
1209 typ,
1210 bar,
1211 unique_id,
1212 addr_off,
1213 addr_len,
1214 ),
1215 }
1216 }
1217 }
1218
1219 #[repr(C)]
1220 #[derive(Debug, IntoBytes, Immutable, KnownLayout)]
1221 pub struct VirtioCapability64 {
1222 common: VirtioCapabilityCommon,
1223 offset_hi: u32,
1224 length_hi: u32,
1225 }
1226
1227 impl VirtioCapability64 {
1228 pub fn new(typ: u8, bar: u8, unique_id: u8, addr_off: u64, addr_len: u64) -> Self {
1229 Self {
1230 common: VirtioCapabilityCommon::new(
1231 size_of::<Self>() as u8,
1232 typ,
1233 bar,
1234 unique_id,
1235 addr_off as u32,
1236 addr_len as u32,
1237 ),
1238 offset_hi: (addr_off >> 32) as u32,
1239 length_hi: (addr_len >> 32) as u32,
1240 }
1241 }
1242 }
1243
1244 #[repr(C)]
1245 #[derive(Debug, IntoBytes, Immutable, KnownLayout)]
1246 pub struct VirtioNotifyCapability {
1247 common: VirtioCapabilityCommon,
1248 offset_multiplier: u32,
1249 }
1250
1251 impl VirtioNotifyCapability {
1252 pub fn new(offset_multiplier: u32, bar: u8, addr_off: u32, addr_len: u32) -> Self {
1253 Self {
1254 common: VirtioCapabilityCommon::new(
1255 size_of::<Self>() as u8,
1256 VirtioPciCapType::NOTIFY_CFG.0,
1257 bar,
1258 0,
1259 addr_off,
1260 addr_len,
1261 ),
1262 offset_multiplier,
1263 }
1264 }
1265 }
1266
1267 #[cfg(test)]
1268 mod tests {
1269 use super::*;
1270 use pci_core::capabilities::ReadOnlyCapability;
1271 use pci_core::test_helpers::read_cap_u32;
1272
1273 #[test]
1274 fn common_check() {
1275 let common =
1276 ReadOnlyCapability::new("common", VirtioCapability::new(0x13, 2, 0, 0x100, 0x200));
1277 assert_eq!(read_cap_u32(&common, 0), 0x13100009);
1278 assert_eq!(read_cap_u32(&common, 4), 2);
1279 assert_eq!(read_cap_u32(&common, 8), 0x100);
1280 assert_eq!(read_cap_u32(&common, 12), 0x200);
1281 }
1282
1283 #[test]
1284 fn notify_check() {
1285 let notify = ReadOnlyCapability::new(
1286 "notify",
1287 VirtioNotifyCapability::new(0x123, 2, 0x100, 0x200),
1288 );
1289 assert_eq!(read_cap_u32(¬ify, 0), 0x2140009);
1290 assert_eq!(read_cap_u32(¬ify, 4), 2);
1291 assert_eq!(read_cap_u32(¬ify, 8), 0x100);
1292 assert_eq!(read_cap_u32(¬ify, 12), 0x200);
1293 }
1294 }
1295}