Skip to contentSkip to conversation

xen: add Intel IGD passthrough

PATCH Superseded Tiejun Chen 1 participant 9 messages Jun 5, 2015

v8 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v8 cover xen: add Intel IGD passthrough

v8:

* Rebase on the latest qemu tree
* Cleanup one xen leftover in patch #3

v7:

* Instead of "-gfx_passthru" we'd like to make that a machine option, "-machine xxx,igd-passthru=on""
* try to make something as common shared by others like KvmGT in the future
* Just read those real value from host bridge pci configuration space when create host bridge then put in dev->config.

v6:

* Drop introducing a new machine specific to IGD passthrough
* Try to share some codes from KVM stuff in qemu to retrive VGA BIOS
* Currently IGD drivers always need to access PCH by 1f.0. But we don't want to poke that directly to get ID, and although in real world different GPU should have different PCH. But actually the different PCH DIDs likely map to different PCH SKUs. We do the same thing for the GPU. For PCH, the different SKUs are going to be all the same silicon design and implementation, just different features turn on and off with fuses. The SW interfaces should be consistent across all SKUs in a given family (eg LPT). But just same features may not be supported.

Most of these different PCH features probably don't matter to the Gfx driver, but obviously any difference in display port connections will so it should be fine with any PCH in case of passthrough.

So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) scenarios, 0x9cc3 for BDW(Broadwell).
* Drop igd write ops since its fine to emulate that, and we also shrink those igd read ops as necessary.
* Rebase and cleanup all patches.

v5:

* Simplify to make sure its really inherited from the standard one in patch #3
* Then drop the original patch #3

v4:

* Rebase on latest tree
* Drop patch #2
* Regenerate patches after Michael introduce patch #1
* We need to use this pci_type as a index to reuse I440FX_PCI_DEVICE()
* Test: boot with a preinstalled winxp ./i386-softmmu/qemu-system-i386 -hda winxp-32.img -m 2560 -boot c -machine pc

v3:

* Drop patch #4
* Add one patch #1 from Michael
* Rebase
* In./i386-softmmu/qemu-system-i386 -hda test.img -m 2560 -boot c -machine pc

v2:

* Fix some coding style
* New patch to separate i440fx_init
* Just add prefix with XEN_IGD_PASSTHROUGH/xen_igd_passthrough
* Based on patch #2 to regenerate
* Unify prefix with XEN_IGD_PASSTHROUGH/xen_igd_passthrough like patch #3
* Test: boot with a preinstalled ubuntu 14.04 ./i386-softmmu/qemu-system-i386 -hda test.img -m 2560 -boot c -machine pc

As we discussed we need to create a separate machine to support current IGD passthrough.

----------------------------------------------------------------
Michael S. Tsirkin (1):
i440fx: make types configurable at run-time

Tiejun Chen (9):
pc_init1: pass parameters just with types
piix: create host bridge to passthrough
hw/pci-assign: split pci-assign.c
xen, gfx passthrough: basic graphics passthrough support xen, gfx passthrough: retrieve VGA BIOS to work
igd gfx passthrough: create a isa bridge
xen, gfx passthrough: register a isa bridge
xen, gfx passthrough: register host bridge specific to passthrough xen, gfx passthrough: add opregion mapping

 hw/core/machine.c             |  20 +++
 hw/i386/Makefile.objs         |   1 +
 hw/i386/kvm/pci-assign.c      |  82 +---------
 hw/i386/pc_piix.c             | 151 ++++++++++++++++++-
 hw/i386/pci-assign-load-rom.c |  93 ++++++++++++
 hw/pci-host/piix.c            |  91 +++++++++++-
 hw/xen/Makefile.objs          |   1 +
 hw/xen/xen-host-pci-device.c  |   5 +
 hw/xen/xen-host-pci-device.h  |   1 +
 hw/xen/xen_pt.c               |  32 ++++
 hw/xen/xen_pt.h               |  21 ++-
 hw/xen/xen_pt_config_init.c   |  51 ++++++-
 hw/xen/xen_pt_graphics.c      | 272 ++++++++++++++++++++++++++++++++++
 include/hw/boards.h           |   1 +
 include/hw/i386/pc.h          |   8 +-
 include/hw/pci/pci-assign.h   |  27 ++++
 include/hw/xen/xen.h          |   1 +
 qemu-options.hx               |   3 +
 vl.c                          |  10 ++
 19 files changed, 780 insertions(+), 91 deletions(-)
 create mode 100644 hw/i386/pci-assign-load-rom.c
 create mode 100644 hw/xen/xen_pt_graphics.c
 create mode 100644 include/hw/pci/pci-assign.h

