diff --git a/vm/devices/virtio/virtio/src/tests.rs b/vm/devices/virtio/virtio/src/tests.rs index 58f38808b4..aa9d5aecf0 100644 --- a/vm/devices/virtio/virtio/src/tests.rs +++ b/vm/devices/virtio/virtio/src/tests.rs @@ -61,10 +61,12 @@ use vmcore::vm_task::SingleDriverBackend; use vmcore::vm_task::VmTaskDriverSource; // Device features - first bank +const TEST_DEVICE_FEATURE_BIT: u32 = 2; // arbitrary device-specific feature for testing const VIRTIO_F_RING_INDIRECT_DESC: u32 = 0x10000000; const VIRTIO_F_RING_EVENT_IDX: u32 = 0x20000000; // Device features - second bank const VIRTIO_F_VERSION_1: u32 = 1; +const VIRTIO_F_ACCESS_PLATFORM: u32 = 2; const VIRTIO_F_RING_PACKED: u32 = 4; // Device status @@ -1399,7 +1401,12 @@ impl VirtioPciTestDevice { DeviceTraits { device_id: VirtioDeviceType::CONSOLE, device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX) + .with_bank( + 0, + TEST_DEVICE_FEATURE_BIT + | VIRTIO_F_RING_INDIRECT_DESC + | VIRTIO_F_RING_EVENT_IDX, + ) .with_bank(1, VIRTIO_F_RING_PACKED), max_queues: num_queues, device_register_length: 12, @@ -1452,7 +1459,12 @@ async fn verify_chipset_config(driver: DefaultDriver) { DeviceTraits { device_id: VirtioDeviceType::CONSOLE, device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX) + .with_bank( + 0, + TEST_DEVICE_FEATURE_BIT + | VIRTIO_F_RING_INDIRECT_DESC + | VIRTIO_F_RING_EVENT_IDX, + ) .with_bank(1, VIRTIO_F_RING_PACKED), max_queues: 1, device_register_length: 0, @@ -1479,7 +1491,7 @@ async fn verify_chipset_config(driver: DefaultDriver) { // device feature (bank 0) assert_eq!( dev.read_u32(16), - VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | 2 + VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT ); // device feature bank index assert_eq!(dev.read_u32(20), 0); @@ -1497,7 +1509,7 @@ async fn verify_chipset_config(driver: DefaultDriver) { dev.write_u32(32, 0xffffffff); assert_eq!( dev.read_u32(32), - VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | 2 + VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT ); // driver feature bank index assert_eq!(dev.read_u32(36), 0); @@ -1603,6 +1615,180 @@ async fn verify_chipset_config(driver: DefaultDriver) { assert_eq!(dev.read_u32(164), 0); } +#[async_test] +async fn verify_transport_features_access_platform_mmio(driver: DefaultDriver) { + let test_mem = VirtioTestMemoryAccess::new(); + let doorbell_registration: Arc = test_mem.clone(); + let mem = GuestMemory::new("test", test_mem); + let interrupt = LineInterrupt::detached(); + let driver_source = VmTaskDriverSource::new(SingleDriverBackend::new(driver)); + + let mut dev = VirtioMmioDevice::new_with_transport_features( + Box::new(TestDevice::new( + &driver_source, + DeviceTraits { + device_id: VirtioDeviceType::CONSOLE, + device_features: VirtioDeviceFeatures::new() + .with_bank( + 0, + TEST_DEVICE_FEATURE_BIT + | VIRTIO_F_RING_INDIRECT_DESC + | VIRTIO_F_RING_EVENT_IDX, + ) + .with_bank(1, VIRTIO_F_RING_PACKED), + max_queues: 1, + device_register_length: 0, + ..Default::default() + }, + None, + )), + &driver_source.simple(), + mem.clone(), + interrupt, + Some(doorbell_registration), + 0, + 1, + VirtioDeviceFeatures::new() + .with_version_1(true) + .with_access_platform(true), + ) + .unwrap(); + + // device feature (bank 1) should include ACCESS_PLATFORM + dev.write_u32(20, 1); + assert_eq!( + dev.read_u32(16), + VIRTIO_F_VERSION_1 | VIRTIO_F_ACCESS_PLATFORM | VIRTIO_F_RING_PACKED + ); +} + +#[async_test] +async fn verify_transport_features_no_access_platform_mmio(driver: DefaultDriver) { + let test_mem = VirtioTestMemoryAccess::new(); + let doorbell_registration: Arc = test_mem.clone(); + let mem = GuestMemory::new("test", test_mem); + let interrupt = LineInterrupt::detached(); + let driver_source = VmTaskDriverSource::new(SingleDriverBackend::new(driver)); + + let mut dev = VirtioMmioDevice::new( + Box::new(TestDevice::new( + &driver_source, + DeviceTraits { + device_id: VirtioDeviceType::CONSOLE, + device_features: VirtioDeviceFeatures::new() + .with_bank( + 0, + TEST_DEVICE_FEATURE_BIT + | VIRTIO_F_RING_INDIRECT_DESC + | VIRTIO_F_RING_EVENT_IDX, + ) + .with_bank(1, VIRTIO_F_RING_PACKED), + max_queues: 1, + device_register_length: 0, + ..Default::default() + }, + None, + )), + &driver_source.simple(), + mem.clone(), + interrupt, + Some(doorbell_registration), + 0, + 1, + ) + .unwrap(); + + // device feature (bank 1) should NOT include ACCESS_PLATFORM + dev.write_u32(20, 1); + assert_eq!(dev.read_u32(16), VIRTIO_F_VERSION_1 | VIRTIO_F_RING_PACKED); +} + +#[async_test] +async fn verify_transport_features_access_platform_pci(driver: DefaultDriver) { + let test_mem = VirtioTestMemoryAccess::new(); + let doorbell_registration: Arc = test_mem.clone(); + let msi_conn = MsiConnection::new(); + let driver_source = VmTaskDriverSource::new(SingleDriverBackend::new(driver)); + + let mut dev = VirtioPciDevice::new_with_transport_features( + Box::new(TestDevice::new( + &driver_source, + DeviceTraits { + device_id: VirtioDeviceType::CONSOLE, + device_features: VirtioDeviceFeatures::new() + .with_bank( + 0, + TEST_DEVICE_FEATURE_BIT + | VIRTIO_F_RING_INDIRECT_DESC + | VIRTIO_F_RING_EVENT_IDX, + ) + .with_bank(1, VIRTIO_F_RING_PACKED), + max_queues: 1, + device_register_length: 12, + ..Default::default() + }, + None, + )), + &driver_source.simple(), + GuestMemory::new("test", test_mem), + PciInterruptModel::Msix(msi_conn.target()), + Some(doorbell_registration), + &mut ExternallyManagedMmioIntercepts, + None, + VirtioDeviceFeatures::new() + .with_version_1(true) + .with_access_platform(true), + ) + .unwrap(); + + // device feature (bank 1) should include ACCESS_PLATFORM + dev.write_u32(0, 1); // select bank 1 + assert_eq!( + dev.read_u32(4), + VIRTIO_F_VERSION_1 | VIRTIO_F_ACCESS_PLATFORM | VIRTIO_F_RING_PACKED + ); +} + +#[async_test] +async fn verify_transport_features_no_access_platform_pci(driver: DefaultDriver) { + let test_mem = VirtioTestMemoryAccess::new(); + let doorbell_registration: Arc = test_mem.clone(); + let msi_conn = MsiConnection::new(); + let driver_source = VmTaskDriverSource::new(SingleDriverBackend::new(driver)); + + let mut dev = VirtioPciDevice::new( + Box::new(TestDevice::new( + &driver_source, + DeviceTraits { + device_id: VirtioDeviceType::CONSOLE, + device_features: VirtioDeviceFeatures::new() + .with_bank( + 0, + TEST_DEVICE_FEATURE_BIT + | VIRTIO_F_RING_INDIRECT_DESC + | VIRTIO_F_RING_EVENT_IDX, + ) + .with_bank(1, VIRTIO_F_RING_PACKED), + max_queues: 1, + device_register_length: 12, + ..Default::default() + }, + None, + )), + &driver_source.simple(), + GuestMemory::new("test", test_mem), + PciInterruptModel::Msix(msi_conn.target()), + Some(doorbell_registration), + &mut ExternallyManagedMmioIntercepts, + None, + ) + .unwrap(); + + // device feature (bank 1) should NOT include ACCESS_PLATFORM + dev.write_u32(0, 1); // select bank 1 + assert_eq!(dev.read_u32(4), VIRTIO_F_VERSION_1 | VIRTIO_F_RING_PACKED); +} + #[async_test] async fn verify_pci_config(driver: DefaultDriver) { let mut pci_test_device = @@ -1786,7 +1972,7 @@ async fn verify_pci_registers(driver: DefaultDriver) { // device feature (bank 0) assert_eq!( pci_test_device.read_u32(bar_address1 + 4), - VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | 2 + VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT ); // device feature (bank 1) pci_test_device.write_u32(bar_address1, 1); @@ -1808,7 +1994,7 @@ async fn verify_pci_registers(driver: DefaultDriver) { pci_test_device.write_u32(bar_address1 + 12, 0xffffffff); assert_eq!( pci_test_device.read_u32(bar_address1 + 12), - VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | 2 + VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT ); // driver feature (bank 1) pci_test_device.write_u32(bar_address1 + 8, 1); @@ -2615,7 +2801,7 @@ async fn verify_device_split_queue_simple(driver: DefaultDriver) { let test_mem = VirtioTestMemoryAccess::new(); let guest = VirtioTestGuest::new_split(&driver, &test_mem, 1, 2, true); let features = VirtioDeviceFeatures::new() - .with_bank(0, VIRTIO_F_RING_EVENT_IDX | 2) + .with_bank(0, VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT) .with_bank(1, VIRTIO_F_VERSION_1); verify_device_queue_simple_inner(test_mem, guest, features).await; } @@ -2624,7 +2810,7 @@ async fn verify_device_packed_queue_simple(driver: DefaultDriver) { let test_mem = VirtioTestMemoryAccess::new(); let guest = VirtioTestGuest::new_packed(&driver, &test_mem, 1, 2, true); let features = VirtioDeviceFeatures::new() - .with_bank(0, VIRTIO_F_RING_EVENT_IDX | 2) + .with_bank(0, VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT) .with_bank(1, VIRTIO_F_VERSION_1 | VIRTIO_F_RING_PACKED); verify_device_queue_simple_inner(test_mem, guest, features).await; } @@ -2716,7 +2902,7 @@ async fn verify_device_split_multi_queue(driver: DefaultDriver) { let test_mem = VirtioTestMemoryAccess::new(); let guest = VirtioTestGuest::new_split(&driver, &test_mem, num_queues, 2, true); let features = VirtioDeviceFeatures::new() - .with_bank(0, VIRTIO_F_RING_EVENT_IDX | 2) + .with_bank(0, VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT) .with_bank(1, VIRTIO_F_VERSION_1); verify_device_multi_queue_inner(test_mem, guest, num_queues, features).await; } @@ -2726,7 +2912,7 @@ async fn verify_device_packed_multi_queue(driver: DefaultDriver) { let test_mem = VirtioTestMemoryAccess::new(); let guest = VirtioTestGuest::new_packed(&driver, &test_mem, num_queues, 2, true); let features = VirtioDeviceFeatures::new() - .with_bank(0, VIRTIO_F_RING_EVENT_IDX | 2) + .with_bank(0, VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT) .with_bank(1, VIRTIO_F_VERSION_1 | VIRTIO_F_RING_PACKED); verify_device_multi_queue_inner(test_mem, guest, num_queues, features).await; } @@ -2796,7 +2982,7 @@ async fn verify_device_split_multi_queue_pci(driver: DefaultDriver) { let test_mem = VirtioTestMemoryAccess::new(); let guest = VirtioTestGuest::new_split(&driver, &test_mem, num_queues, 2, true); let features = VirtioDeviceFeatures::new() - .with_bank(0, VIRTIO_F_RING_EVENT_IDX | 2) + .with_bank(0, VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT) .with_bank(1, VIRTIO_F_VERSION_1); verify_device_multi_queue_pci_inner(test_mem, guest, num_queues, features).await; } @@ -2806,7 +2992,10 @@ async fn verify_device_packed_multi_queue_pci(driver: DefaultDriver) { let test_mem = VirtioTestMemoryAccess::new(); let guest = VirtioTestGuest::new_packed(&driver, &test_mem, num_queues, 2, true); let features = VirtioDeviceFeatures::new() - .with_bank(0, VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | 2) + .with_bank( + 0, + VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX | TEST_DEVICE_FEATURE_BIT, + ) .with_bank(1, VIRTIO_F_VERSION_1 | VIRTIO_F_RING_PACKED); verify_device_multi_queue_pci_inner(test_mem, guest, num_queues, features).await; } @@ -2821,8 +3010,10 @@ async fn verify_enable_failure_mmio_does_not_set_driver_ok(_driver: DefaultDrive Box::new(FailingTestDevice { traits: DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 0, ..Default::default() @@ -2874,8 +3065,10 @@ async fn verify_enable_failure_pci_does_not_set_driver_ok(_driver: DefaultDriver Box::new(FailingTestDevice { traits: DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 12, ..Default::default() @@ -3561,8 +3754,10 @@ impl PartialFailTestDevice { Self { traits: DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues, device_register_length: 0, ..Default::default() @@ -3952,8 +4147,10 @@ async fn pci_intx_line_deasserted_on_reset(driver: DefaultDriver) { &driver_source, DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 12, ..Default::default() @@ -4133,8 +4330,10 @@ async fn mmio_save_restore_round_trip(driver: DefaultDriver) { &driver_source, DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 0, ..Default::default() @@ -4169,8 +4368,10 @@ async fn mmio_save_restore_round_trip(driver: DefaultDriver) { &driver_source, DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 0, ..Default::default() @@ -4211,7 +4412,7 @@ async fn pci_save_restore_incompatible_features(driver: DefaultDriver) { let mut dev = VirtioPciTestDevice::new(&driver, 1, &test_mem, None); // Negotiate features including the device-specific bit (bank 0, bit 1). let mut driver_features = guest.queue_features(); - driver_features.set_bank(0, driver_features.bank(0) | 2); + driver_features.set_bank(0, driver_features.bank(0) | TEST_DEVICE_FEATURE_BIT); guest.setup_pci_device(&mut dev, driver_features).await; dev.pci_device.stop().await; @@ -4383,8 +4584,10 @@ async fn mmio_restore_reinstalls_doorbells(driver: DefaultDriver) { &driver_source, DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 0, ..Default::default() @@ -4421,8 +4624,10 @@ async fn mmio_restore_reinstalls_doorbells(driver: DefaultDriver) { &driver_source, DeviceTraits { device_id: VirtioDeviceType::CONSOLE, - device_features: VirtioDeviceFeatures::new() - .with_bank(0, 2 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX), + device_features: VirtioDeviceFeatures::new().with_bank( + 0, + TEST_DEVICE_FEATURE_BIT | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX, + ), max_queues: 1, device_register_length: 0, ..Default::default() diff --git a/vm/devices/virtio/virtio/src/transport/core.rs b/vm/devices/virtio/virtio/src/transport/core.rs index a208965d1e..894de957bf 100644 --- a/vm/devices/virtio/virtio/src/transport/core.rs +++ b/vm/devices/virtio/virtio/src/transport/core.rs @@ -96,12 +96,15 @@ pub(crate) struct VirtioTransportCore { } impl VirtioTransportCore { - /// Create a new transport core, spawning the device task. - pub fn new( + /// Create a new transport core, merging caller-supplied transport + /// features (e.g. `VIRTIO_F_VERSION_1`, `VIRTIO_F_ACCESS_PLATFORM`) + /// with the device-specific features. + pub(crate) fn new_with_transport_features( device: Box, driver: &impl Spawn, guest_memory: GuestMemory, doorbell_registration: Option>, + transport_features: VirtioDeviceFeatures, ) -> std::io::Result { let traits = device.traits(); let queues: Vec = (0..traits.max_queues) @@ -121,7 +124,13 @@ impl VirtioTransportCore { }) .collect::>>()?; - let device_feature = traits.device_features.with_version_1(true); + // Always enforce VERSION_1 — both PCI-modern and MMIO v2 transports + // require it, and omitting it would be a caller bug. + let transport_features = transport_features.with_version_1(true); + + let device_feature = VirtioDeviceFeatures::from_bits( + traits.device_features.into_bits() | transport_features.into_bits(), + ); let supports_save_restore = device.supports_save_restore(); let (sender, receiver) = mesh::channel(); diff --git a/vm/devices/virtio/virtio/src/transport/mmio.rs b/vm/devices/virtio/virtio/src/transport/mmio.rs index fb05ecec66..1c033631c0 100644 --- a/vm/devices/virtio/virtio/src/transport/mmio.rs +++ b/vm/devices/virtio/virtio/src/transport/mmio.rs @@ -10,6 +10,7 @@ use crate::DynVirtioDevice; use crate::MAX_QUEUE_SIZE; use crate::spec::VIRTIO_MMIO_INTERRUPT_STATUS_CONFIG_CHANGE; use crate::spec::VIRTIO_MMIO_INTERRUPT_STATUS_USED_BUFFER; +use crate::spec::VirtioDeviceFeatures; use crate::spec::mmio::VirtioMmioRegister; use chipset_device::ChipsetDevice; use chipset_device::io::IoResult; @@ -105,6 +106,8 @@ impl fmt::Debug for VirtioMmioDevice { } impl VirtioMmioDevice { + /// Create a new MMIO transport with default transport features + /// (`VIRTIO_F_VERSION_1`). pub fn new( device: Box, driver: &impl Spawn, @@ -113,6 +116,30 @@ impl VirtioMmioDevice { doorbell_registration: Option>, mmio_gpa: u64, mmio_len: u64, + ) -> std::io::Result { + Self::new_with_transport_features( + device, + driver, + guest_memory, + interrupt, + doorbell_registration, + mmio_gpa, + mmio_len, + VirtioDeviceFeatures::new().with_version_1(true), + ) + } + + /// Create a new MMIO transport, merging caller-supplied transport + /// features with the device-specific features. + pub fn new_with_transport_features( + device: Box, + driver: &impl Spawn, + guest_memory: GuestMemory, + interrupt: LineInterrupt, + doorbell_registration: Option>, + mmio_gpa: u64, + mmio_len: u64, + transport_features: VirtioDeviceFeatures, ) -> std::io::Result { let traits = device.traits(); let interrupt_state = Arc::new(Mutex::new(InterruptState { @@ -120,7 +147,13 @@ impl VirtioMmioDevice { status: 0, })); - let core = VirtioTransportCore::new(device, driver, guest_memory, doorbell_registration)?; + let core = VirtioTransportCore::new_with_transport_features( + device, + driver, + guest_memory, + doorbell_registration, + transport_features, + )?; Ok(Self { core, diff --git a/vm/devices/virtio/virtio/src/transport/pci.rs b/vm/devices/virtio/virtio/src/transport/pci.rs index e8f58883b7..36302edc50 100644 --- a/vm/devices/virtio/virtio/src/transport/pci.rs +++ b/vm/devices/virtio/virtio/src/transport/pci.rs @@ -11,6 +11,7 @@ use super::task::defer_config_read; use super::task::defer_config_write; use crate::DynVirtioDevice; use crate::MAX_QUEUE_SIZE; +use crate::spec::VirtioDeviceFeatures; use crate::spec::pci::VIRTIO_PCI_COMMON_CFG_SIZE; use crate::spec::pci::VIRTIO_PCI_DEVICE_ID_BASE; use crate::spec::pci::VIRTIO_VENDOR_ID; @@ -145,7 +146,32 @@ pub struct VirtioPciDevice { } impl VirtioPciDevice { + /// Create a new PCI transport with default transport features + /// (`VIRTIO_F_VERSION_1`). pub fn new( + device: Box, + driver: &impl Spawn, + guest_memory: GuestMemory, + interrupt_model: PciInterruptModel<'_>, + doorbell_registration: Option>, + mmio_registration: &mut dyn RegisterMmioIntercept, + shared_mem_mapper: Option<&dyn MemoryMapper>, + ) -> io::Result { + Self::new_with_transport_features( + device, + driver, + guest_memory, + interrupt_model, + doorbell_registration, + mmio_registration, + shared_mem_mapper, + VirtioDeviceFeatures::new().with_version_1(true), + ) + } + + /// Create a new PCI transport, merging caller-supplied transport + /// features with the device-specific features. + pub fn new_with_transport_features( mut device: Box, driver: &impl Spawn, guest_memory: GuestMemory, @@ -153,6 +179,7 @@ impl VirtioPciDevice { doorbell_registration: Option>, mmio_registration: &mut dyn RegisterMmioIntercept, shared_mem_mapper: Option<&dyn MemoryMapper>, + transport_features: VirtioDeviceFeatures, ) -> io::Result { let traits = device.traits(); @@ -266,7 +293,13 @@ impl VirtioPciDevice { } }; - let core = VirtioTransportCore::new(device, driver, guest_memory, doorbell_registration)?; + let core = VirtioTransportCore::new_with_transport_features( + device, + driver, + guest_memory, + doorbell_registration, + transport_features, + )?; Ok(VirtioPciDevice { core,