Skip to contentSkip to conversation

xen: add Intel IGD passthrough support

PATCH Superseded Tiejun Chen 1 participant 7 messages May 26, 2014

v3 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v3 cover xen: add Intel IGD passthrough support

v3:

* In this case, as we discussed we will give priority to devices to reserve a specific devfn by passing "device_model_args_hvm = ['-device', 'xen-platform,addr=0x3']" and "vga=none", so withdraw patch #1, #2 and #4.
* Fix some typos.
* Add more comments to make that readable.
* To unmap igd_opregion when call xen_pt_unregister_vga_regions().
* Improve some return paths.
* Force to convert igd_guest/host_opoegion as an unsigned long type while calling xc_domain_memory_mapping().
* We need to map 3 pages for opregion as hvmloader set.

v2:

* rebase on current qemu tree.
* retrieve VGA bios from sysfs properly.
* redefine some function name.
* introduce bitmap to manage registe/runregister pci dev, and provide a common way to reserve some specific devfn.
* introduce is_igd_passthrough() to make sure we touch physical host bridge only in IGD case.
* We should return zero as an invalid address value while calling igd_read_opregion().

Additionally, now its also not necessary to recompile seabios with some extra steps like v1.

The following patches are ported partially from Xen Qemu-traditional branch which are adding Intel IGD passthrough supporting to Qemu upstream.

To pass through IGD to guest, user need to add following lines in Xen config file:
gfx_passthru=1
pci=['00:02.0 <at> 2']

Now successfully boot Ubuntu 14.04 guests with IGD assigned in Haswell desktop with Latest Xen + Qemu upstream.

----------------------------------------------------------------
Tiejun Chen (2):
xen, gfx passthrough: create intel isa bridge xen, gfx passthrough: create host bridge to passthrough

Yang Zhang (3):
xen, gfx passthrough: basic graphics passthrough support xen, gfx passthrough: support Intel IGD passthrough with VT-D xen, gfx passthrough: add opregion mapping

 hw/pci-host/piix.c           |  56 +++++++++++++-
 hw/xen/Makefile.objs         |   2 +-
 hw/xen/xen-host-pci-device.c |   5 ++
 hw/xen/xen-host-pci-device.h |   1 +
 hw/xen/xen_pt.c              |  10 +++
 hw/xen/xen_pt.h              |  12 ++-
 hw/xen/xen_pt_config_init.c  |  50 ++++++++++++-
 hw/xen/xen_pt_graphics.c     | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |   9 +++
 vl.c                         |  11 ++-
 10 files changed, 668 insertions(+), 6 deletions(-)
 create mode 100644 hw/xen/xen_pt_graphics.c

Thanks
Tiejun

#1 lore raw

PATCH v3 1/5 xen, gfx passthrough: basic graphics passthrough support

basic gfx passthrough support:
- add a vga type for gfx passthrough
- retrieve VGA bios from sysfs, then load it to guest 0xC0000
- register/unregister legacy VGA I/O ports and MMIOs for passthroughed gfx

The original patch is from Weidong Han <[email protected]>

---
v3:

* Fix some typos.
* Add more comments to make that readable.
* Improve some return paths.

v2:

* retrieve VGA bios from sysfs properly.
* redefine some function name.

 hw/xen/Makefile.objs         |   2 +-
 hw/xen/xen-host-pci-device.c |   5 +
 hw/xen/xen-host-pci-device.h |   1 +
 hw/xen/xen_pt.c              |  10 ++
 hw/xen/xen_pt.h              |   4 +
 hw/xen/xen_pt_graphics.c     | 232 +++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |   9 ++
 vl.c                         |  11 +-
 8 files changed, 272 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen/xen_pt_graphics.c
hw/xen/Makefile.objs +1 -1
index a0ca0aa..77b7dae 100644
@@ -2,4 +2,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 +10 -0
index be4220b..a0113ea 100644
@@ -450,6 +450,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
                    d->rom.size, d->rom.base_addr);
     }
 