Thanks
Tiejun

#1 lore raw

PATCH v8 1/10 i440fx: make types configurable at run-time

From: "Michael S. Tsirkin" <[email protected]>

IGD passthrough wants to supply a different pci and host devices, inheriting i440fx devices. Make types configurable.

---
 hw/i386/pc_piix.c    | 4 +++-
 hw/pci-host/piix.c   | 9 ++++-----
 include/hw/i386/pc.h | 6 +++++-
 3 files changed, 12 insertions(+), 7 deletions(-)
hw/i386/pc_piix.c +3 -1
index 6e7fa42..c05b7c7 100644
@@ -202,7 +202,9 @@ static void pc_init1(MachineState *machine)
     }
 
     if (pci_enabled) {
-        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
+        pci_bus = i440fx_init(TYPE_I440FX_PCI_HOST_BRIDGE,
+                              TYPE_I440FX_PCI_DEVICE,
+                              &i440fx_state, &piix3_devfn, &isa_bus, gsi,
                               system_memory, system_io, machine->ram_size,
                               below_4g_mem_size,
                               above_4g_mem_size,
hw/pci-host/piix.c +4 -5
index 723836f..c812eaa 100644
@@ -40,7 +40,6 @@
  * http://download.intel.com/design/chipsets/datashts/29054901.pdf
  */
 
-#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
 #define I440FX_PCI_HOST_BRIDGE(obj) \
     OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX_PCI_HOST_BRIDGE)
 
@@ -91,7 +90,6 @@ typedef struct PIIX3State {
     MemoryRegion rcr_mem;
 } PIIX3State;
 
-#define TYPE_I440FX_PCI_DEVICE "i440FX"
 #define I440FX_PCI_DEVICE(obj) \
     OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
 
@@ -304,7 +302,8 @@ static void i440fx_realize(PCIDevice *dev, Error **errp)
     cpu_smm_register(&i440fx_set_smm, d);
 }
 
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
+PCIBus *i440fx_init(const char *host_type, const char *pci_type,
+                    PCII440FXState **pi440fx_state,
                     int *piix3_devfn,
                     ISABus **isa_bus, qemu_irq *pic,
                     MemoryRegion *address_space_mem,
@@ -324,7 +323,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
     unsigned i;
     I440FXState *i440fx;
 
-    dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE);
+    dev = qdev_create(NULL, host_type);
     s = PCI_HOST_BRIDGE(dev);
     b = pci_bus_new(dev, NULL, pci_address_space,
                     address_space_io, 0, TYPE_PCI_BUS);
@@ -332,7 +331,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
     object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
     qdev_init_nofail(dev);
 
-    d = pci_create_simple(b, 0, TYPE_I440FX_PCI_DEVICE);
+    d = pci_create_simple(b, 0, pci_type);
     *pi440fx_state = I440FX_PCI_DEVICE(d);
     f = *pi440fx_state;
     f->system_memory = address_space_mem;
include/hw/i386/pc.h +5 -1
index 27bd748..bb808c9 100644
@@ -229,7 +229,11 @@ extern int no_hpet;
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
 
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
+#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
+#define TYPE_I440FX_PCI_DEVICE "i440FX"
+
+PCIBus *i440fx_init(const char *host_type, const char *pci_type,
+                    PCII440FXState **pi440fx_state, int *piix_devfn,
                     ISABus **isa_bus, qemu_irq *pic,
                     MemoryRegion *address_space_mem,
                     MemoryRegion *address_space_io,
Signature · 1 line
1.9.1
#2 lore raw

PATCH v8 2/10 pc_init1: pass parameters just with types

In reply to Tiejun Chen

Pass types to configure pc_init1().

---
 hw/i386/pc_piix.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)
hw/i386/pc_piix.c +8 -6
index c05b7c7..3e2fc04 100644
@@ -75,7 +75,8 @@ static bool has_reserved_memory = true;
 static bool kvmclock_enabled = true;
 
 /* PC hardware initialisation */
-static void pc_init1(MachineState *machine)
+static void pc_init1(MachineState *machine,
+                     const char *host_type, const char *pci_type)
 {
     PCMachineState *pc_machine = PC_MACHINE(machine);
     MemoryRegion *system_memory = get_system_memory();
@@ -202,8 +203,8 @@ static void pc_init1(MachineState *machine)
     }
 
     if (pci_enabled) {
-        pci_bus = i440fx_init(TYPE_I440FX_PCI_HOST_BRIDGE,
-                              TYPE_I440FX_PCI_DEVICE,
+        pci_bus = i440fx_init(host_type,
+                              pci_type,
                               &i440fx_state, &piix3_devfn, &isa_bus, gsi,
                               system_memory, system_io, machine->ram_size,
                               below_4g_mem_size,
@@ -437,7 +438,7 @@ static void pc_init_isa(MachineState *machine)
     }
     x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
     enable_compat_apic_id_mode();
-    pc_init1(machine);
+    pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
 }
 
 #ifdef CONFIG_XEN
@@ -445,7 +446,7 @@ static void pc_xen_hvm_init(MachineState *machine)
 {
     PCIBus *bus;
 
-    pc_init1(machine);
+    pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
 
     bus = pci_find_primary_bus();
     if (bus != NULL) {
@@ -461,7 +462,8 @@ static void pc_xen_hvm_init(MachineState *machine)
         if (compat) { \
             compat(machine); \
         } \
-        pc_init1(machine); \
+        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
+                 TYPE_I440FX_PCI_DEVICE); \
     } \
     DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
 
Signature · 1 line
1.9.1
#3 lore raw

PATCH v8 3/10 piix: create host bridge to passthrough

In reply to Tiejun Chen

Implement a pci host bridge specific to passthrough. Actually this just inherits the standard one. And we also just expose a minimal real host bridge pci configuration subset.

---
 hw/pci-host/piix.c   | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/i386/pc.h |  2 ++
 2 files changed, 84 insertions(+)
hw/pci-host/piix.c +82 -0
index c812eaa..0906ba5 100644
@@ -728,6 +728,87 @@ static const TypeInfo i440fx_info = {
     .class_init    = i440fx_class_init,
 };
 
+/* IGD Passthrough Host Bridge. */
+typedef struct {
+    uint8_t offset;
+    uint8_t len;
+} IGDHostInfo;
+
+/* Here we just expose minimal host bridge offset subset. */
+static const IGDHostInfo igd_host_bridge_infos[] = {
+    {0x08, 2},  /* revision id */
+    {0x2c, 2},  /* sybsystem vendor id */
+    {0x2e, 2},  /* sybsystem id */
+    {0x50, 2},  /* SNB: processor graphics control register */
+    {0x52, 2},  /* processor graphics control register */
+    {0xa4, 4},  /* SNB: graphics base of stolen memory */
+    {0xa8, 4},  /* SNB: base of GTT stolen memory */
+};
+
+static int host_pci_config_read(int pos, int len, uint32_t val)
+{
+    char path[PATH_MAX];
+    int config_fd;
+    ssize_t size = sizeof(path);
+    /* Access real host bridge. */
+    int rc = snprintf(path, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
+                      0, 0, 0, 0, "config");
+
+    if (rc >= size || rc < 0) {
+        return -ENODEV;
+    }
+
+    config_fd = open(path, O_RDWR);
+    if (config_fd < 0) {
+        return -ENODEV;
+    }
+
+    do {
+        rc = pread(config_fd, (uint8_t *)&val, len, pos);
+    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
+    if (rc != len) {
+        return -errno;
+    }
+
+    return 0;
+}
+
+static int igd_pt_i440fx_initfn(struct PCIDevice *pci_dev)
+{
+    uint32_t val = 0;
+    int rc, i, num;
+    int pos, len;
+
+    num = ARRAY_SIZE(igd_host_bridge_infos);
+    for (i = 0; i < num; i++) {
+        pos = igd_host_bridge_infos[i].offset;
+        len = igd_host_bridge_infos[i].len;
+        rc = host_pci_config_read(pos, len, val);
+        if (rc) {
+            return -ENODEV;
+        }
+        pci_default_write_config(pci_dev, pos, val, len);
+    }
+
+    return 0;
+}
+
+static void igd_passthrough_i440fx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = igd_pt_i440fx_initfn;
+    dc->desc = "IGD Passthrough Host bridge";
+}
+
+static const TypeInfo igd_passthrough_i440fx_info = {
+    .name          = TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE,
+    .parent        = TYPE_I440FX_PCI_DEVICE,
+    .instance_size = sizeof(PCII440FXState),
+    .class_init    = igd_passthrough_i440fx_class_init,
+};
+
 static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
                                                 PCIBus *rootbus)
 {
@@ -769,6 +850,7 @@ static const TypeInfo i440fx_pcihost_info = {
 static void i440fx_register_types(void)
 {
     type_register_static(&i440fx_info);
+    type_register_static(&igd_passthrough_i440fx_info);
     type_register_static(&piix3_info);
     type_register_static(&piix3_xen_info);
     type_register_static(&i440fx_pcihost_info);
include/hw/i386/pc.h +2 -0
index bb808c9..83962aa 100644
@@ -232,6 +232,8 @@ typedef struct PCII440FXState PCII440FXState;
 #define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
 #define TYPE_I440FX_PCI_DEVICE "i440FX"
 
+#define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX"
+
 PCIBus *i440fx_init(const char *host_type, const char *pci_type,
                     PCII440FXState **pi440fx_state, int *piix_devfn,
                     ISABus **isa_bus, qemu_irq *pic,
Signature · 1 line
1.9.1
#4 lore raw

PATCH v8 4/10 hw/pci-assign: split pci-assign.c

In reply to Tiejun Chen

We will try to reuse assign_dev_load_option_rom in xen side, and especially its a good beginning to unify pci assign codes both on kvm and xen in the future.

---
 hw/i386/Makefile.objs         |  1 +
 hw/i386/kvm/pci-assign.c      | 82 ++++----------------------------------
 hw/i386/pci-assign-load-rom.c | 93 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/pci/pci-assign.h   | 27 +++++++++++++
 4 files changed, 128 insertions(+), 75 deletions(-)
 create mode 100644 hw/i386/pci-assign-load-rom.c
 create mode 100644 include/hw/pci/pci-assign.h
hw/i386/Makefile.objs +1 -0
index 0be5d97..2b9c98d 100644
@@ -7,6 +7,7 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/
 
 obj-y += kvmvapic.o
 obj-y += acpi-build.o
+obj-y += pci-assign-load-rom.o
 hw/i386/acpi-build.o: hw/i386/acpi-build.c \
 	hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex \
 	hw/i386/ssdt-tpm.hex hw/i386/ssdt-tpm2.hex
hw/i386/kvm/pci-assign.c +7 -75

103 lines not on this page · raw message

hw/i386/pci-assign-load-rom.c new file +93 -0

93 lines not on this page · raw message

include/hw/pci/pci-assign.h new file +27 -0
new file mode 100644
index 0000000..55f42c5
@@ -0,0 +1,27 @@
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Just split from hw/i386/kvm/pci-assign.c.
+ */
+#ifndef PCI_ASSIGN_H
+#define PCI_ASSIGN_H
+
+#include "hw/pci/pci.h"
+
+//#define DEVICE_ASSIGNMENT_DEBUG
+
+#ifdef DEVICE_ASSIGNMENT_DEBUG
+#define DEBUG(fmt, ...)                                       \
+    do {                                                      \
+        fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__);  \
+    } while (0)
+#else
+#define DEBUG(fmt, ...)
+#endif
+
+void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner,
+                                     int *size, unsigned int domain,
+                                     unsigned int bus, unsigned int slot,
+                                     unsigned int function);
+#endif /* PCI_ASSIGN_H */
Signature · 1 line
1.9.1
#5 lore raw

PATCH v8 5/10 xen, gfx passthrough: basic graphics passthrough support

In reply to Tiejun Chen

basic gfx passthrough support:
- add a vga type for gfx passthrough
- register/unregister legacy VGA I/O ports and MMIOs for passthrough GFX

---
 hw/core/machine.c            |  20 ++++++++
 hw/xen/Makefile.objs         |   1 +
 hw/xen/xen-host-pci-device.c |   5 ++
 hw/xen/xen-host-pci-device.h |   1 +
 hw/xen/xen_pt.c              |   4 ++
 hw/xen/xen_pt.h              |  10 +++-
 hw/xen/xen_pt_graphics.c     | 111 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/boards.h          |   1 +
 qemu-options.hx              |   3 ++
 vl.c                         |  10 ++++
 10 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 hw/xen/xen_pt_graphics.c
hw/core/machine.c +20 -0
index 25c45e6..0655665 100644
@@ -226,6 +226,20 @@ static void machine_set_usb(Object *obj, bool value, Error **errp)
     ms->usb_disabled = !value;
 }
 
+static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return ms->igd_gfx_passthru;
+}
+
+static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->igd_gfx_passthru = value;
+}
+
 static char *machine_get_firmware(Object *obj, Error **errp)
 {
     MachineState *ms = MACHINE(obj);
@@ -380,6 +394,12 @@ static void machine_initfn(Object *obj)
     object_property_set_description(obj, "usb",
                                     "Set on/off to enable/disable usb",
                                     NULL);
+    object_property_add_bool(obj, "igd-passthru",
+                             machine_get_igd_gfx_passthru,
+                             machine_set_igd_gfx_passthru, NULL);
+    object_property_set_description(obj, "igd-passthru",
+                                    "Set on/off to enable/disable igd passthrou",
+                                    NULL);
     object_property_add_str(obj, "firmware",
                             machine_get_firmware,
                             machine_set_firmware, NULL);
hw/xen/Makefile.objs +1 -0
index a0ca0aa..a9ad7e7 100644
@@ -3,3 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
 
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
+obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_pt_graphics.o
hw/xen/xen-host-pci-device.c +5 -0
index 743b37b..a54b7de 100644
@@ -376,6 +376,11 @@ int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
         goto error;
     }
     d->irq = v;
+    rc = xen_host_pci_get_hex_value(d, "class", &v);
+    if (rc) {
+        goto error;
+    }
+    d->class_code = v;
     d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
 
     return 0;
hw/xen/xen-host-pci-device.h +1 -0
index c2486f0..f1e1c30 100644
@@ -25,6 +25,7 @@ typedef struct XenHostPCIDevice {
 
     uint16_t vendor_id;
     uint16_t device_id;
+    uint32_t class_code;
     int irq;
 
     XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
hw/xen/xen_pt.c +4 -0
index 9afcda8..50bdf6f 100644
@@ -494,6 +494,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
                    d->rom.size, d->rom.base_addr);
     }
 
+    xen_pt_register_vga_regions(d);
     return 0;
 }
 
@@ -798,6 +799,7 @@ out:
 static void xen_pt_unregister_device(PCIDevice *d)
 {
     XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
+    XenHostPCIDevice *host_dev = &s->real_device;
     uint8_t machine_irq = s->machine_irq;
     uint8_t intx = xen_pt_pci_intx(s);
     int rc;
@@ -841,6 +843,8 @@ static void xen_pt_unregister_device(PCIDevice *d)
     /* delete all emulated config registers */
     xen_pt_config_delete(s);
 
+    xen_pt_unregister_vga_regions(host_dev);
+
     memory_listener_unregister(&s->memory_listener);
     memory_listener_unregister(&s->io_listener);
 
hw/xen/xen_pt.h +9 -1
index 4bba559..dfa6171 100644
@@ -301,5 +301,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
     return s->msix && s->msix->bar_index == bar;
 }
 
-
+extern bool has_igd_gfx_passthru;
+static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
+{
+    return (has_igd_gfx_passthru
+            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
+int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
+int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
+int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev);
 #endif /* !XEN_PT_H */
hw/xen/xen_pt_graphics.c new file +111 -0

111 lines not on this page · raw message

include/hw/boards.h +1 -0
index ff79797..a7b75ac 100644
@@ -134,6 +134,7 @@ struct MachineState {
     bool mem_merge;
     bool usb;
     bool usb_disabled;
+    bool igd_gfx_passthru;
     char *firmware;
     bool iommu;
     bool suppress_vmdesc;
qemu-options.hx +3 -0
index 7edd1f1..964ba0d 100644
@@ -38,6 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "                dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
     "                mem-merge=on|off controls memory merge support (default: on)\n"
     "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n"
+    "                igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n"
     "                aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n"
     "                dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n"
     "                suppress-vmdesc=on|off disables self-describing migration (default=off)\n",
@@ -55,6 +56,8 @@ than one accelerator specified, the next one is used if the previous one fails
 to initialize.
 @item kernel_irqchip=on|off
 Enables in-kernel irqchip support for the chosen accelerator when available.
+@item gfx_passthru=on|off
+Enables IGD GFX passthrough support for the chosen machine when available.
 @item vmport=on|off|auto
 Enables emulation of VMWare IO port, for vmmouse etc. auto says to select the
 value based on accel. For accel=xen the default is off otherwise the default
vl.c +10 -0
index 1d4c089..34c1d55 100644
@@ -1224,6 +1224,13 @@ static void configure_msg(QemuOpts *opts)
     enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true);
 }
 
+/* Now we still need this for compatibility with XEN. */
+bool has_igd_gfx_passthru;
+static void igd_gfx_passthru(void)
+{
+    has_igd_gfx_passthru = current_machine->igd_gfx_passthru;
+}
+
 /***********************************************************/
 /* USB devices */
 
@@ -4256,6 +4263,9 @@ int main(int argc, char **argv, char **envp)
             exit(1);
     }
 
+    /* Check if IGD GFX passthrough. */
+    igd_gfx_passthru();
+
     /* init generic devices */
     if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
         exit(1);
Signature · 1 line
1.9.1
#6 lore raw

PATCH v8 6/10 xen, gfx passthrough: retrieve VGA BIOS to work

In reply to Tiejun Chen

Now we retrieve VGA bios like kvm stuff in qemu but we need to fix Device Identification in case if its not matched with the real IGD device since Seabios is always trying to compare this ID to work out VGA BIOS.

---
 hw/xen/xen_pt.c          | 10 ++++++
 hw/xen/xen_pt.h          |  5 +++
 hw/xen/xen_pt_graphics.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
hw/xen/xen_pt.c +10 -0
index 50bdf6f..3bf2233 100644
@@ -717,6 +717,16 @@ static int xen_pt_initfn(PCIDevice *d)
     s->memory_listener = xen_pt_memory_listener;
     s->io_listener = xen_pt_io_listener;
 
+    /* Setup VGA bios for passthrough GFX */
+    if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
+        (s->real_device.dev == 2) && (s->real_device.func == 0)) {
+        if (xen_pt_setup_vga(s, &s->real_device) < 0) {
+            XEN_PT_ERR(d, "Setup VGA BIOS of passthrough GFX failed!\n");
+            xen_host_pci_device_put(&s->real_device);
+            return -1;
+        }
+    }
+
     /* Handle real device's MMIO/PIO BARs */
     xen_pt_register_regions(s, &cmd);
 
hw/xen/xen_pt.h +5 -0
index dfa6171..6c42754 100644
@@ -301,6 +301,11 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
     return s->msix && s->msix->bar_index == bar;
 }
 
