From d97079d793e9a761f1df56fdbf17009bc51b3848 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Mon, 5 Aug 2019 16:26:21 -0700 Subject: [PATCH] vm-virtio: Update VirtioPciCap and introduce VirtioPciCap64 Based on the latest version of the virtio specification, the structure virtio_pci_cap has been updated and a new structure virtio_pci_cap64 has been introduced. virtio_pci_cap now includes a field "id" that does not modify the existing structure size since there was a 3 bytes reserved field already there. The id is used in the context of shared memory regions which need to be identified since there could be more than one of this kind of capability. virtio_pci_cap64 is a new structure that includes virtio_pci_cap and extends it to allow 64 bits offsets and 64 bits region length. This is used in the context of shared memory regions capability, as we might need to describe regions of 4G or more, that could be placed at a 4G offset or more in the associated BAR. Signed-off-by: Sebastien Boeuf --- vm-virtio/src/transport/pci_device.rs | 60 +++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/vm-virtio/src/transport/pci_device.rs b/vm-virtio/src/transport/pci_device.rs index 3c717a176..fca7dbfe1 100755 --- a/vm-virtio/src/transport/pci_device.rs +++ b/vm-virtio/src/transport/pci_device.rs @@ -42,6 +42,7 @@ enum PciCapabilityType { IsrConfig = 3, DeviceConfig = 4, PciConfig = 5, + SharedMemoryConfig = 8, } #[allow(dead_code)] @@ -51,7 +52,8 @@ struct VirtioPciCap { cap_len: u8, // Generic PCI field: capability length cfg_type: u8, // Identifies the structure. pci_bar: u8, // Where to find it. - padding: [u8; 3], // Pad to full dword. + id: u8, // Multiple capabilities of the same type + padding: [u8; 2], // Pad to full dword. offset: Le32, // Offset within bar. length: Le32, // Length of the structure, in bytes. } @@ -76,7 +78,8 @@ impl VirtioPciCap { cap_len: (std::mem::size_of::() as u8) + VIRTIO_PCI_CAP_LEN_OFFSET, cfg_type: cfg_type as u8, pci_bar, - padding: [0; 3], + id: 0, + padding: [0; 2], offset: Le32::from(offset), length: Le32::from(length), } @@ -117,7 +120,8 @@ impl VirtioPciNotifyCap { + VIRTIO_PCI_CAP_LEN_OFFSET, cfg_type: cfg_type as u8, pci_bar, - padding: [0; 3], + id: 0, + padding: [0; 2], offset: Le32::from(offset), length: Le32::from(length), }, @@ -126,6 +130,45 @@ impl VirtioPciNotifyCap { } } +#[allow(dead_code)] +#[repr(packed)] +#[derive(Clone, Copy, Default)] +struct VirtioPciCap64 { + cap: VirtioPciCap, + offset_hi: Le32, + length_hi: Le32, +} +// It is safe to implement ByteValued. All members are simple numbers and any value is valid. +unsafe impl ByteValued for VirtioPciCap64 {} + +impl PciCapability for VirtioPciCap64 { + fn bytes(&self) -> &[u8] { + self.as_slice() + } + + fn id(&self) -> PciCapabilityID { + PciCapabilityID::VendorSpecific + } +} + +impl VirtioPciCap64 { + pub fn new(cfg_type: PciCapabilityType, pci_bar: u8, id: u8, offset: u64, length: u64) -> Self { + VirtioPciCap64 { + cap: VirtioPciCap { + cap_len: (std::mem::size_of::() as u8) + VIRTIO_PCI_CAP_LEN_OFFSET, + cfg_type: cfg_type as u8, + pci_bar, + id, + padding: [0; 2], + offset: Le32::from(offset as u32), + length: Le32::from(length as u32), + }, + offset_hi: Le32::from((offset >> 32) as u32), + length_hi: Le32::from((length >> 32) as u32), + } + } +} + #[allow(dead_code)] #[derive(Copy, Clone)] pub enum PciVirtioSubclass { @@ -351,6 +394,17 @@ impl VirtioPciDevice { .add_capability(&configuration_cap) .map_err(PciDeviceError::CapabilitiesSetup)?; + let shm_cap = VirtioPciCap64::new( + PciCapabilityType::SharedMemoryConfig, + settings_bar, + 0, + 0u64, + 0u64, + ); + self.configuration + .add_capability(&shm_cap) + .map_err(PciDeviceError::CapabilitiesSetup)?; + if self.msix_config.is_some() { let msix_cap = MsixCap::new( settings_bar,