summary refs log tree commit diff
path: root/devices/src/vfio.rs
diff options
context:
space:
mode:
authorXiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>2019-06-21 13:56:52 +0800
committerCommit Bot <commit-bot@chromium.org>2020-01-07 05:58:46 +0000
commit5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9 (patch)
tree5d2c9d33ecdc894337359e15b18a244d4d7056d6 /devices/src/vfio.rs
parentf2eecc4152eca8d395566cffa2c102ec090a152d (diff)
downloadcrosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.tar
crosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.tar.gz
crosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.tar.bz2
crosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.tar.lz
crosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.tar.xz
crosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.tar.zst
crosvm-5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9.zip
Vfio: Add igd Opregion support
igd opregion is used by igd driver to get vbt info and exhange info
between bios and driver, but it isn't a standard pci resource, host
bios allocate, reserve its memory, and report the memory base address
through cfg_register 0xFC on native.

As crosvm doesn't have bios, it is hard to allocate and reserve opregion
for guest. Here opregion is faked as mmio memory, and let crosvm
allocate guest memory from mmio space, report its base to cfg_register
0xFC also.

guest driver read cfg_register 0xFC to get opregion base address, then rw
it throgh this address. Read is forwarded to vfio kernel and write is
ignored.

BUG=chromium:992270
TEST=crosvm --vfio /sys/devices/pci0000:00/0000:00:02.0, pass through
host igd into linux guest, the physical local display lightup and show linux desktop.

Change-Id: I1cc3618e99313fc1f88b96dcbc635f090b19340c
Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1688689
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/vfio.rs')
-rw-r--r--devices/src/vfio.rs36
1 files changed, 36 insertions, 0 deletions
diff --git a/devices/src/vfio.rs b/devices/src/vfio.rs
index f8c15c8..791dc78 100644
--- a/devices/src/vfio.rs
+++ b/devices/src/vfio.rs
@@ -289,6 +289,8 @@ struct VfioRegion {
     offset: u64,
     // vectors for mmap offset and size
     mmaps: Vec<vfio_region_sparse_mmap_area>,
+    // type and subtype for cap type
+    cap_info: Option<(u32, u32)>,
 }
 
 /// Vfio device for exposing regions which could be read/write to kernel vfio device.
@@ -497,6 +499,7 @@ impl VfioDevice {
             }
 
             let mut mmaps: Vec<vfio_region_sparse_mmap_area> = Vec::new();
+            let mut cap_info: Option<(u32, u32)> = None;
             if reg_info.argsz > argsz {
                 let cap_len: usize = (reg_info.argsz - argsz) as usize;
                 let mut region_with_cap =
@@ -527,6 +530,7 @@ impl VfioDevice {
                 let cap_header_sz = mem::size_of::<vfio_info_cap_header>() as u32;
                 let mmap_cap_sz = mem::size_of::<vfio_region_info_cap_sparse_mmap>() as u32;
                 let mmap_area_sz = mem::size_of::<vfio_region_sparse_mmap_area>() as u32;
+                let type_cap_sz = mem::size_of::<vfio_region_info_cap_type>() as u32;
                 let region_info_sz = reg_info.argsz;
 
                 // region_with_cap[0].cap_info may contain many structures, like
@@ -567,6 +571,17 @@ impl VfioDevice {
                         for area in areas.iter() {
                             mmaps.push(area.clone());
                         }
+                    } else if cap_header.id as u32 == VFIO_REGION_INFO_CAP_TYPE {
+                        if offset + type_cap_sz > region_info_sz {
+                            break;
+                        }
+                        // cap_ptr is vfio_region_info_cap_type here
+                        // Safe, this vfio_region_info_cap_type is in this function allocated
+                        // region_with_cap vec
+                        let cap_type_info =
+                            unsafe { &*(cap_ptr as *mut u8 as *const vfio_region_info_cap_type) };
+
+                        cap_info = Some((cap_type_info.type_, cap_type_info.subtype));
                     }
 
                     offset = cap_header.next;
@@ -583,6 +598,7 @@ impl VfioDevice {
                 size: reg_info.size,
                 offset: reg_info.offset,
                 mmaps,
+                cap_info,
             };
             regions.push(region);
         }
@@ -629,6 +645,26 @@ impl VfioDevice {
         }
     }
 
+    /// find the specified cap type in device regions
+    /// Input:
+    ///      type_:  cap type
+    ///      sub_type: cap sub_type
+    /// Output:
+    ///     None: device doesn't have the specified cap type
+    ///     Some((bar_index, region_size)): device has the specified cap type, return region's
+    ///                                     index and size
+    pub fn get_cap_type_info(&self, type_: u32, sub_type: u32) -> Option<(u32, u64)> {
+        for (index, region) in self.regions.iter().enumerate() {
+            if let Some(cap_info) = &region.cap_info {
+                if cap_info.0 == type_ && cap_info.1 == sub_type {
+                    return Some((index as u32, region.size));
+                }
+            }
+        }
+
+        None
+    }
+
     /// Read region's data from VFIO device into buf
     /// index: region num
     /// buf: data destination and buf length is read size