+    xen_pt_register_vga_regions(d);
     return 0;
 }
 
@@ -470,6 +471,8 @@ static void xen_pt_unregister_regions(XenPCIPassthroughState *s)
     if (d->rom.base_addr && d->rom.size) {
         memory_region_destroy(&s->rom);
     }
+
+    xen_pt_unregister_vga_regions(d);
 }
 
 /* region mapping */
@@ -693,6 +696,13 @@ static int xen_pt_initfn(PCIDevice *d)
     /* Handle real device's MMIO/PIO BARs */
     xen_pt_register_regions(s);
 
+    /* Setup VGA bios for passthroughed gfx */
+    if (xen_pt_setup_vga(&s->real_device) < 0) {
+        XEN_PT_ERR(d, "Setup VGA BIOS of passthroughed gfx failed!\n");
+        xen_host_pci_device_put(&s->real_device);
+        return -1;
+    }
+
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
         XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");
hw/xen/xen_pt.h +4 -0
index 942dc60..4d3a18d 100644
@@ -298,5 +298,9 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
     return s->msix && s->msix->bar_index == bar;
 }
 
+extern int xen_has_gfx_passthru;
+int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
+int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
+int xen_pt_setup_vga(XenHostPCIDevice *dev);
 
 #endif /* !XEN_PT_H */
hw/xen/xen_pt_graphics.c new file +232 -0

232 lines not on this page · raw message

qemu-options.hx +9 -0
index c2c0823..9cb324f 100644
@@ -1053,6 +1053,15 @@ STEXI
 Rotate graphical output some deg left (only PXA LCD).
 ETEXI
 
+DEF("gfx_passthru", 0, QEMU_OPTION_gfx_passthru,
+    "-gfx_passthru   enable Intel IGD passthrough by XEN\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -gfx_passthru
+@findex -gfx_passthru
+Enable Intel IGD passthrough by XEN
+ETEXI
+
 DEF("vga", HAS_ARG, QEMU_OPTION_vga,
     "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|none]\n"
     "                select video card type\n", QEMU_ARCH_ALL)
vl.c +10 -1
index 673148e..c02207f 100644
@@ -1438,6 +1438,13 @@ static void smp_parse(QemuOpts *opts)
 
 }
 
+/* We still need this for compatibility with XEN. */
+int xen_has_gfx_passthru;
+static void xen_gfx_passthru(const char *optarg)
+{
+    xen_has_gfx_passthru = 1;
+}
+
 static void configure_realtime(QemuOpts *opts)
 {
     bool enable_mlock;
@@ -2990,7 +2997,6 @@ int main(int argc, char **argv, char **envp)
     const char *trace_file = NULL;
     const ram_addr_t default_ram_size = (ram_addr_t)DEFAULT_RAM_SIZE *
                                         1024 * 1024;
-
     atexit(qemu_run_exit_notifiers);
     error_set_progname(argv[0]);
     qemu_init_exec_dir(argv[0]);
@@ -3957,6 +3963,9 @@ int main(int argc, char **argv, char **envp)
                 }
                 configure_msg(opts);
                 break;
+            case QEMU_OPTION_gfx_passthru:
+                xen_gfx_passthru(optarg);
+                break;
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
Signature · 1 line
1.9.1
#2 lore raw

PATCH v3 2/5 xen, gfx passthrough: create intel isa bridge

In reply to Tiejun Chen

ISA bridge is needed since Intel gfx drive will probe it instead of Dev31:Fun0 to make graphics device passthrough work easy for VMM, that only need to expose ISA bridge to let driver know the real hardware underneath.

The original patch is from Allen Kay [[email protected]]

---
v3:

* Fix some typos.
* Improve some return paths.

v2:

* Nothing is changed.

 hw/xen/xen_pt_graphics.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)
hw/xen/xen_pt_graphics.c +63 -0
index e63bd6f..51b174f 100644
@@ -230,3 +230,66 @@ out:
     g_free(bios);
     return rc;
 }
+
+static uint32_t isa_bridge_read_config(PCIDevice *d, uint32_t addr, int len)
+{
+    return pci_default_read_config(d, addr, len);
+}
+
+static void isa_bridge_write_config(PCIDevice *d, uint32_t addr, uint32_t v,
+                                    int len)
+{
+    pci_default_write_config(d, addr, v, len);
+
+    return;
+}
+
+static void isa_bridge_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->config_read = isa_bridge_read_config;
+    k->config_write = isa_bridge_write_config;
+
+    return;
+};
+
+typedef struct {
+    PCIDevice dev;
+} ISABridgeState;
+
+static TypeInfo isa_bridge_info = {
+    .name          = "intel-pch-isa-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(ISABridgeState),
+    .class_init = isa_bridge_class_init,
+};
+
+static void xen_pt_graphics_register_types(void)
+{
+    type_register_static(&isa_bridge_info);
+}
+
+type_init(xen_pt_graphics_register_types)
+
+static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
+{
+    struct PCIDevice *dev;
+
+    char rid;
+
+    dev = pci_create(bus, PCI_DEVFN(0x1f, 0), "intel-pch-isa-bridge");
+
+    qdev_init_nofail(&dev->qdev);
+
+    pci_config_set_vendor_id(dev->config, hdev->vendor_id);
+    pci_config_set_device_id(dev->config, hdev->device_id);
+
+    xen_host_pci_get_block(hdev, PCI_REVISION_ID, (uint8_t *)&rid, 1);
+
+    pci_config_set_revision(dev->config, rid);
+    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_ISA);
+
+    XEN_PT_LOG(dev, "Intel PCH ISA bridge created.\n");
+    return 0;
+}
Signature · 1 line
1.9.1
#3 lore raw

PATCH v3 3/5 xen, gfx passthrough: support Intel IGD passthrough with VT-D

In reply to Tiejun Chen

Some registers of Intel IGD are mapped in host bridge, so it needs to passthrough these registers of physical host bridge to guest because emulated host bridge in guest doesn't have these mappings.

The original patch is from Weidong Han < weidong.han @ intel.com >

---
v3:

* Improve comments to make that readable.

v2:

* To introduce is_igd_passthrough() to make sure we touch physical host bridge only in IGD case.

 hw/xen/xen_pt.h          |   4 ++
 hw/xen/xen_pt_graphics.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 163 insertions(+)
hw/xen/xen_pt.h +4 -0
index 4d3a18d..507165c 100644
@@ -302,5 +302,9 @@ extern int xen_has_gfx_passthru;
 int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
 int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
 int xen_pt_setup_vga(XenHostPCIDevice *dev);
+int pci_create_pch(PCIBus *bus);
+void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
+                   uint32_t val, int len);
+uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len);
 
 #endif /* !XEN_PT_H */
hw/xen/xen_pt_graphics.c +159 -0

168 lines not on this page · raw message

Signature · 1 line
1.9.1
#4 lore raw

PATCH v3 4/5 xen, gfx passthrough: create host bridge to passthrough

In reply to Tiejun Chen

Implement that pci host bridge to specific to passthrough. Actually thsi just inherit the standard one.

---
v3:

* Just fix this patch head description typo.

v2:

* New patch.

 hw/pci-host/piix.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 54 insertions(+), 2 deletions(-)
hw/pci-host/piix.c +54 -2
index ffdc853..8b11953 100644
@@ -34,6 +34,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/i386/ioapic.h"
 #include "qapi/visitor.h"
+#include "hw/xen/xen_pt.h"
 
 /*
  * I440FX chipset data sheet.
@@ -95,6 +96,10 @@ typedef struct PIIX3State {
 #define I440FX_PCI_DEVICE(obj) \
     OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
 
+#define TYPE_I440FX_XEN_PCI_DEVICE "i440FX-xen"
+#define I440FX_XEN_PCI_DEVICE(obj) \
+    OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_XEN_PCI_DEVICE)
+
 struct PCII440FXState {
     /*< private >*/
     PCIDevice parent_obj;
@@ -305,6 +310,16 @@ static int i440fx_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int i440fx_xen_initfn(PCIDevice *dev)
+{
+    PCII440FXState *d = I440FX_XEN_PCI_DEVICE(dev);
+
+    dev->config[I440FX_SMRAM] = 0x02;
+
+    cpu_smm_register(&i440fx_set_smm, d);
+    return 0;
+}
+
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
                     int *piix3_devfn,
                     ISABus **isa_bus, qemu_irq *pic,
@@ -333,8 +348,15 @@ 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);
-    *pi440fx_state = I440FX_PCI_DEVICE(d);
+    if (xen_enabled()) {
+        d = pci_create_simple(b, 0, TYPE_I440FX_XEN_PCI_DEVICE);
+        *pi440fx_state = I440FX_XEN_PCI_DEVICE(d);
+        pci_create_pch(b);
+    } else {
+        d = pci_create_simple(b, 0, TYPE_I440FX_PCI_DEVICE);
+        *pi440fx_state = I440FX_PCI_DEVICE(d);
+    }
+
     f = *pi440fx_state;
     f->system_memory = address_space_mem;
     f->pci_address_space = pci_address_space;
@@ -705,6 +727,35 @@ static const TypeInfo i440fx_info = {
     .class_init    = i440fx_class_init,
 };
 
