Package: qemu-system-x86
Version: 6.0+dfsg-1~exp0 and 5.2+dfsg-10
Severity: normal
Tags: patch upstream

Dear Maintainer,

I find that when using qemu with a Windows Xen HVM DomU and also passing 
through the Intel integrated graphics device (IGD) to the Windows Xen HVM DomU, 
it is much more reliable if the Intel IGD is at PCI slot 2 in the HVM DomU. 
When using the ancient qemu-xen-traditional device model provided by the Xen 
project, the Intel IGD always grabs slot 2 when it is passed through to the Xen 
HVM DomU using the gfx_passthru option in xl.cfg, but not when using what the 
Xen project refers to as the upstream qemu device model, which is the device 
model provided by the qemu-system-x86 package. Intel says the IGD device needs 
to be at PCI slot 2 and but it will be at a different slot when using the qemu 
version provided by the qemu-system-x86 package.

One problem that occurs is that Windows sometimes reports code 43 errors in the 
Windows Device Manager when the Intel IGD is not set to PCI slot 2, and this 
prevents IGD passthrough from working because the Windows code 43 error causes 
Windows to disable the affected device. Other times, the screen is a little 
fuzzy at first but it usually clears up later.

I investigated and found out how the ancient qemu-xen-traditional model ensures 
the IGD grabs PCI slot 2, it is by patching the hw/pci/pci.c file, but the 
patch in qemu-xen-traditional is not appropriate for this version of qemu 
because unlike qemu-xen-traditional, this version is designed to support more 
configuratons than with Xen.

I was able to develop a patch that causes the Intel IGD to grab slot 2 with 
these versions of qemu when qemu is running with xen as the accelerator and 
when using the xenlight (xl/libxl) toolstack to build the Xen HVM. The patch is 
designed to only affect Xen HVMs with IGD passthrough, that is, when using the 
xenlight toolstack and setting gfx_passthru to '1' or 'igd' in the Xen HVM 
DomU's xl.cfg file.

The following patch is for the 6.0+dfsg-1~exp0 package, but it also applies to 
the 5.2+dfsg-10 package also with some fuzz. I used it as the last patch in the 
series of patches in debian/patches, and it works well. It uses CONFIG_DEVICES 
to only compile on platforms with CONFIG_XEN_IGD_PASSTHROUGH set by the meson 
build system, and it also checks and only applies at runtime if the 
gfx_passthru option is set, and all the patch is in the xen part of the qemu 
code.

-------------Start of Patch--------------------------------

--- a/hw/i386/xen/xen-hvm.c     2021-04-29 13:18:58.000000000 -0400
+++ b/hw/i386/xen/xen-hvm.c     2021-06-18 09:44:58.000000000 -0400
@@ -9,6 +9,7 @@
  */
 
 #include "qemu/osdep.h"
+#include CONFIG_DEVICES
 #include "qemu/units.h"
 
 #include "cpu.h"
@@ -38,6 +39,11 @@
 #include <xen/hvm/ioreq.h>
 #include <xen/hvm/e820.h>
 
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+#include "hw/pci/pci_bus.h"
+#include "hw/xen/xen_pt.h"
+#endif
+
 //#define DEBUG_XEN_HVM
 
 #ifdef DEBUG_XEN_HVM
