summary refs log tree commit diff
path: root/devices/src/pci/vfio_pci.rs
diff options
context:
space:
mode:
authorXiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>2019-06-06 10:04:03 +0800
committerCommit Bot <commit-bot@chromium.org>2019-12-17 10:25:05 +0000
commit5aef6474862a94c85ac90757fe8ba7376a3ed1d6 (patch)
tree21858b0dfb8d0a76da1630d35e9b37e2805d5ba1 /devices/src/pci/vfio_pci.rs
parent0f4c5fff7a9a4283572b23d5ad9c9af6c125bb15 (diff)
downloadcrosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.tar
crosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.tar.gz
crosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.tar.bz2
crosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.tar.lz
crosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.tar.xz
crosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.tar.zst
crosvm-5aef6474862a94c85ac90757fe8ba7376a3ed1d6.zip
vfio: Disable igd stolen memory
igd stolen memory isn't a standard pci resource, so guest couldn't
access it. Once guest i915 driver see its size is zero, i915 won't use
it. Here sotlen memory's size register PciCfg 0x51 is forced to zero.

BUG=chromium:992270
TEST=crosvm run --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: I1a0a6edda5d92d32307ea8025ef96677ca62c125
Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1688368
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/pci/vfio_pci.rs')
-rw-r--r--devices/src/pci/vfio_pci.rs53
1 files changed, 49 insertions, 4 deletions
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index 07c7b60..f0cebde 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -18,10 +18,16 @@ use vm_control::{
 };
 
 use crate::pci::pci_device::{Error as PciDeviceError, PciDevice};
-use crate::pci::PciInterruptPin;
+use crate::pci::{PciClassCode, PciInterruptPin};
 
 use crate::vfio::{VfioDevice, VfioIrqType};
 
+const PCI_VENDOR_ID: u32 = 0x0;
+const INTEL_VENDOR_ID: u16 = 0x8086;
+const PCI_COMMAND: u32 = 0x4;
+const PCI_COMMAND_MEMORY: u8 = 0x2;
+const PCI_BASE_CLASS_CODE: u32 = 0x0B;
+
 const PCI_INTERRUPT_PIN: u32 = 0x3D;
 
 struct VfioPciConfig {
@@ -298,6 +304,10 @@ struct IoInfo {
     bar_index: u32,
 }
 
+enum DeviceData {
+    IntelGfxData,
+}
+
 /// Implements the Vfio Pci device, then a pci device is added into vm
 pub struct VfioPciDevice {
     device: Arc<VfioDevice>,
@@ -310,6 +320,7 @@ pub struct VfioPciDevice {
     msi_cap: Option<VfioMsiCap>,
     irq_type: Option<VfioIrqType>,
     vm_socket_mem: VmMemoryControlRequestSocket,
+    device_data: Option<DeviceData>,
 
     // scratch MemoryMapping to avoid unmap beform vm exit
     mem: Vec<MemoryMapping>,
@@ -326,6 +337,17 @@ impl VfioPciDevice {
         let config = VfioPciConfig::new(Arc::clone(&dev));
         let msi_cap = VfioMsiCap::new(&config, vfio_device_socket_irq);
 
+        let vendor_id = config.read_config_word(PCI_VENDOR_ID);
+        let class_code = config.read_config_byte(PCI_BASE_CLASS_CODE);
+
+        let is_intel_gfx = vendor_id == INTEL_VENDOR_ID
+            && class_code == PciClassCode::DisplayController.get_register_value();
+        let device_data = if is_intel_gfx {
+            Some(DeviceData::IntelGfxData)
+        } else {
+            None
+        };
+
         VfioPciDevice {
             device: dev,
             config,
@@ -337,10 +359,23 @@ impl VfioPciDevice {
             msi_cap,
             irq_type: None,
             vm_socket_mem: vfio_device_socket_mem,
+            device_data,
             mem: Vec::new(),
         }
     }
 
+    fn is_intel_gfx(&self) -> bool {
+        let mut ret = false;
+
+        if let Some(device_data) = &self.device_data {
+            match *device_data {
+                DeviceData::IntelGfxData => ret = true,
+            }
+        }
+
+        ret
+    }
+
     fn find_region(&self, addr: u64) -> Option<MmioInfo> {
         for mmio_info in self.mmio_regions.iter() {
             if addr >= mmio_info.start && addr < mmio_info.start + mmio_info.length {
@@ -510,9 +545,6 @@ impl VfioPciDevice {
     }
 }
 
-const PCI_COMMAND: u8 = 0x4;
-const PCI_COMMAND_MEMORY: u8 = 0x2;
-
 impl PciDevice for VfioPciDevice {
     fn debug_label(&self) -> String {
         "vfio pci device".to_string()
@@ -641,6 +673,14 @@ impl PciDevice for VfioPciDevice {
             );
         }
 
+        // Quirk, enable igd memory for guest vga arbitrate, otherwise kernel vga arbitrate
+        // driver doesn't claim this vga device, then xorg couldn't boot up.
+        if self.is_intel_gfx() {
+            let mut cmd = self.config.read_config_byte(PCI_COMMAND);
+            cmd |= PCI_COMMAND_MEMORY;
+            self.config.write_config_byte(cmd, PCI_COMMAND);
+        }
+
         Ok(ranges)
     }
 
@@ -673,6 +713,11 @@ impl PciDevice for VfioPciDevice {
             }
         }
 
+        // Quirk for intel graphic, set stolen memory size to 0 in pci_cfg[0x51]
+        if self.is_intel_gfx() && reg == 0x50 {
+            config &= 0xffff00ff;
+        }
+
         config
     }