+extern void *pci_assign_dev_load_option_rom(PCIDevice *dev,
+                                            struct Object *owner, int *size,
+                                            unsigned int domain,
+                                            unsigned int bus, unsigned int slot,
+                                            unsigned int function);
 extern bool has_igd_gfx_passthru;
 static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
 {
hw/xen/xen_pt_graphics.c +79 -0

82 lines not on this page · raw message

Signature · 1 line
1.9.1
#7 lore raw

PATCH v8 7/10 igd gfx passthrough: create a isa bridge

In reply to Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0. But we don't want to poke that directly to get ID, and although in real world different GPU should have different PCH. But actually the different PCH DIDs likely map to different PCH SKUs. We do the same thing for the GPU. For PCH, the different SKUs are going to be all the same silicon design and implementation, just different features turn on and off with fuses. The SW interfaces should be consistent across all SKUs in a given family (eg LPT). But just same features may not be supported.

Most of these different PCH features probably don't matter to the Gfx driver, but obviously any difference in display port connections will so it should be fine with any PCH in case of passthrough.

So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) scenarios, 0x9cc3 for BDW(Broadwell).

---
 hw/i386/pc_piix.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)
hw/i386/pc_piix.c +112 -0
index 3e2fc04..6054b5a 100644
@@ -904,6 +904,118 @@ static void pc_i440fx_0_10_machine_options(MachineClass *m)
 DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
                       pc_i440fx_0_10_machine_options);
 
