vfio_pci: add support for ACPI _DSM forwarding
Allow devices to host's ACPI _DSM via the recently proposed VFIO_DEVICE_ACPI_DSM IOCTL Co-authored-by: Xiong Zhang <xiong.y.zhang@intel.corp-partner.google.com> BUG=b:194391459, b:289878032 TEST=host's ACPI _DSM method can be triggered from guest Change-Id: I8de8cfbc85cdf6f9f15e53d4c5a4d4a3aa564ebd Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3822005 Reviewed-by: Grzegorz Jaszczyk <jaszczyk@google.com> Commit-Queue: Grzegorz Jaszczyk <jaszczyk@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
476b7f89bd
commit
eb6ac34ede
5 changed files with 68 additions and 4 deletions
|
|
@ -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::<u32>(reg_idx * std::mem::size_of::<u32>())
|
||||
.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
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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<u8>) -> Result<Vec<u8>> {
|
||||
let count = args.len();
|
||||
let mut dsm = vec_with_array_field::<vfio_acpi_dsm, u8>(count);
|
||||
dsm[0].argsz = (mem::size_of::<vfio_acpi_dsm>() + count * mem::size_of::<u8>()) 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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<u8>,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue