diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs index cbc4c3792..b5fde2444 100644 --- a/devices/src/pci/vfio_pci.rs +++ b/devices/src/pci/vfio_pci.rs @@ -2085,12 +2085,24 @@ impl PciDevice for VfioPciDevice { } fn read_virtual_config_register(&self, reg_idx: usize) -> u32 { + // HACK TODO: + // The results should be passed via shared memory (see `write_virtual_config_register`); + // HOWEVER, for not-yet-known reasons, Guest is unable to see the changes immediately + // even after `msync`. While the investigation is still ongoing, let's use this hack + // temporarily to unblock integration tests. + if reg_idx < 1024 { + if let Some(shm) = &self.vcfg_shm_mmap { + return shm + .read_obj::(reg_idx * std::mem::size_of::()) + .expect("failed to read vcfg."); + } + } warn!( - "{} read unsupported register {}", + "{} read unsupported vcfg register {}", self.debug_label(), reg_idx ); - 0 + 0xFFFF_FFFF } fn write_virtual_config_register(&mut self, reg_idx: usize, value: u32) { @@ -2113,8 +2125,22 @@ impl PciDevice for VfioPciDevice { } }; } + 1 => { + if let Some(shm) = &self.vcfg_shm_mmap { + let mut args = [0u8; 4096]; + shm.read_slice(&mut args, 0) + .expect("failed to read DSM Args."); + let res = self + .device + .acpi_dsm(args.to_vec()) + .expect("failed to call DSM."); + shm.write_slice(&res, 0) + .expect("failed to write DSM result."); + shm.msync().expect("failed to msync."); + } + } _ => warn!( - "{} write unsupported register {}", + "{} write unsupported vcfg register {}", self.debug_label(), reg_idx ), diff --git a/devices/src/vfio.rs b/devices/src/vfio.rs index 96f605bd5..809baf229 100644 --- a/devices/src/vfio.rs +++ b/devices/src/vfio.rs @@ -43,6 +43,7 @@ use resources::Alloc; use resources::Error as ResourcesError; use sync::Mutex; use thiserror::Error; +use vfio_sys::vfio::vfio_acpi_dsm; use vfio_sys::*; use vm_memory::MemoryRegionInformation; use zerocopy::AsBytes; @@ -93,6 +94,8 @@ pub enum VfioError { Resources(ResourcesError), #[error("unknown vfio device type (flags: {0:#x})")] UnknownDeviceType(u32), + #[error("failed to call vfio device's ACPI _DSM: {0}")] + VfioAcpiDsm(Error), #[error( "vfio API version doesn't match with VFIO_API_VERSION defined in vfio_sys/src/vfio.rs" )] @@ -947,6 +950,27 @@ impl VfioDevice { } } + /// call _DSM from the device's ACPI table + pub fn acpi_dsm(&self, args: Vec) -> Result> { + let count = args.len(); + let mut dsm = vec_with_array_field::(count); + dsm[0].argsz = (mem::size_of::() + count * mem::size_of::()) as u32; + dsm[0].padding = 0; + // Safe as we allocated enough space to hold args + unsafe { + dsm[0].args.as_mut_slice(count).clone_from_slice(&args); + } + // Safe as we are the owner of self and dsm which are valid value + let ret = unsafe { ioctl_with_mut_ref(&self.dev, VFIO_DEVICE_ACPI_DSM(), &mut dsm[0]) }; + if ret < 0 { + Err(VfioError::VfioAcpiDsm(get_error())) + } else { + // Safe as we allocated enough space to hold args + let res = unsafe { dsm[0].args.as_slice(count) }; + Ok(res.to_vec()) + } + } + /// Enable vfio device's irq and associate Irqfd Event with device. /// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to subindex + /// descriptors length will be assigned with irqfd in the descriptors array. diff --git a/jail/seccomp/x86_64/vfio_device.policy b/jail/seccomp/x86_64/vfio_device.policy index 4484e1587..deaadbcfc 100644 --- a/jail/seccomp/x86_64/vfio_device.policy +++ b/jail/seccomp/x86_64/vfio_device.policy @@ -8,7 +8,13 @@ # 0x3B71: VFIO_IOMMU_MAP_DMA # 0x3B72: VFIO_IOMMU_UNMAP_DMA # 0x3B75: VFIO_DEVICE_FEATURE -ioctl: arg1 == 0x3B6E || arg1 == 0x3B71 || arg1 == 0x3B72 || arg1 == 0x3B75 +# 0x3B76: VFIO_DEVICE_ACPI_DSM +ioctl: arg1 == 0x3B6E || \ + arg1 == 0x3B71 || \ + arg1 == 0x3B72 || \ + arg1 == 0x3B75 || \ + arg1 == 0x3B76 +msync: 1 open: return ENOENT openat: return ENOENT pread64: 1 diff --git a/vfio_sys/src/lib.rs b/vfio_sys/src/lib.rs index 99d098a8e..2097eff64 100644 --- a/vfio_sys/src/lib.rs +++ b/vfio_sys/src/lib.rs @@ -101,6 +101,7 @@ ioctl_io_nr!(VFIO_IOMMU_UNMAP_DMA, VFIO_TYPE, VFIO_BASE + 14); ioctl_io_nr!(VFIO_IOMMU_ENABLE, VFIO_TYPE, VFIO_BASE + 15); ioctl_io_nr!(VFIO_IOMMU_DISABLE, VFIO_TYPE, VFIO_BASE + 16); ioctl_io_nr!(VFIO_DEVICE_FEATURE, VFIO_TYPE, VFIO_BASE + 17); +ioctl_io_nr!(VFIO_DEVICE_ACPI_DSM, VFIO_TYPE, VFIO_BASE + 18); ioctl_io_nr!( PLAT_IRQ_FORWARD_SET, diff --git a/vfio_sys/src/vfio.rs b/vfio_sys/src/vfio.rs index 968fb5bc8..9ab172e2d 100644 --- a/vfio_sys/src/vfio.rs +++ b/vfio_sys/src/vfio.rs @@ -613,3 +613,10 @@ pub struct vfio_iommu_spapr_tce_remove { pub flags: u32, pub start_addr: u64, } +#[repr(C)] +#[derive(Debug, Default)] +pub struct vfio_acpi_dsm { + pub argsz: u32, + pub padding: u32, + pub args: __IncompleteArrayField, +}