+typedef struct {
+    uint16_t gpu_device_id;
+    uint16_t pch_device_id;
+    uint8_t pch_revision_id;
+} IGDDeviceIDInfo;
+
+/* In real world different GPU should have different PCH. But actually
+ * the different PCH DIDs likely map to different PCH SKUs. We do the
+ * same thing for the GPU. For PCH, the different SKUs are going to be
+ * all the same silicon design and implementation, just different
+ * features turn on and off with fuses. The SW interfaces should be
+ * consistent across all SKUs in a given family (eg LPT). But just same
+ * features may not be supported.
+ *
+ * Most of these different PCH features probably don't matter to the
+ * Gfx driver, but obviously any difference in display port connections
+ * will so it should be fine with any PCH in case of passthrough.
+ *
+ * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
+ * scenarios, 0x9cc3 for BDW(Broadwell).
+ */
+static const IGDDeviceIDInfo igd_combo_id_infos[] = {
+    /* HSW Classic */
+    {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
+    {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
+    {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
+    {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
+    {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
+    /* HSW ULT */
+    {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
+    {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
+    {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
+    {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
+    {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
+    {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
+    /* HSW CRW */
+    {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
+    {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
+    /* HSW Server */
+    {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
+    /* HSW SRVR */
+    {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
+    /* BSW */
+    {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
+    {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
+    {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
+    {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
+    {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
+    {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
+    {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
+    {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
+    {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
+    {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
+    {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
+};
+
+static void isa_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "ISA bridge faked to support IGD PT";
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+};
+
+static TypeInfo isa_bridge_info = {
+    .name          = "igd-passthrough-isa-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = isa_bridge_class_init,
+};
+
+static void pt_graphics_register_types(void)
+{
+    type_register_static(&isa_bridge_info);
+}
+type_init(pt_graphics_register_types)
+
+void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
+{
+    struct PCIDevice *bridge_dev;
+    int i, num;
+    uint16_t pch_dev_id = 0xffff;
+    uint8_t pch_rev_id;
+
+    num = ARRAY_SIZE(igd_combo_id_infos);
+    for (i = 0; i < num; i++) {
+        if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
+            pch_dev_id = igd_combo_id_infos[i].pch_device_id;
+            pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
+        }
+    }
+
+    if (pch_dev_id == 0xffff) {
+        return;
+    }
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                                   "igd-passthrough-isa-bridge");
+
+    /*
+     * Note that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (!bridge_dev) {
+        fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
+        return;
+    }
+    pci_config_set_device_id(bridge_dev->config, pch_dev_id);
+    pci_config_set_revision(bridge_dev->config, pch_rev_id);
+}
 
 static void isapc_machine_options(MachineClass *m)
 {
Signature · 1 line
1.9.1
#8 lore raw
In reply to Tiejun Chen

Sorry, just please ignore this series because looks some patches are not sent out.

Tiejun

Quoted 116 lines · Tiejun Chen

v8:

* Rebase on the latest qemu tree
* Cleanup one xen leftover in patch #3

v7:

* Instead of "-gfx_passthru" we'd like to make that a machine option, "-machine xxx,igd-passthru=on""
* try to make something as common shared by others like KvmGT in the future
* Just read those real value from host bridge pci configuration space when create host bridge then put in dev->config.

v6:

* Drop introducing a new machine specific to IGD passthrough
* Try to share some codes from KVM stuff in qemu to retrive VGA BIOS
* Currently IGD drivers always need to access PCH by 1f.0. But we don't want to poke that directly to get ID, and although in real world different GPU should have different PCH. But actually the different PCH DIDs likely map to different PCH SKUs. We do the same thing for the GPU. For PCH, the different SKUs are going to be all the same silicon design and implementation, just different features turn on and off with fuses. The SW interfaces should be consistent across all SKUs in a given family (eg LPT). But just same features may not be supported.

Most of these different PCH features probably don't matter to the Gfx driver, but obviously any difference in display port connections will so it should be fine with any PCH in case of passthrough.

So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) scenarios, 0x9cc3 for BDW(Broadwell).
* Drop igd write ops since its fine to emulate that, and we also shrink those igd read ops as necessary.
* Rebase and cleanup all patches.

v5:

* Simplify to make sure its really inherited from the standard one in patch #3
* Then drop the original patch #3

v4:

* Rebase on latest tree
* Drop patch #2
* Regenerate patches after Michael introduce patch #1
* We need to use this pci_type as a index to reuse I440FX_PCI_DEVICE()
* Test: boot with a preinstalled winxp ./i386-softmmu/qemu-system-i386 -hda winxp-32.img -m 2560 -boot c -machine pc

v3:

* Drop patch #4
* Add one patch #1 from Michael
* Rebase
* In./i386-softmmu/qemu-system-i386 -hda test.img -m 2560 -boot c -machine pc

v2:

* Fix some coding style
* New patch to separate i440fx_init
* Just add prefix with XEN_IGD_PASSTHROUGH/xen_igd_passthrough
* Based on patch #2 to regenerate
* Unify prefix with XEN_IGD_PASSTHROUGH/xen_igd_passthrough like patch #3
* Test: boot with a preinstalled ubuntu 14.04 ./i386-softmmu/qemu-system-i386 -hda test.img -m 2560 -boot c -machine pc

As we discussed we need to create a separate machine to support current IGD passthrough.

----------------------------------------------------------------
Michael S. Tsirkin (1):
i440fx: make types configurable at run-time

Tiejun Chen (9):
pc_init1: pass parameters just with types
piix: create host bridge to passthrough
hw/pci-assign: split pci-assign.c
xen, gfx passthrough: basic graphics passthrough support xen, gfx passthrough: retrieve VGA BIOS to work
igd gfx passthrough: create a isa bridge
xen, gfx passthrough: register a isa bridge
xen, gfx passthrough: register host bridge specific to passthrough xen, gfx passthrough: add opregion mapping

  hw/core/machine.c             |  20 +++
  hw/i386/Makefile.objs         |   1 +
  hw/i386/kvm/pci-assign.c      |  82 +---------
  hw/i386/pc_piix.c             | 151 ++++++++++++++++++-
  hw/i386/pci-assign-load-rom.c |  93 ++++++++++++
  hw/pci-host/piix.c            |  91 +++++++++++-
  hw/xen/Makefile.objs          |   1 +
  hw/xen/xen-host-pci-device.c  |   5 +
  hw/xen/xen-host-pci-device.h  |   1 +
  hw/xen/xen_pt.c               |  32 ++++
  hw/xen/xen_pt.h               |  21 ++-
  hw/xen/xen_pt_config_init.c   |  51 ++++++-
  hw/xen/xen_pt_graphics.c      | 272 ++++++++++++++++++++++++++++++++++
  include/hw/boards.h           |   1 +
  include/hw/i386/pc.h          |   8 +-
  include/hw/pci/pci-assign.h   |  27 ++++
  include/hw/xen/xen.h          |   1 +
  qemu-options.hx               |   3 +
  vl.c                          |  10 ++
  19 files changed, 780 insertions(+), 91 deletions(-)

create mode 100644 hw/i386/pci-assign-load-rom.c create mode 100644 hw/xen/xen_pt_graphics.c create mode 100644 include/hw/pci/pci-assign.h

Thanks
Tiejun