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:
Victor Ding 2022-01-20 15:42:16 +00:00 committed by crosvm LUCI
parent 476b7f89bd
commit eb6ac34ede
5 changed files with 68 additions and 4 deletions

View file

@ -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
),

View file

@ -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.

View file

@ -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

View file

@ -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,

View file

@ -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>,
}