@@ -1530,6 +1536,21 @@
     exit(1);
 }
 
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+/* Reserve pci slot 2 for the Intel IGD */
+void xen_hvm_reserve_igd_slot(PCIBus *pci_bus)
+{
+    DPRINTF("Checking if igd-passthrough is set...\n");
+    if (xen_igd_gfx_pt_enabled()) {
+        DPRINTF("Reserving PCI slot 0x02 for IGD...\n");
+        pci_bus->slot_reserved_mask = XEN_IGD_PCI_SLOT;
+    }
+    else {
+        DPRINTF("IGD passthrough is not set\n");
+    }
+}
+#endif
+
 void destroy_hvm_domain(bool reboot)
 {
     xc_interface *xc_handle;
--- a/hw/i386/pc_piix.c 2021-06-18 09:39:56.000000000 -0400
+++ b/hw/i386/pc_piix.c 2021-06-18 09:49:15.000000000 -0400
@@ -208,6 +208,13 @@
                               pci_memory, ram_memory);
         pcms->bus = pci_bus;
 
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+        /* This function checks if igd-passthru is enabled and 
+         * if so, reserve slot 2 for it on the PCI Bus */
+        if (xen_enabled()) {
+            xen_hvm_reserve_igd_slot(pci_bus);
+        }
+#endif
         piix3 = piix3_create(pci_bus, &isa_bus);
         piix3->pic = x86ms->gsi;
         piix3_devfn = piix3->dev.devfn;
--- a/include/hw/xen/xen-x86.h  2021-04-29 13:18:58.000000000 -0400
+++ b/include/hw/xen/xen-x86.h  2021-06-18 09:54:05.000000000 -0400
@@ -12,4 +12,8 @@
 
 void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory);
 
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+void xen_hvm_reserve_igd_slot(PCIBus *pci_bus);
+#endif
+
 #endif /* QEMU_HW_XEN_X86_H */
--- a/hw/xen/xen_pt.c   2021-04-29 13:18:58.000000000 -0400
+++ b/hw/xen/xen_pt.c   2021-06-18 10:07:42.000000000 -0400
@@ -53,6 +53,7 @@
  */
 
 #include "qemu/osdep.h"
+#include CONFIG_DEVICES
 #include "qapi/error.h"
 #include <sys/ioctl.h>
 
@@ -65,6 +66,10 @@
 #include "xen_pt.h"
 #include "qemu/range.h"
 #include "exec/address-spaces.h"
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+#include "hw/pci/pci_bus.h"
+static void xen_pt_clear_igd_slot(DeviceState *qdev, Error **errp);
+#endif
 
 static bool has_igd_gfx_passthru;
 
@@ -961,11 +966,47 @@
     PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
 }
 
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+#define XEN_PT_DEVICE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(XenPTDeviceClass, klass, TYPE_XEN_PT_DEVICE)
+#define XEN_PT_DEVICE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(XenPTDeviceClass, obj, TYPE_XEN_PT_DEVICE)
+
+typedef void (*XenPTQdevRealize)(DeviceState *qdev, Error **errp);
+
+typedef struct XenPTDeviceClass {
+    PCIDeviceClass parent_class;
+    XenPTQdevRealize pci_qdev_realize;
+} XenPTDeviceClass;
+
+static void xen_pt_clear_igd_slot(DeviceState *qdev, Error **errp)
+{
+    PCIDevice *pci_dev = (PCIDevice *)qdev;
+    XenPCIPassthroughState *s = XEN_PT_DEVICE(pci_dev);
+    XenPTDeviceClass *xptc = XEN_PT_DEVICE_GET_CLASS(s);
+    PCIBus *bus = pci_get_bus(pci_dev);
+
+    /* If this is the Intel IGD, clear the bit that reserves slot 2 */
+    if (has_igd_gfx_passthru && s && (s->hostaddr.slot == 0x2)
+        && (s->hostaddr.function == 0)) {
+        bus->slot_reserved_mask &= ~XEN_IGD_PCI_SLOT;
+        XEN_PT_LOG(pci_dev, "Intel IGD found, slot_reserved_mask = 0x%x\n",
+                   bus->slot_reserved_mask);
+    }
+    xptc->pci_qdev_realize(qdev, errp);
+}
+#endif
+
 static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+    XenPTDeviceClass *xptc = XEN_PT_DEVICE_CLASS(klass);
+    xptc->pci_qdev_realize = dc->realize;
+    dc->realize = xen_pt_clear_igd_slot;
+#endif
     k->realize = xen_pt_realize;
     k->exit = xen_pt_unregister_device;
     k->config_read = xen_pt_pci_read_config;
