From 5c6bf3e32ded73afae857b10d5ddd6ca1cfaceb9 Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Fri, 21 Jun 2019 13:56:52 +0800 Subject: 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 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1688689 Tested-by: kokoro Reviewed-by: Daniel Verkamp --- devices/src/vfio.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'devices/src/vfio.rs') 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, + // 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 = 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::() as u32; let mmap_cap_sz = mem::size_of::() as u32; let mmap_area_sz = mem::size_of::() as u32; + let type_cap_sz = mem::size_of::() 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) = ®ion.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 -- cgit 1.4.1