+static void i440fx_xen_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = i440fx_xen_initfn;
+    k->config_write = igd_pci_write;
+    k->config_read = igd_pci_read;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82441;
+    k->revision = 0x02;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    dc->desc = "XEN Host bridge";
+    dc->vmsd = &vmstate_i440fx;
+    /*
+     * PCI-facing part of the host bridge, not usable without the
+     * host-facing part, which can't be device_add'ed, yet.
+     */
+    dc->cannot_instantiate_with_device_add_yet = true;
+    dc->hotpluggable   = false;
+}
+
+static const TypeInfo i440fx_xen_info = {
+    .name          = TYPE_I440FX_XEN_PCI_DEVICE,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCII440FXState),
+    .class_init    = i440fx_xen_class_init,
+};
+
 static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
                                                 PCIBus *rootbus)
 {
@@ -746,6 +797,7 @@ static const TypeInfo i440fx_pcihost_info = {
 static void i440fx_register_types(void)
 {
     type_register_static(&i440fx_info);
+    type_register_static(&i440fx_xen_info);
     type_register_static(&piix3_info);
     type_register_static(&piix3_xen_info);
     type_register_static(&i440fx_pcihost_info);
Signature · 1 line
1.9.1
#5 lore raw

PATCH v3 5/5 xen, gfx passthrough: add opregion mapping

In reply to Tiejun Chen

The OpRegion shouldn't be mapped 1:1 because the address in the host can't be used in the guest directly.

This patch traps read and write access to the opregion of the Intel GPU config space (offset 0xfc).

The original patch is from Jean Guyader <[email protected]>

---
v3:

* Fix some typos.
* Add more comments to make that readable.
* To unmap igd_opregion when call xen_pt_unregister_vga_regions().
* Improve some return paths.
* We need to map 3 pages for opregion as hvmloader set.
* Force to convert igd_guest/host_opoegion as an unsigned long type while calling xc_domain_memory_mapping().

v2:

* We should return zero as an invalid address value while calling igd_read_opregion().

 hw/xen/xen_pt.h             |  4 ++-
 hw/xen/xen_pt_config_init.c | 50 ++++++++++++++++++++++++++++++++++-
 hw/xen/xen_pt_graphics.c    | 64 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 2 deletions(-)
hw/xen/xen_pt.h +3 -1
index 507165c..25147cf 100644
@@ -63,7 +63,7 @@ typedef int (*xen_pt_conf_byte_read)
 #define XEN_PT_BAR_UNMAPPED (-1)
 
 #define PCI_CAP_MAX 48
-
+#define PCI_INTEL_OPREGION 0xfc
 
 typedef enum {
     XEN_PT_GRP_TYPE_HARDWIRED = 0,  /* 0 Hardwired reg group */
@@ -306,5 +306,7 @@ int pci_create_pch(PCIBus *bus);
 void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
                    uint32_t val, int len);
 uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len);
+uint32_t igd_read_opregion(XenPCIPassthroughState *s);
+void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
 
 #endif /* !XEN_PT_H */
hw/xen/xen_pt_config_init.c +49 -1

80 lines not on this page · raw message

hw/xen/xen_pt_graphics.c +64 -0

85 lines not on this page · raw message

Signature · 1 line
1.9.1
#6 lore raw
In reply to Tiejun Chen

Please ignore this series since I have some typos to some email address :(

Sorry for any inconveniences.

Thanks
Tiejun

Quoted 80 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tiejun Chen
Sent: Monday, May 26, 2014 5:37 PM
To: [email protected]; [email protected]; [email protected]; [email protected]
Cc: [email protected]; [email protected]; Kay, Allen M; [email protected]; [email protected]; Zhang, Yang Z
Subject: [Qemu-devel] [v3][PATCH 0/8] xen: add Intel IGD passthrough support

v3:

* In this case, as we discussed we will give priority to devices to reserve a specific devfn by passing "device_model_args_hvm = ['-device', 'xen-platform,addr=0x3']" and "vga=none", so withdraw patch #1, #2 and #4.
* Fix some typos.
* Add more comments to make that readable.
* To unmap igd_opregion when call xen_pt_unregister_vga_regions().
* Improve some return paths.
* Force to convert igd_guest/host_opoegion as an unsigned long type while calling xc_domain_memory_mapping().
* We need to map 3 pages for opregion as hvmloader set.

v2:

* rebase on current qemu tree.
* retrieve VGA bios from sysfs properly.
* redefine some function name.
* introduce bitmap to manage registe/runregister pci dev, and provide a common way to reserve some specific devfn.
* introduce is_igd_passthrough() to make sure we touch physical host bridge only in IGD case.
* We should return zero as an invalid address value while calling igd_read_opregion().

Additionally, now its also not necessary to recompile seabios with some extra steps like v1.

The following patches are ported partially from Xen Qemu-traditional branch which are adding Intel IGD passthrough supporting to Qemu upstream.

To pass through IGD to guest, user need to add following lines in Xen config file:
gfx_passthru=1
pci=['00:02.0 <at> 2']

Now successfully boot Ubuntu 14.04 guests with IGD assigned in Haswell desktop with Latest Xen + Qemu upstream.

----------------------------------------------------------------
Tiejun Chen (2):
xen, gfx passthrough: create intel isa bridge xen, gfx passthrough: create host bridge to passthrough

Yang Zhang (3):
xen, gfx passthrough: basic graphics passthrough support xen, gfx passthrough: support Intel IGD passthrough with VT-D xen, gfx passthrough: add opregion mapping

 hw/pci-host/piix.c           |  56 +++++++++++++-
 hw/xen/Makefile.objs         |   2 +-
 hw/xen/xen-host-pci-device.c |   5 ++
 hw/xen/xen-host-pci-device.h |   1 +
 hw/xen/xen_pt.c              |  10 +++
 hw/xen/xen_pt.h              |  12 ++-
 hw/xen/xen_pt_config_init.c  |  50 ++++++++++++-
 hw/xen/xen_pt_graphics.c     | 518
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++
 qemu-options.hx              |   9 +++
 vl.c                         |  11 ++-
 10 files changed, 668 insertions(+), 6 deletions(-)  create mode 100644

hw/xen/xen_pt_graphics.c

Thanks
Tiejun