From d448be0d0da134be506a7a4b7c27476f9e2d1218 Mon Sep 17 00:00:00 2001 From: Keiichi Watanabe Date: Wed, 20 Oct 2021 22:52:25 +0900 Subject: [PATCH] devices: vfio: Add methods to read/write region at specified address Add utility methods to read/write VFIO memory region BUG=b:194137301 TEST=build Change-Id: Ia1054bb74bed791451e7bb8c87c2eb9b84353a2d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3149873 Reviewed-by: Chirantan Ekbote Tested-by: kokoro Commit-Queue: Keiichi Watanabe --- devices/src/vfio.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/devices/src/vfio.rs b/devices/src/vfio.rs index 0c52bb550c..8794eb60d9 100644 --- a/devices/src/vfio.rs +++ b/devices/src/vfio.rs @@ -11,6 +11,7 @@ use std::mem; use std::os::raw::c_ulong; use std::os::unix::prelude::FileExt; use std::path::{Path, PathBuf}; +use std::slice; use std::sync::Arc; use std::u32; @@ -44,6 +45,8 @@ pub enum VfioError { GroupSetContainer(Error), #[error("group is inviable")] GroupViable, + #[error("invalid region index: {0}")] + InvalidIndex(u32), #[error("invalid file path")] InvalidPath, #[error("failed to add guest memory map into iommu table: {0}")] @@ -544,7 +547,17 @@ pub struct VfioIrq { pub index: u32, } -struct VfioRegion { +/// Address on VFIO memory region. +#[derive(Debug, Default, Clone)] +pub struct VfioRegionAddr { + /// region number. + pub index: u32, + /// offset in the region. + pub addr: u64, +} + +#[derive(Debug)] +pub struct VfioRegion { // flags for this region: read/write/mmap flags: u32, size: u64, @@ -1059,6 +1072,16 @@ impl VfioDevice { None } + /// Returns file offset corresponding to the given `VfioRegionAddr`. + /// The offset can be used when reading/writing the VFIO device's FD directly. + pub fn get_offset_for_addr(&self, addr: &VfioRegionAddr) -> Result { + let region = self + .regions + .get(addr.index as usize) + .ok_or(VfioError::InvalidIndex(addr.index))?; + Ok(region.offset + addr.addr) + } + /// Read region's data from VFIO device into buf /// index: region num /// buf: data destination and buf length is read size @@ -1087,6 +1110,18 @@ impl VfioDevice { }); } + /// Reads a value from the specified `VfioRegionAddr.addr` + `offset`. + pub fn region_read_from_addr(&self, addr: &VfioRegionAddr, offset: u64) -> T { + let mut val = mem::MaybeUninit::zeroed(); + // Safe because we have zero-initialized `size_of::()` bytes. + let buf = + unsafe { slice::from_raw_parts_mut(val.as_mut_ptr() as *mut u8, mem::size_of::()) }; + self.region_read(addr.index, buf, addr.addr + offset); + // Safe because any bit pattern is valid for a type that implements + // DataInit. + unsafe { val.assume_init() } + } + /// write the data from buf into a vfio device region /// index: region num /// buf: data src and buf length is write size @@ -1118,6 +1153,11 @@ impl VfioDevice { }); } + /// Writes data into the specified `VfioRegionAddr.addr` + `offset`. + pub fn region_write_to_addr(&self, val: &T, addr: &VfioRegionAddr, offset: u64) { + self.region_write(addr.index, val.as_slice(), addr.addr + offset); + } + /// get vfio device's descriptors which are passed into minijail process pub fn keep_rds(&self) -> Vec { vec![