@@ -988,6 +1029,9 @@
     .instance_size = sizeof(XenPCIPassthroughState),
     .instance_finalize = xen_pci_passthrough_finalize,
     .class_init = xen_pci_passthrough_class_init,
+#ifdef CONFIG_XEN_IGD_PASSTHROUGH
+    .class_size = sizeof(XenPTDeviceClass),
+#endif
     .instance_init = xen_pci_passthrough_instance_init,
     .interfaces = (InterfaceInfo[]) {
         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
--- a/hw/xen/xen_pt.h   2021-04-29 13:18:58.000000000 -0400
+++ b/hw/xen/xen_pt.h   2021-06-18 10:13:08.000000000 -0400
@@ -33,7 +33,7 @@
 
 /* Helper */
 #define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
-
+#define XEN_IGD_PCI_SLOT 0x00000004UL /* slot_reserved_mask for Intel IGD */
 typedef const struct XenPTRegInfo XenPTRegInfo;
 typedef struct XenPTReg XenPTReg;
------------END of Patch--------------------------------


-- System Information:
Debian Release: 11.0
  APT prefers testing-security
  APT policy: (500, 'testing-security'), (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 5.10.0-7-amd64 (SMP w/4 CPU threads)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages qemu-system-x86 depends on:
pn  ipxe-qemu             <none>
ii  libaio1               0.3.112-9
ii  libasound2            1.2.4-1.1
ii  libbrlapi0.8          6.3+dfsg-1
ii  libc6                 2.31-12
ii  libcacard0            1:2.8.0-3
ii  libcapstone4          4.0.2-3
ii  libepoxy0             1.5.5-1
ii  libfdt1               1.6.0-1
ii  libgbm1               20.3.4-1
ii  libgcc-s1             10.2.1-6
ii  libglib2.0-0          2.66.8-1
ii  libgnutls30           3.7.1-3
ii  libibverbs1           33.2-1
ii  libjpeg62-turbo       1:2.0.6-4
ii  libncursesw6          6.2+20201114-2
ii  libnettle8            3.7.3-1
ii  libnuma1              2.0.12-1+b1
ii  libpixman-1-0         0.40.0-1
ii  libpmem1              1.10-1
ii  libpng16-16           1.6.37-3
ii  librdmacm1            33.2-1
ii  libsasl2-2            2.1.27+dfsg-2.1
ii  libseccomp2           2.5.1-1
ii  libslirp0             4.4.0-1
ii  libspice-server1      0.14.3-2.1
ii  libtinfo6             6.2+20201114-2
ii  libudev1              247.3-5
ii  liburing1             0.7-3
ii  libusb-1.0-0          2:1.0.24-3
ii  libusbredirparser1    0.8.0-1+b1
ii  libvdeplug2           4.0.1-2
ii  libvirglrenderer1     0.8.2-5
ii  libxendevicemodel1    4.14.1+11-gb0b734a8b3-1
ii  libxenevtchn1         4.14.1+11-gb0b734a8b3-1
ii  libxenforeignmemory1  4.14.1+11-gb0b734a8b3-1
ii  libxengnttab1         4.14.1+11-gb0b734a8b3-1
ii  libxenmisc4.14        4.14.1+11-gb0b734a8b3-1
ii  libxenstore3.0        4.14.1+11-gb0b734a8b3-1
ii  libxentoolcore1       4.14.1+11-gb0b734a8b3-1
pn  qemu-system-common    <none>
pn  qemu-system-data      <none>
ii  seabios               1.14.0-2
ii  zlib1g                1:1.2.11.dfsg-2

Versions of packages qemu-system-x86 recommends:
ii  ovmf             2020.11-2
pn  qemu-system-gui  <none>
pn  qemu-utils       <none>

Versions of packages qemu-system-x86 suggests:
pn  qemu-block-extra  <none>
ii  samba             2:4.13.5+dfsg-2
pn  sgabios           <none>
pn  vde2              <none>

Reply via email to