All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/5] xen: add Intel IGD passthrough support
@ 2014-02-21  6:44 ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

The following patches are ported 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@2']

Besides, since Xen + Qemu upstream is requiring seabios, user also need to
recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow IGD pass through
successfully:
1. change CONFIG_OPTIONROMS_DEPLOYED=y in file: xen/tools/firmware/seabios-config
2. recompile the tools

I have successfully boot Win 7 and RHEL6u4 guests with IGD assigned in Haswell
desktop with Latest Xen + Qemu upstream.

Yang Zhang (5):
  xen, gfx passthrough: basic graphics passthrough support
  xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
  xen, gfx passthrough: create intel isa bridge
  xen, gfx passthrough: support Intel IGD passthrough with VT-D
  xen, gfx passthrough: add opregion mapping

 configure                    |    2 +-
 hw/pci-host/piix.c           |   15 ++
 hw/pci/pci.c                 |   19 ++
 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              |   13 ++-
 hw/xen/xen_pt_config_init.c  |   45 +++++-
 hw/xen/xen_pt_graphics.c     |  407 ++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |    9 +
 vl.c                         |    8 +
 12 files changed, 532 insertions(+), 4 deletions(-)
 create mode 100644 hw/xen/xen_pt_graphics.c

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 0/5] xen: add Intel IGD passthrough support
@ 2014-02-21  6:44 ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

The following patches are ported 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@2']

Besides, since Xen + Qemu upstream is requiring seabios, user also need to
recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow IGD pass through
successfully:
1. change CONFIG_OPTIONROMS_DEPLOYED=y in file: xen/tools/firmware/seabios-config
2. recompile the tools

I have successfully boot Win 7 and RHEL6u4 guests with IGD assigned in Haswell
desktop with Latest Xen + Qemu upstream.

Yang Zhang (5):
  xen, gfx passthrough: basic graphics passthrough support
  xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
  xen, gfx passthrough: create intel isa bridge
  xen, gfx passthrough: support Intel IGD passthrough with VT-D
  xen, gfx passthrough: add opregion mapping

 configure                    |    2 +-
 hw/pci-host/piix.c           |   15 ++
 hw/pci/pci.c                 |   19 ++
 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              |   13 ++-
 hw/xen/xen_pt_config_init.c  |   45 +++++-
 hw/xen/xen_pt_graphics.c     |  407 ++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |    9 +
 vl.c                         |    8 +
 12 files changed, 532 insertions(+), 4 deletions(-)
 create mode 100644 hw/xen/xen_pt_graphics.c

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [Qemu-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
  2014-02-21  6:44 ` Yang Zhang
@ 2014-02-21  6:44   ` Yang Zhang
  -1 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

basic gfx passthrough support:
- add a vga type for gfx passthrough
- retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Weidong Han <weidong.han@intel.com>
---
 configure                    |    2 +-
 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     |  164 ++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |    9 +++
 vl.c                         |    8 ++
 9 files changed, 203 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen/xen_pt_graphics.c

diff --git a/configure b/configure
index 4648117..19525ab 100755
--- a/configure
+++ b/configure
@@ -4608,7 +4608,7 @@ case "$target_name" in
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
       echo "CONFIG_XEN=y" >> $config_target_mak
       if test "$xen_pci_passthrough" = yes; then
-        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
+        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_host_mak"
       fi
     fi
     ;;
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
index ce640c6..350d337 100644
--- a/hw/xen/Makefile.objs
+++ b/hw/xen/Makefile.objs
@@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
 
 obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
index 743b37b..a54b7de 100644
--- a/hw/xen/xen-host-pci-device.c
+++ b/hw/xen/xen-host-pci-device.c
@@ -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;
diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
index c2486f0..f1e1c30 100644
--- a/hw/xen/xen-host-pci-device.h
+++ b/hw/xen/xen-host-pci-device.h
@@ -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];
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index be4220b..5a36902 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -450,6 +450,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
                    d->rom.size, d->rom.base_addr);
     }
 
+    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);
     }
+
+    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 (setup_vga_pt(&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");
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 942dc60..c04bbfd 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -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 gfx_passthru;
+int register_vga_regions(XenHostPCIDevice *dev);
+int unregister_vga_regions(XenHostPCIDevice *dev);
+int setup_vga_pt(XenHostPCIDevice *dev);
 
 #endif /* !XEN_PT_H */
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
new file mode 100644
index 0000000..9ad8a74
--- /dev/null
+++ b/hw/xen/xen_pt_graphics.c
@@ -0,0 +1,164 @@
+/*
+ * graphics passthrough
+ */
+#include "xen_pt.h"
+#include "xen-host-pci-device.h"
+#include "hw/xen/xen_backend.h"
+
+/*
+ * register VGA resources for the domain with assigned gfx
+ */
+int register_vga_regions(XenHostPCIDevice *dev)
+{
+    int ret = 0;
+
+    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
+        return ret;
+    }
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
+            0x3B0, 0xA, DPCI_ADD_MAPPING);
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
+            0x3C0, 0x20, DPCI_ADD_MAPPING);
+
+    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0x20,
+            DPCI_ADD_MAPPING);
+
+    if (ret != 0) {
+        XEN_PT_ERR(NULL, "VGA region mapping failed\n");
+    }
+
+    return ret;
+}
+
+/*
+ * unregister VGA resources for the domain with assigned gfx
+ */
+int unregister_vga_regions(XenHostPCIDevice *dev)
+{
+    int ret = 0;
+
+    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
+        return ret;
+    }
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
+            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
+            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
+
+    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0xa0000 >> XC_PAGE_SHIFT,
+            20,
+            DPCI_REMOVE_MAPPING);
+
+    if (ret != 0) {
+        XEN_PT_ERR(NULL, "VGA region unmapping failed\n");
+    }
+
+    return ret;
+}
+
+static int get_vgabios(unsigned char *buf)
+{
+    int fd;
+    uint32_t bios_size = 0;
+    uint32_t start = 0xC0000;
+    uint16_t magic = 0;
+
+    fd = open("/dev/mem", O_RDONLY);
+    if (fd < 0) {
+        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
+        return 0;
+    }
+
+    /*
+     * Check if it a real bios extension.
+     * The magic number is 0xAA55.
+     */
+    if (start != lseek(fd, start, SEEK_SET)) {
+        goto out;
+    }
+    if (read(fd, &magic, 2) != 2) {
+        goto out;
+    }
+    if (magic != 0xAA55) {
+        goto out;
+    }
+
+    /* Find the size of the rom extension */
+    if (start != lseek(fd, start, SEEK_SET)) {
+        goto out;
+    }
+    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) {
+        goto out;
+    }
+    if (read(fd, &bios_size, 1) != 1) {
+        goto out;
+    }
+
+    /* This size is in 512 bytes */
+    bios_size *= 512;
+
+    /*
+     * Set the file to the begining of the rombios,
+     * to start the copy.
+     */
+    if (start != lseek(fd, start, SEEK_SET)) {
+        goto out;
+    }
+
+    if (bios_size != read(fd, buf, bios_size)) {
+        bios_size = 0;
+    }
+
+out:
+    close(fd);
+    return bios_size;
+}
+
+int setup_vga_pt(XenHostPCIDevice *dev)
+{
+    unsigned char *bios = NULL;
+    int bios_size = 0;
+    char *c = NULL;
+    char checksum = 0;
+    int rc = 0;
+
+    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
+        return rc;
+    }
+
+    bios = malloc(64 * 1024);
+    /* Allocated 64K for the vga bios */
+    if (!bios) {
+        return -1;
+    }
+
+    bios_size = get_vgabios(bios);
+    if (bios_size == 0 || bios_size > 64 * 1024) {
+        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
+        rc = -1;
+        goto out;
+    }
+
+    /* Adjust the bios checksum */
+    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
+        checksum += *c;
+    }
+    if (checksum) {
+        bios[bios_size - 1] -= checksum;
+        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
+    }
+
+    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
+out:
+    free(bios);
+    return rc;
+}
diff --git a/qemu-options.hx b/qemu-options.hx
index 56e5fdf..95de002 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1034,6 +1034,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|none]\n"
     "                select video card type\n", QEMU_ARCH_ALL)
diff --git a/vl.c b/vl.c
index 316de54..8a91054 100644
--- a/vl.c
+++ b/vl.c
@@ -215,6 +215,9 @@ static bool tcg_allowed = true;
 bool xen_allowed;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+int gfx_passthru = 0;
+#endif
 static int tcg_tb_size;
 
 static int default_serial = 1;
@@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
                 }
                 configure_msg(opts);
                 break;
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+            case QEMU_OPTION_gfx_passthru:
+                gfx_passthru = 1;
+                break;
+#endif
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
@ 2014-02-21  6:44   ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

basic gfx passthrough support:
- add a vga type for gfx passthrough
- retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Weidong Han <weidong.han@intel.com>
---
 configure                    |    2 +-
 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     |  164 ++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |    9 +++
 vl.c                         |    8 ++
 9 files changed, 203 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen/xen_pt_graphics.c

diff --git a/configure b/configure
index 4648117..19525ab 100755
--- a/configure
+++ b/configure
@@ -4608,7 +4608,7 @@ case "$target_name" in
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
       echo "CONFIG_XEN=y" >> $config_target_mak
       if test "$xen_pci_passthrough" = yes; then
-        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
+        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_host_mak"
       fi
     fi
     ;;
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
index ce640c6..350d337 100644
--- a/hw/xen/Makefile.objs
+++ b/hw/xen/Makefile.objs
@@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
 
 obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
index 743b37b..a54b7de 100644
--- a/hw/xen/xen-host-pci-device.c
+++ b/hw/xen/xen-host-pci-device.c
@@ -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;
diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
index c2486f0..f1e1c30 100644
--- a/hw/xen/xen-host-pci-device.h
+++ b/hw/xen/xen-host-pci-device.h
@@ -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];
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index be4220b..5a36902 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -450,6 +450,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
                    d->rom.size, d->rom.base_addr);
     }
 
+    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);
     }
+
+    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 (setup_vga_pt(&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");
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 942dc60..c04bbfd 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -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 gfx_passthru;
+int register_vga_regions(XenHostPCIDevice *dev);
+int unregister_vga_regions(XenHostPCIDevice *dev);
+int setup_vga_pt(XenHostPCIDevice *dev);
 
 #endif /* !XEN_PT_H */
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
new file mode 100644
index 0000000..9ad8a74
--- /dev/null
+++ b/hw/xen/xen_pt_graphics.c
@@ -0,0 +1,164 @@
+/*
+ * graphics passthrough
+ */
+#include "xen_pt.h"
+#include "xen-host-pci-device.h"
+#include "hw/xen/xen_backend.h"
+
+/*
+ * register VGA resources for the domain with assigned gfx
+ */
+int register_vga_regions(XenHostPCIDevice *dev)
+{
+    int ret = 0;
+
+    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
+        return ret;
+    }
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
+            0x3B0, 0xA, DPCI_ADD_MAPPING);
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
+            0x3C0, 0x20, DPCI_ADD_MAPPING);
+
+    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0x20,
+            DPCI_ADD_MAPPING);
+
+    if (ret != 0) {
+        XEN_PT_ERR(NULL, "VGA region mapping failed\n");
+    }
+
+    return ret;
+}
+
+/*
+ * unregister VGA resources for the domain with assigned gfx
+ */
+int unregister_vga_regions(XenHostPCIDevice *dev)
+{
+    int ret = 0;
+
+    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
+        return ret;
+    }
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
+            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
+
+    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
+            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
+
+    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0xa0000 >> XC_PAGE_SHIFT,
+            20,
+            DPCI_REMOVE_MAPPING);
+
+    if (ret != 0) {
+        XEN_PT_ERR(NULL, "VGA region unmapping failed\n");
+    }
+
+    return ret;
+}
+
+static int get_vgabios(unsigned char *buf)
+{
+    int fd;
+    uint32_t bios_size = 0;
+    uint32_t start = 0xC0000;
+    uint16_t magic = 0;
+
+    fd = open("/dev/mem", O_RDONLY);
+    if (fd < 0) {
+        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
+        return 0;
+    }
+
+    /*
+     * Check if it a real bios extension.
+     * The magic number is 0xAA55.
+     */
+    if (start != lseek(fd, start, SEEK_SET)) {
+        goto out;
+    }
+    if (read(fd, &magic, 2) != 2) {
+        goto out;
+    }
+    if (magic != 0xAA55) {
+        goto out;
+    }
+
+    /* Find the size of the rom extension */
+    if (start != lseek(fd, start, SEEK_SET)) {
+        goto out;
+    }
+    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) {
+        goto out;
+    }
+    if (read(fd, &bios_size, 1) != 1) {
+        goto out;
+    }
+
+    /* This size is in 512 bytes */
+    bios_size *= 512;
+
+    /*
+     * Set the file to the begining of the rombios,
+     * to start the copy.
+     */
+    if (start != lseek(fd, start, SEEK_SET)) {
+        goto out;
+    }
+
+    if (bios_size != read(fd, buf, bios_size)) {
+        bios_size = 0;
+    }
+
+out:
+    close(fd);
+    return bios_size;
+}
+
+int setup_vga_pt(XenHostPCIDevice *dev)
+{
+    unsigned char *bios = NULL;
+    int bios_size = 0;
+    char *c = NULL;
+    char checksum = 0;
+    int rc = 0;
+
+    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
+        return rc;
+    }
+
+    bios = malloc(64 * 1024);
+    /* Allocated 64K for the vga bios */
+    if (!bios) {
+        return -1;
+    }
+
+    bios_size = get_vgabios(bios);
+    if (bios_size == 0 || bios_size > 64 * 1024) {
+        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
+        rc = -1;
+        goto out;
+    }
+
+    /* Adjust the bios checksum */
+    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
+        checksum += *c;
+    }
+    if (checksum) {
+        bios[bios_size - 1] -= checksum;
+        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
+    }
+
+    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
+out:
+    free(bios);
+    return rc;
+}
diff --git a/qemu-options.hx b/qemu-options.hx
index 56e5fdf..95de002 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1034,6 +1034,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|none]\n"
     "                select video card type\n", QEMU_ARCH_ALL)
diff --git a/vl.c b/vl.c
index 316de54..8a91054 100644
--- a/vl.c
+++ b/vl.c
@@ -215,6 +215,9 @@ static bool tcg_allowed = true;
 bool xen_allowed;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+int gfx_passthru = 0;
+#endif
 static int tcg_tb_size;
 
 static int default_serial = 1;
@@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
                 }
                 configure_msg(opts);
                 break;
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+            case QEMU_OPTION_gfx_passthru:
+                gfx_passthru = 1;
+                break;
+#endif
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [Qemu-devel] [PATCH 2/5] xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
  2014-02-21  6:44 ` Yang Zhang
@ 2014-02-21  6:44   ` Yang Zhang
  -1 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

Some VBIOSs and drivers assume the IGD BDF (bus:device:function) is
always 00:02.0, so this patch reserves 00:02.0 for assigned IGD in
guest.

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

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Weidong Han <weidong.han@intel.com>
---
 hw/pci/pci.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4e0701d..e81816e 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -808,6 +808,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
             devfn += PCI_FUNC_MAX) {
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+            /* If gfx_passthru is in use, reserve 00:02.* for the IGD */
+            if (gfx_passthru && devfn == 0x10) {
+                continue;
+            }
+#endif
             if (!bus->devices[devfn])
                 goto found;
         }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 2/5] xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
@ 2014-02-21  6:44   ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

Some VBIOSs and drivers assume the IGD BDF (bus:device:function) is
always 00:02.0, so this patch reserves 00:02.0 for assigned IGD in
guest.

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

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Weidong Han <weidong.han@intel.com>
---
 hw/pci/pci.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4e0701d..e81816e 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -808,6 +808,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
             devfn += PCI_FUNC_MAX) {
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+            /* If gfx_passthru is in use, reserve 00:02.* for the IGD */
+            if (gfx_passthru && devfn == 0x10) {
+                continue;
+            }
+#endif
             if (!bus->devices[devfn])
                 goto found;
         }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [Qemu-devel] [PATCH 3/5] xen, gfx passthrough: create intel isa bridge
  2014-02-21  6:44 ` Yang Zhang
@ 2014-02-21  6:44   ` Yang Zhang
  -1 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

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 [allen.m.kay@intel.com]

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Allen Kay <allen.m.kay@intel.com>
---
 hw/xen/xen_pt_graphics.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 9ad8a74..54f16cf 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -162,3 +162,74 @@ out:
     free(bios);
     return rc;
 }
+
+static uint32_t isa_bridge_read_config(PCIDevice *d, uint32_t addr, int len)
+{
+    uint32_t v;
+
+    v = pci_default_read_config(d, addr, len);
+
+    return v;
+}
+
+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          = "inte-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), "inte-pch-isa-bridge");
+    if (!dev) {
+        XEN_PT_LOG(dev, "fail to create PCH ISA bridge.\n");
+        return -1;
+    }
+
+    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 is created.\n");
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 3/5] xen, gfx passthrough: create intel isa bridge
@ 2014-02-21  6:44   ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

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 [allen.m.kay@intel.com]

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Allen Kay <allen.m.kay@intel.com>
---
 hw/xen/xen_pt_graphics.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 9ad8a74..54f16cf 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -162,3 +162,74 @@ out:
     free(bios);
     return rc;
 }
+
+static uint32_t isa_bridge_read_config(PCIDevice *d, uint32_t addr, int len)
+{
+    uint32_t v;
+
+    v = pci_default_read_config(d, addr, len);
+
+    return v;
+}
+
+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          = "inte-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), "inte-pch-isa-bridge");
+    if (!dev) {
+        XEN_PT_LOG(dev, "fail to create PCH ISA bridge.\n");
+        return -1;
+    }
+
+    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 is created.\n");
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [Qemu-devel] [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D
  2014-02-21  6:44 ` Yang Zhang
@ 2014-02-21  6:44   ` Yang Zhang
  -1 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

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 >

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc:Weidong Han <weidong.han@intel.com>
---
 hw/pci-host/piix.c       |   15 ++++++
 hw/pci/pci.c             |   13 +++++
 hw/xen/xen_pt.h          |    5 ++
 hw/xen/xen_pt_graphics.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 160 insertions(+), 0 deletions(-)

diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index ffdc853..68cf756 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -34,6 +34,9 @@
 #include "sysemu/sysemu.h"
 #include "hw/i386/ioapic.h"
 #include "qapi/visitor.h"
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+#include "hw/xen/xen_pt.h"
+#endif
 
 /*
  * I440FX chipset data sheet.
@@ -389,6 +392,18 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
 
     i440fx_update_memory_mappings(f);
 
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+    /*
+     * 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.
+     */
+    if (intel_pch_init(b) == 0) {
+        d->config_read = igd_pci_read;
+        d->config_write = igd_pci_write;
+    }
+#endif
+
     return b;
 }
 
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e81816e..7016b71 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -36,6 +36,9 @@
 #include "hw/pci/msix.h"
 #include "exec/address-spaces.h"
 #include "hw/hotplug.h"
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+#include "hw/xen/xen_pt.h"
+#endif
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -805,6 +808,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     PCIConfigWriteFunc *config_write = pc->config_write;
     AddressSpace *dma_as;
 
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+    /*
+     * Some video bioses and gfx drivers will assume the bdf of IGD is 00:02.0.
+     * So user need to set it to 00:02.0 in Xen configure file explicitly,
+     * otherwise IGD will fail to work.
+     */
+    if (gfx_passthru && devfn == 0x10)
+        igd_passthru = 1;
+    else
+#endif
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
             devfn += PCI_FUNC_MAX) {
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index c04bbfd..92e4d51 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -299,8 +299,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
 }
 
 extern int gfx_passthru;
+extern int igd_passthru;
 int register_vga_regions(XenHostPCIDevice *dev);
 int unregister_vga_regions(XenHostPCIDevice *dev);
 int setup_vga_pt(XenHostPCIDevice *dev);
+int intel_pch_init(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 */
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 54f16cf..2a01406 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -5,6 +5,8 @@
 #include "xen-host-pci-device.h"
 #include "hw/xen/xen_backend.h"
 
+int igd_passthru;
+
 /*
  * register VGA resources for the domain with assigned gfx
  */
@@ -233,3 +235,128 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
     XEN_PT_LOG(dev, "Intel PCH ISA bridge is created.\n");
     return 0;
 }
+
+int intel_pch_init(PCIBus *bus)
+{
+    XenHostPCIDevice hdev;
+    int r = 0;
+
+    if (!gfx_passthru) {
+        return -1;
+    }
+
+    r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0);
+    if (r) {
+        XEN_PT_ERR(NULL, "Fail to find intel PCH in host\n");
+        goto err;
+    }
+
+    if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) {
+        r = create_pch_isa_bridge(bus, &hdev);
+        if (r) {
+            XEN_PT_ERR(NULL, "Fail to create PCH ISA bridge.\n");
+            goto err;
+        }
+    }
+
+    xen_host_pci_device_put(&hdev);
+
+    return  r;
+
+err:
+    return r;
+}
+
+void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
+                   uint32_t val, int len)
+{
+    XenHostPCIDevice dev;
+    int r;
+
+    assert(pci_dev->devfn == 0x00);
+
+    if (!igd_passthru) {
+        goto write_default;
+    }
+
+    switch (config_addr) {
+    case 0x58:      /* PAVPC Offset */
+        break;
+    default:
+        goto write_default;
+    }
+
+    /* Host write */
+    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
+    if (r) {
+        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
+        abort();
+    }
+
+    r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len);
+    if (r) {
+        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
+        abort();
+    }
+
+    xen_host_pci_device_put(&dev);
+
+    return;
+
+write_default:
+    pci_default_write_config(pci_dev, config_addr, val, len);
+}
+
+uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
+{
+    XenHostPCIDevice dev;
+    uint32_t val;
+    int r;
+
+    assert(pci_dev->devfn == 0x00);
+
+    if (!igd_passthru) {
+        goto read_default;
+    }
+
+    switch (config_addr) {
+    case 0x00:        /* vendor id */
+    case 0x02:        /* device id */
+    case 0x08:        /* revision id */
+    case 0x2c:        /* sybsystem vendor id */
+    case 0x2e:        /* sybsystem id */
+    case 0x50:        /* SNB: processor graphics control register */
+    case 0x52:        /* processor graphics control register */
+    case 0xa0:        /* top of memory */
+    case 0xb0:        /* ILK: BSM: should read from dev 2 offset 0x5c */
+    case 0x58:        /* SNB: PAVPC Offset */
+    case 0xa4:        /* SNB: graphics base of stolen memory */
+    case 0xa8:        /* SNB: base of GTT stolen memory */
+        break;
+    default:
+        goto read_default;
+    }
+
+    /* Host read */
+    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
+    if (r) {
+        goto err_out;
+    }
+
+    r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len);
+    if (r) {
+        goto err_out;
+    }
+
+    xen_host_pci_device_put(&dev);
+
+    return val;
+
+read_default:
+    return pci_default_read_config(pci_dev, config_addr, len);
+
+err_out:
+    XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
+    return -1;
+}
+
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D
@ 2014-02-21  6:44   ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

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 >

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc:Weidong Han <weidong.han@intel.com>
---
 hw/pci-host/piix.c       |   15 ++++++
 hw/pci/pci.c             |   13 +++++
 hw/xen/xen_pt.h          |    5 ++
 hw/xen/xen_pt_graphics.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 160 insertions(+), 0 deletions(-)

diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index ffdc853..68cf756 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -34,6 +34,9 @@
 #include "sysemu/sysemu.h"
 #include "hw/i386/ioapic.h"
 #include "qapi/visitor.h"
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+#include "hw/xen/xen_pt.h"
+#endif
 
 /*
  * I440FX chipset data sheet.
@@ -389,6 +392,18 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
 
     i440fx_update_memory_mappings(f);
 
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+    /*
+     * 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.
+     */
+    if (intel_pch_init(b) == 0) {
+        d->config_read = igd_pci_read;
+        d->config_write = igd_pci_write;
+    }
+#endif
+
     return b;
 }
 
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e81816e..7016b71 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -36,6 +36,9 @@
 #include "hw/pci/msix.h"
 #include "exec/address-spaces.h"
 #include "hw/hotplug.h"
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+#include "hw/xen/xen_pt.h"
+#endif
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -805,6 +808,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     PCIConfigWriteFunc *config_write = pc->config_write;
     AddressSpace *dma_as;
 
+#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
+    /*
+     * Some video bioses and gfx drivers will assume the bdf of IGD is 00:02.0.
+     * So user need to set it to 00:02.0 in Xen configure file explicitly,
+     * otherwise IGD will fail to work.
+     */
+    if (gfx_passthru && devfn == 0x10)
+        igd_passthru = 1;
+    else
+#endif
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
             devfn += PCI_FUNC_MAX) {
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index c04bbfd..92e4d51 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -299,8 +299,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
 }
 
 extern int gfx_passthru;
+extern int igd_passthru;
 int register_vga_regions(XenHostPCIDevice *dev);
 int unregister_vga_regions(XenHostPCIDevice *dev);
 int setup_vga_pt(XenHostPCIDevice *dev);
+int intel_pch_init(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 */
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 54f16cf..2a01406 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -5,6 +5,8 @@
 #include "xen-host-pci-device.h"
 #include "hw/xen/xen_backend.h"
 
+int igd_passthru;
+
 /*
  * register VGA resources for the domain with assigned gfx
  */
@@ -233,3 +235,128 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
     XEN_PT_LOG(dev, "Intel PCH ISA bridge is created.\n");
     return 0;
 }
+
+int intel_pch_init(PCIBus *bus)
+{
+    XenHostPCIDevice hdev;
+    int r = 0;
+
+    if (!gfx_passthru) {
+        return -1;
+    }
+
+    r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0);
+    if (r) {
+        XEN_PT_ERR(NULL, "Fail to find intel PCH in host\n");
+        goto err;
+    }
+
+    if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) {
+        r = create_pch_isa_bridge(bus, &hdev);
+        if (r) {
+            XEN_PT_ERR(NULL, "Fail to create PCH ISA bridge.\n");
+            goto err;
+        }
+    }
+
+    xen_host_pci_device_put(&hdev);
+
+    return  r;
+
+err:
+    return r;
+}
+
+void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
+                   uint32_t val, int len)
+{
+    XenHostPCIDevice dev;
+    int r;
+
+    assert(pci_dev->devfn == 0x00);
+
+    if (!igd_passthru) {
+        goto write_default;
+    }
+
+    switch (config_addr) {
+    case 0x58:      /* PAVPC Offset */
+        break;
+    default:
+        goto write_default;
+    }
+
+    /* Host write */
+    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
+    if (r) {
+        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
+        abort();
+    }
+
+    r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len);
+    if (r) {
+        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
+        abort();
+    }
+
+    xen_host_pci_device_put(&dev);
+
+    return;
+
+write_default:
+    pci_default_write_config(pci_dev, config_addr, val, len);
+}
+
+uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
+{
+    XenHostPCIDevice dev;
+    uint32_t val;
+    int r;
+
+    assert(pci_dev->devfn == 0x00);
+
+    if (!igd_passthru) {
+        goto read_default;
+    }
+
+    switch (config_addr) {
+    case 0x00:        /* vendor id */
+    case 0x02:        /* device id */
+    case 0x08:        /* revision id */
+    case 0x2c:        /* sybsystem vendor id */
+    case 0x2e:        /* sybsystem id */
+    case 0x50:        /* SNB: processor graphics control register */
+    case 0x52:        /* processor graphics control register */
+    case 0xa0:        /* top of memory */
+    case 0xb0:        /* ILK: BSM: should read from dev 2 offset 0x5c */
+    case 0x58:        /* SNB: PAVPC Offset */
+    case 0xa4:        /* SNB: graphics base of stolen memory */
+    case 0xa8:        /* SNB: base of GTT stolen memory */
+        break;
+    default:
+        goto read_default;
+    }
+
+    /* Host read */
+    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
+    if (r) {
+        goto err_out;
+    }
+
+    r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len);
+    if (r) {
+        goto err_out;
+    }
+
+    xen_host_pci_device_put(&dev);
+
+    return val;
+
+read_default:
+    return pci_default_read_config(pci_dev, config_addr, len);
+
+err_out:
+    XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
+    return -1;
+}
+
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [Qemu-devel] [PATCH 5/5] xen, gfx passthrough: add opregion mapping
  2014-02-21  6:44 ` Yang Zhang
@ 2014-02-21  6:44   ` Yang Zhang
  -1 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

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 <jean.guyader@eu.citrix.com>

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Jean Guyader <jean.guyader@eu.citrix.com>
---
 hw/xen/xen_pt.h             |    4 ++-
 hw/xen/xen_pt_config_init.c |   45 ++++++++++++++++++++++++++++++++++++++++++-
 hw/xen/xen_pt_graphics.c    |   45 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 92e4d51..9f7fd4e 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -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 */
@@ -307,5 +307,7 @@ int intel_pch_init(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 */
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index 8ccc2e4..30135c1 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -575,6 +575,22 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
     return 0;
 }
 
+static int xen_pt_intel_opregion_read(XenPCIPassthroughState *s,
+                                      XenPTReg *cfg_entry,
+                                      uint32_t *value, uint32_t valid_mask)
+{
+    *value = igd_read_opregion(s);
+    return 0;
+}
+
+static int xen_pt_intel_opregion_write(XenPCIPassthroughState *s,
+                                       XenPTReg *cfg_entry, uint32_t *value,
+                                       uint32_t dev_value, uint32_t valid_mask)
+{
+    igd_write_opregion(s, *value);
+    return 0;
+}
+
 /* Header Type0 reg static information table */
 static XenPTRegInfo xen_pt_emu_reg_header0[] = {
     /* Vendor ID reg */
@@ -1438,6 +1454,20 @@ static XenPTRegInfo xen_pt_emu_reg_msix[] = {
     },
 };
 
+static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
+    /* Intel IGFX OpRegion reg */
+    {
+        .offset     = 0x0,
+        .size       = 4,
+        .init_val   = 0,
+        .no_wb      = 1,
+        .u.dw.read   = xen_pt_intel_opregion_read,
+        .u.dw.write  = xen_pt_intel_opregion_write,
+    },
+    {
+        .size = 0,
+    },
+};
 
 /****************************
  * Capabilities
@@ -1675,6 +1705,14 @@ static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
         .size_init   = xen_pt_msix_size_init,
         .emu_regs = xen_pt_emu_reg_msix,
     },
+    /* Intel IGD Opregion group */
+    {
+        .grp_id      = PCI_INTEL_OPREGION,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0x4,
+        .size_init   = xen_pt_reg_grp_size_init,
+        .emu_regs    = xen_pt_emu_reg_igd_opregion,
+    },
     {
         .grp_size = 0,
     },
@@ -1804,7 +1842,8 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
         uint32_t reg_grp_offset = 0;
         XenPTRegGroup *reg_grp_entry = NULL;
 
-        if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) {
+        if (xen_pt_emu_reg_grps[i].grp_id != 0xFF
+            && xen_pt_emu_reg_grps[i].grp_id != PCI_INTEL_OPREGION) {
             if (xen_pt_hide_dev_cap(&s->real_device,
                                     xen_pt_emu_reg_grps[i].grp_id)) {
                 continue;
@@ -1817,6 +1856,10 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
             }
         }
 
+        if (xen_pt_emu_reg_grps[i].grp_id == PCI_INTEL_OPREGION) {
+            reg_grp_offset = PCI_INTEL_OPREGION;
+        }
+
         reg_grp_entry = g_new0(XenPTRegGroup, 1);
         QLIST_INIT(&reg_grp_entry->reg_tbl_list);
         QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 2a01406..bebfcfd 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -6,6 +6,7 @@
 #include "hw/xen/xen_backend.h"
 
 int igd_passthru;
+static int igd_guest_opregion;
 
 /*
  * register VGA resources for the domain with assigned gfx
@@ -360,3 +361,47 @@ err_out:
     return -1;
 }
 
+uint32_t igd_read_opregion(XenPCIPassthroughState *s)
+{
+    uint32_t val = -1;
+
+    if (igd_guest_opregion == 0) {
+        return val;
+    }
+
+    val = igd_guest_opregion;
+
+    XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
+    return val;
+}
+
+void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
+{
+    uint32_t host_opregion = 0;
+    int ret;
+
+    if (igd_guest_opregion) {
+        XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
+                   val);
+        return;
+    }
+
+    xen_host_pci_get_block(&s->real_device, PCI_INTEL_OPREGION,
+            (uint8_t *)&host_opregion, 4);
+    igd_guest_opregion = (val & ~0xfff) | (host_opregion & 0xfff);
+
+    ret = xc_domain_memory_mapping(xen_xc, xen_domid,
+            igd_guest_opregion >> XC_PAGE_SHIFT,
+            host_opregion >> XC_PAGE_SHIFT,
+            2,
+            DPCI_ADD_MAPPING);
+
+    if (ret != 0) {
+        XEN_PT_ERR(&s->dev, "Error: Can't map opregion\n");
+        igd_guest_opregion = 0;
+        return;
+    }
+
+    XEN_PT_LOG(&s->dev, "Map OpRegion: %x -> %x\n", host_opregion,
+            igd_guest_opregion);
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 5/5] xen, gfx passthrough: add opregion mapping
@ 2014-02-21  6:44   ` Yang Zhang
  0 siblings, 0 replies; 32+ messages in thread
From: Yang Zhang @ 2014-02-21  6:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, jean.guyader, Yang Zhang, anthony, anthony.perard

From: Yang Zhang <yang.z.zhang@Intel.com>

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 <jean.guyader@eu.citrix.com>

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Cc: Jean Guyader <jean.guyader@eu.citrix.com>
---
 hw/xen/xen_pt.h             |    4 ++-
 hw/xen/xen_pt_config_init.c |   45 ++++++++++++++++++++++++++++++++++++++++++-
 hw/xen/xen_pt_graphics.c    |   45 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 92e4d51..9f7fd4e 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -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 */
@@ -307,5 +307,7 @@ int intel_pch_init(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 */
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index 8ccc2e4..30135c1 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -575,6 +575,22 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
     return 0;
 }
 
+static int xen_pt_intel_opregion_read(XenPCIPassthroughState *s,
+                                      XenPTReg *cfg_entry,
+                                      uint32_t *value, uint32_t valid_mask)
+{
+    *value = igd_read_opregion(s);
+    return 0;
+}
+
+static int xen_pt_intel_opregion_write(XenPCIPassthroughState *s,
+                                       XenPTReg *cfg_entry, uint32_t *value,
+                                       uint32_t dev_value, uint32_t valid_mask)
+{
+    igd_write_opregion(s, *value);
+    return 0;
+}
+
 /* Header Type0 reg static information table */
 static XenPTRegInfo xen_pt_emu_reg_header0[] = {
     /* Vendor ID reg */
@@ -1438,6 +1454,20 @@ static XenPTRegInfo xen_pt_emu_reg_msix[] = {
     },
 };
 
+static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
+    /* Intel IGFX OpRegion reg */
+    {
+        .offset     = 0x0,
+        .size       = 4,
+        .init_val   = 0,
+        .no_wb      = 1,
+        .u.dw.read   = xen_pt_intel_opregion_read,
+        .u.dw.write  = xen_pt_intel_opregion_write,
+    },
+    {
+        .size = 0,
+    },
+};
 
 /****************************
  * Capabilities
@@ -1675,6 +1705,14 @@ static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
         .size_init   = xen_pt_msix_size_init,
         .emu_regs = xen_pt_emu_reg_msix,
     },
+    /* Intel IGD Opregion group */
+    {
+        .grp_id      = PCI_INTEL_OPREGION,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0x4,
+        .size_init   = xen_pt_reg_grp_size_init,
+        .emu_regs    = xen_pt_emu_reg_igd_opregion,
+    },
     {
         .grp_size = 0,
     },
@@ -1804,7 +1842,8 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
         uint32_t reg_grp_offset = 0;
         XenPTRegGroup *reg_grp_entry = NULL;
 
-        if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) {
+        if (xen_pt_emu_reg_grps[i].grp_id != 0xFF
+            && xen_pt_emu_reg_grps[i].grp_id != PCI_INTEL_OPREGION) {
             if (xen_pt_hide_dev_cap(&s->real_device,
                                     xen_pt_emu_reg_grps[i].grp_id)) {
                 continue;
@@ -1817,6 +1856,10 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
             }
         }
 
+        if (xen_pt_emu_reg_grps[i].grp_id == PCI_INTEL_OPREGION) {
+            reg_grp_offset = PCI_INTEL_OPREGION;
+        }
+
         reg_grp_entry = g_new0(XenPTRegGroup, 1);
         QLIST_INIT(&reg_grp_entry->reg_tbl_list);
         QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 2a01406..bebfcfd 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -6,6 +6,7 @@
 #include "hw/xen/xen_backend.h"
 
 int igd_passthru;
+static int igd_guest_opregion;
 
 /*
  * register VGA resources for the domain with assigned gfx
@@ -360,3 +361,47 @@ err_out:
     return -1;
 }
 
+uint32_t igd_read_opregion(XenPCIPassthroughState *s)
+{
+    uint32_t val = -1;
+
+    if (igd_guest_opregion == 0) {
+        return val;
+    }
+
+    val = igd_guest_opregion;
+
+    XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
+    return val;
+}
+
+void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
+{
+    uint32_t host_opregion = 0;
+    int ret;
+
+    if (igd_guest_opregion) {
+        XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
+                   val);
+        return;
+    }
+
+    xen_host_pci_get_block(&s->real_device, PCI_INTEL_OPREGION,
+            (uint8_t *)&host_opregion, 4);
+    igd_guest_opregion = (val & ~0xfff) | (host_opregion & 0xfff);
+
+    ret = xc_domain_memory_mapping(xen_xc, xen_domid,
+            igd_guest_opregion >> XC_PAGE_SHIFT,
+            host_opregion >> XC_PAGE_SHIFT,
+            2,
+            DPCI_ADD_MAPPING);
+
+    if (ret != 0) {
+        XEN_PT_ERR(&s->dev, "Error: Can't map opregion\n");
+        igd_guest_opregion = 0;
+        return;
+    }
+
+    XEN_PT_LOG(&s->dev, "Map OpRegion: %x -> %x\n", host_opregion,
+            igd_guest_opregion);
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] xen: add Intel IGD passthrough support
  2014-02-21  6:44 ` Yang Zhang
@ 2014-02-27  5:38   ` Zhang, Yang Z
  -1 siblings, 0 replies; 32+ messages in thread
From: Zhang, Yang Z @ 2014-02-27  5:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, Kay, Allen M,
	anthony, anthony.perard

Zhang, Yang Z wrote on 2014-02-21:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> The following patches are ported 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@2']
> 
> Besides, since Xen + Qemu upstream is requiring seabios, user also
> need to recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow
> IGD pass through
> successfully:
> 1. change CONFIG_OPTIONROMS_DEPLOYED=y in file:
> xen/tools/firmware/seabios-config 2. recompile the tools
> 
> I have successfully boot Win 7 and RHEL6u4 guests with IGD assigned in
> Haswell desktop with Latest Xen + Qemu upstream.
> 
> Yang Zhang (5):
>   xen, gfx passthrough: basic graphics passthrough support
>   xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
>   xen, gfx passthrough: create intel isa bridge
>   xen, gfx passthrough: support Intel IGD passthrough with VT-D
>   xen, gfx passthrough: add opregion mapping
>  configure                    |    2 +- hw/pci-host/piix.c           |  
>  15 ++ hw/pci/pci.c                 |   19 ++ 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              |   13 ++-
>  hw/xen/xen_pt_config_init.c  |   45 +++++- hw/xen/xen_pt_graphics.c    
>  |  407 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx      
>         |    9 + vl.c                         |    8 + 12 files changed,
>  532 insertions(+), 4 deletions(-)  create mode
> 100644 hw/xen/xen_pt_graphics.c

Ping.

Best regards,
Yang

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 0/5] xen: add Intel IGD passthrough support
@ 2014-02-27  5:38   ` Zhang, Yang Z
  0 siblings, 0 replies; 32+ messages in thread
From: Zhang, Yang Z @ 2014-02-27  5:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, Kay, Allen M,
	anthony, anthony.perard

Zhang, Yang Z wrote on 2014-02-21:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> The following patches are ported 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@2']
> 
> Besides, since Xen + Qemu upstream is requiring seabios, user also
> need to recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow
> IGD pass through
> successfully:
> 1. change CONFIG_OPTIONROMS_DEPLOYED=y in file:
> xen/tools/firmware/seabios-config 2. recompile the tools
> 
> I have successfully boot Win 7 and RHEL6u4 guests with IGD assigned in
> Haswell desktop with Latest Xen + Qemu upstream.
> 
> Yang Zhang (5):
>   xen, gfx passthrough: basic graphics passthrough support
>   xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
>   xen, gfx passthrough: create intel isa bridge
>   xen, gfx passthrough: support Intel IGD passthrough with VT-D
>   xen, gfx passthrough: add opregion mapping
>  configure                    |    2 +- hw/pci-host/piix.c           |  
>  15 ++ hw/pci/pci.c                 |   19 ++ 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              |   13 ++-
>  hw/xen/xen_pt_config_init.c  |   45 +++++- hw/xen/xen_pt_graphics.c    
>  |  407 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx      
>         |    9 + vl.c                         |    8 + 12 files changed,
>  532 insertions(+), 4 deletions(-)  create mode
> 100644 hw/xen/xen_pt_graphics.c

Ping.

Best regards,
Yang

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] xen: add Intel IGD passthrough support
  2014-02-27  5:38   ` Zhang, Yang Z
@ 2014-02-27 12:47     ` Stefano Stabellini
  -1 siblings, 0 replies; 32+ messages in thread
From: Stefano Stabellini @ 2014-02-27 12:47 UTC (permalink / raw)
  To: Zhang, Yang Z
  Cc: peter.maydell, xen-devel, stefano.stabellini, Kay, Allen M,
	qemu-devel, anthony, anthony.perard

On Thu, 27 Feb 2014, Zhang, Yang Z wrote:
> Zhang, Yang Z wrote on 2014-02-21:
> > From: Yang Zhang <yang.z.zhang@Intel.com>
> > 
> > The following patches are ported 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@2']
> > 
> > Besides, since Xen + Qemu upstream is requiring seabios, user also
> > need to recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow
> > IGD pass through
> > successfully:
> > 1. change CONFIG_OPTIONROMS_DEPLOYED=y in file:
> > xen/tools/firmware/seabios-config 2. recompile the tools
> > 
> > I have successfully boot Win 7 and RHEL6u4 guests with IGD assigned in
> > Haswell desktop with Latest Xen + Qemu upstream.
> > 
> > Yang Zhang (5):
> >   xen, gfx passthrough: basic graphics passthrough support
> >   xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
> >   xen, gfx passthrough: create intel isa bridge
> >   xen, gfx passthrough: support Intel IGD passthrough with VT-D
> >   xen, gfx passthrough: add opregion mapping
> >  configure                    |    2 +- hw/pci-host/piix.c           |  
> >  15 ++ hw/pci/pci.c                 |   19 ++ 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              |   13 ++-
> >  hw/xen/xen_pt_config_init.c  |   45 +++++- hw/xen/xen_pt_graphics.c    
> >  |  407 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx      
> >         |    9 + vl.c                         |    8 + 12 files changed,
> >  532 insertions(+), 4 deletions(-)  create mode
> > 100644 hw/xen/xen_pt_graphics.c
> 
> Ping.

Sorry but with the Xen 4.4 release and travels I won't be able to review
it for a while, but I'll get around to it at some point not too far.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 0/5] xen: add Intel IGD passthrough support
@ 2014-02-27 12:47     ` Stefano Stabellini
  0 siblings, 0 replies; 32+ messages in thread
From: Stefano Stabellini @ 2014-02-27 12:47 UTC (permalink / raw)
  To: Zhang, Yang Z
  Cc: peter.maydell, xen-devel, stefano.stabellini, Kay, Allen M,
	qemu-devel, anthony, anthony.perard

On Thu, 27 Feb 2014, Zhang, Yang Z wrote:
> Zhang, Yang Z wrote on 2014-02-21:
> > From: Yang Zhang <yang.z.zhang@Intel.com>
> > 
> > The following patches are ported 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@2']
> > 
> > Besides, since Xen + Qemu upstream is requiring seabios, user also
> > need to recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow
> > IGD pass through
> > successfully:
> > 1. change CONFIG_OPTIONROMS_DEPLOYED=y in file:
> > xen/tools/firmware/seabios-config 2. recompile the tools
> > 
> > I have successfully boot Win 7 and RHEL6u4 guests with IGD assigned in
> > Haswell desktop with Latest Xen + Qemu upstream.
> > 
> > Yang Zhang (5):
> >   xen, gfx passthrough: basic graphics passthrough support
> >   xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
> >   xen, gfx passthrough: create intel isa bridge
> >   xen, gfx passthrough: support Intel IGD passthrough with VT-D
> >   xen, gfx passthrough: add opregion mapping
> >  configure                    |    2 +- hw/pci-host/piix.c           |  
> >  15 ++ hw/pci/pci.c                 |   19 ++ 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              |   13 ++-
> >  hw/xen/xen_pt_config_init.c  |   45 +++++- hw/xen/xen_pt_graphics.c    
> >  |  407 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx      
> >         |    9 + vl.c                         |    8 + 12 files changed,
> >  532 insertions(+), 4 deletions(-)  create mode
> > 100644 hw/xen/xen_pt_graphics.c
> 
> Ping.

Sorry but with the Xen 4.4 release and travels I won't be able to review
it for a while, but I'll get around to it at some point not too far.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
  2014-02-21  6:44   ` Yang Zhang
@ 2014-03-21 16:24     ` Anthony PERARD
  -1 siblings, 0 replies; 32+ messages in thread
From: Anthony PERARD @ 2014-03-21 16:24 UTC (permalink / raw)
  To: Yang Zhang
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, qemu-devel, jean.guyader, anthony

On Fri, Feb 21, 2014 at 02:44:09PM +0800, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> basic gfx passthrough support:
> - add a vga type for gfx passthrough
> - retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc: Weidong Han <weidong.han@intel.com>
> ---
>  configure                    |    2 +-
>  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     |  164 ++++++++++++++++++++++++++++++++++++++++++
>  qemu-options.hx              |    9 +++
>  vl.c                         |    8 ++
>  9 files changed, 203 insertions(+), 2 deletions(-)
>  create mode 100644 hw/xen/xen_pt_graphics.c
> 
> diff --git a/configure b/configure
> index 4648117..19525ab 100755
> --- a/configure
> +++ b/configure
> @@ -4608,7 +4608,7 @@ case "$target_name" in
>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
>        echo "CONFIG_XEN=y" >> $config_target_mak
>        if test "$xen_pci_passthrough" = yes; then
> -        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
> +        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_host_mak"

Why do you need to move this option from config_target to config_host?

>        fi
>      fi
>      ;;
> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
> index ce640c6..350d337 100644
> --- a/hw/xen/Makefile.objs
> +++ b/hw/xen/Makefile.objs
> @@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
>  
>  obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
> diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
> index 743b37b..a54b7de 100644
> --- a/hw/xen/xen-host-pci-device.c
> +++ b/hw/xen/xen-host-pci-device.c
> @@ -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;
> diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
> index c2486f0..f1e1c30 100644
> --- a/hw/xen/xen-host-pci-device.h
> +++ b/hw/xen/xen-host-pci-device.h
> @@ -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];
> diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
> index be4220b..5a36902 100644
> --- a/hw/xen/xen_pt.c
> +++ b/hw/xen/xen_pt.c
> @@ -450,6 +450,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
>                     d->rom.size, d->rom.base_addr);
>      }
>  
> +    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);
>      }
> +
> +    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 (setup_vga_pt(&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");
> diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
> index 942dc60..c04bbfd 100644
> --- a/hw/xen/xen_pt.h
> +++ b/hw/xen/xen_pt.h
> @@ -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 gfx_passthru;
> +int register_vga_regions(XenHostPCIDevice *dev);
> +int unregister_vga_regions(XenHostPCIDevice *dev);
> +int setup_vga_pt(XenHostPCIDevice *dev);

I believe those function names need to be prefix with xen_pt_
(e.g. xen_pt_register_vga_regions).

>  #endif /* !XEN_PT_H */
> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
> new file mode 100644
> index 0000000..9ad8a74
> --- /dev/null
> +++ b/hw/xen/xen_pt_graphics.c
> @@ -0,0 +1,164 @@
> +/*
> + * graphics passthrough
> + */
> +#include "xen_pt.h"
> +#include "xen-host-pci-device.h"
> +#include "hw/xen/xen_backend.h"
> +
> +/*
> + * register VGA resources for the domain with assigned gfx
> + */
> +int register_vga_regions(XenHostPCIDevice *dev)
> +{
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {

Instead of 0x0300, you can use PCI_CLASS_DISPLAY_VGA. The same apply to
the few other places.

> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xA, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0x20,
> +            DPCI_ADD_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region mapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +/*
> + * unregister VGA resources for the domain with assigned gfx
> + */
> +int unregister_vga_regions(XenHostPCIDevice *dev)
> +{
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            20,
> +            DPCI_REMOVE_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region unmapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +static int get_vgabios(unsigned char *buf)
> +{
> +    int fd;
> +    uint32_t bios_size = 0;
> +    uint32_t start = 0xC0000;
> +    uint16_t magic = 0;
> +
> +    fd = open("/dev/mem", O_RDONLY);
> +    if (fd < 0) {
> +        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
> +        return 0;
> +    }
> +
> +    /*
> +     * Check if it a real bios extension.
> +     * The magic number is 0xAA55.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (read(fd, &magic, 2) != 2) {
> +        goto out;
> +    }
> +    if (magic != 0xAA55) {
> +        goto out;
> +    }
> +
> +    /* Find the size of the rom extension */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) {
> +        goto out;
> +    }
> +    if (read(fd, &bios_size, 1) != 1) {
> +        goto out;
> +    }
> +
> +    /* This size is in 512 bytes */
> +    bios_size *= 512;
> +
> +    /*
> +     * Set the file to the begining of the rombios,
> +     * to start the copy.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +
> +    if (bios_size != read(fd, buf, bios_size)) {
> +        bios_size = 0;
> +    }
> +
> +out:
> +    close(fd);
> +    return bios_size;
> +}
> +
> +int setup_vga_pt(XenHostPCIDevice *dev)
> +{
> +    unsigned char *bios = NULL;
> +    int bios_size = 0;
> +    char *c = NULL;
> +    char checksum = 0;
> +    int rc = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return rc;
> +    }
> +
> +    bios = malloc(64 * 1024);

I think g_malloc should be used here, instead of malloc, and g_malloc
always return an allocated buffer. (it never fail, or it don't return)

> +    /* Allocated 64K for the vga bios */
> +    if (!bios) {
> +        return -1;
> +    }
> +
> +    bios_size = get_vgabios(bios);
> +    if (bios_size == 0 || bios_size > 64 * 1024) {
> +        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
> +        rc = -1;
> +        goto out;
> +    }
> +
> +    /* Adjust the bios checksum */
> +    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
> +        checksum += *c;
> +    }
> +    if (checksum) {
> +        bios[bios_size - 1] -= checksum;
> +        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
> +    }
> +
> +    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
> +out:
> +    free(bios);
> +    return rc;
> +}
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 56e5fdf..95de002 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1034,6 +1034,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
> +

Is this options really necessary?  If someone is passing-through a
graphic card, he propably want to pass it through as a graphic card,
without having to enable yet another option.

>  DEF("vga", HAS_ARG, QEMU_OPTION_vga,
>      "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
>      "                select video card type\n", QEMU_ARCH_ALL)
> diff --git a/vl.c b/vl.c
> index 316de54..8a91054 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -215,6 +215,9 @@ static bool tcg_allowed = true;
>  bool xen_allowed;
>  uint32_t xen_domid;
>  enum xen_mode xen_mode = XEN_EMULATE;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +int gfx_passthru = 0;
> +#endif
>  static int tcg_tb_size;
>  
>  static int default_serial = 1;
> @@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
>                  }
>                  configure_msg(opts);
>                  break;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +            case QEMU_OPTION_gfx_passthru:
> +                gfx_passthru = 1;
> +                break;
> +#endif
>              default:
>                  os_parse_cmd_args(popt->index, optarg);
>              }

-- 
Anthony PERARD

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
@ 2014-03-21 16:24     ` Anthony PERARD
  0 siblings, 0 replies; 32+ messages in thread
From: Anthony PERARD @ 2014-03-21 16:24 UTC (permalink / raw)
  To: Yang Zhang
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, qemu-devel, jean.guyader, anthony

On Fri, Feb 21, 2014 at 02:44:09PM +0800, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> basic gfx passthrough support:
> - add a vga type for gfx passthrough
> - retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc: Weidong Han <weidong.han@intel.com>
> ---
>  configure                    |    2 +-
>  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     |  164 ++++++++++++++++++++++++++++++++++++++++++
>  qemu-options.hx              |    9 +++
>  vl.c                         |    8 ++
>  9 files changed, 203 insertions(+), 2 deletions(-)
>  create mode 100644 hw/xen/xen_pt_graphics.c
> 
> diff --git a/configure b/configure
> index 4648117..19525ab 100755
> --- a/configure
> +++ b/configure
> @@ -4608,7 +4608,7 @@ case "$target_name" in
>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
>        echo "CONFIG_XEN=y" >> $config_target_mak
>        if test "$xen_pci_passthrough" = yes; then
> -        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
> +        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_host_mak"

Why do you need to move this option from config_target to config_host?

>        fi
>      fi
>      ;;
> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
> index ce640c6..350d337 100644
> --- a/hw/xen/Makefile.objs
> +++ b/hw/xen/Makefile.objs
> @@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
>  
>  obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
> diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
> index 743b37b..a54b7de 100644
> --- a/hw/xen/xen-host-pci-device.c
> +++ b/hw/xen/xen-host-pci-device.c
> @@ -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;
> diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
> index c2486f0..f1e1c30 100644
> --- a/hw/xen/xen-host-pci-device.h
> +++ b/hw/xen/xen-host-pci-device.h
> @@ -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];
> diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
> index be4220b..5a36902 100644
> --- a/hw/xen/xen_pt.c
> +++ b/hw/xen/xen_pt.c
> @@ -450,6 +450,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
>                     d->rom.size, d->rom.base_addr);
>      }
>  
> +    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);
>      }
> +
> +    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 (setup_vga_pt(&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");
> diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
> index 942dc60..c04bbfd 100644
> --- a/hw/xen/xen_pt.h
> +++ b/hw/xen/xen_pt.h
> @@ -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 gfx_passthru;
> +int register_vga_regions(XenHostPCIDevice *dev);
> +int unregister_vga_regions(XenHostPCIDevice *dev);
> +int setup_vga_pt(XenHostPCIDevice *dev);

I believe those function names need to be prefix with xen_pt_
(e.g. xen_pt_register_vga_regions).

>  #endif /* !XEN_PT_H */
> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
> new file mode 100644
> index 0000000..9ad8a74
> --- /dev/null
> +++ b/hw/xen/xen_pt_graphics.c
> @@ -0,0 +1,164 @@
> +/*
> + * graphics passthrough
> + */
> +#include "xen_pt.h"
> +#include "xen-host-pci-device.h"
> +#include "hw/xen/xen_backend.h"
> +
> +/*
> + * register VGA resources for the domain with assigned gfx
> + */
> +int register_vga_regions(XenHostPCIDevice *dev)
> +{
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {

Instead of 0x0300, you can use PCI_CLASS_DISPLAY_VGA. The same apply to
the few other places.

> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xA, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0x20,
> +            DPCI_ADD_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region mapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +/*
> + * unregister VGA resources for the domain with assigned gfx
> + */
> +int unregister_vga_regions(XenHostPCIDevice *dev)
> +{
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            20,
> +            DPCI_REMOVE_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region unmapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +static int get_vgabios(unsigned char *buf)
> +{
> +    int fd;
> +    uint32_t bios_size = 0;
> +    uint32_t start = 0xC0000;
> +    uint16_t magic = 0;
> +
> +    fd = open("/dev/mem", O_RDONLY);
> +    if (fd < 0) {
> +        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
> +        return 0;
> +    }
> +
> +    /*
> +     * Check if it a real bios extension.
> +     * The magic number is 0xAA55.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (read(fd, &magic, 2) != 2) {
> +        goto out;
> +    }
> +    if (magic != 0xAA55) {
> +        goto out;
> +    }
> +
> +    /* Find the size of the rom extension */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) {
> +        goto out;
> +    }
> +    if (read(fd, &bios_size, 1) != 1) {
> +        goto out;
> +    }
> +
> +    /* This size is in 512 bytes */
> +    bios_size *= 512;
> +
> +    /*
> +     * Set the file to the begining of the rombios,
> +     * to start the copy.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +
> +    if (bios_size != read(fd, buf, bios_size)) {
> +        bios_size = 0;
> +    }
> +
> +out:
> +    close(fd);
> +    return bios_size;
> +}
> +
> +int setup_vga_pt(XenHostPCIDevice *dev)
> +{
> +    unsigned char *bios = NULL;
> +    int bios_size = 0;
> +    char *c = NULL;
> +    char checksum = 0;
> +    int rc = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return rc;
> +    }
> +
> +    bios = malloc(64 * 1024);

I think g_malloc should be used here, instead of malloc, and g_malloc
always return an allocated buffer. (it never fail, or it don't return)

> +    /* Allocated 64K for the vga bios */
> +    if (!bios) {
> +        return -1;
> +    }
> +
> +    bios_size = get_vgabios(bios);
> +    if (bios_size == 0 || bios_size > 64 * 1024) {
> +        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
> +        rc = -1;
> +        goto out;
> +    }
> +
> +    /* Adjust the bios checksum */
> +    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
> +        checksum += *c;
> +    }
> +    if (checksum) {
> +        bios[bios_size - 1] -= checksum;
> +        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
> +    }
> +
> +    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
> +out:
> +    free(bios);
> +    return rc;
> +}
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 56e5fdf..95de002 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1034,6 +1034,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
> +

Is this options really necessary?  If someone is passing-through a
graphic card, he propably want to pass it through as a graphic card,
without having to enable yet another option.

>  DEF("vga", HAS_ARG, QEMU_OPTION_vga,
>      "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
>      "                select video card type\n", QEMU_ARCH_ALL)
> diff --git a/vl.c b/vl.c
> index 316de54..8a91054 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -215,6 +215,9 @@ static bool tcg_allowed = true;
>  bool xen_allowed;
>  uint32_t xen_domid;
>  enum xen_mode xen_mode = XEN_EMULATE;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +int gfx_passthru = 0;
> +#endif
>  static int tcg_tb_size;
>  
>  static int default_serial = 1;
> @@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
>                  }
>                  configure_msg(opts);
>                  break;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +            case QEMU_OPTION_gfx_passthru:
> +                gfx_passthru = 1;
> +                break;
> +#endif
>              default:
>                  os_parse_cmd_args(popt->index, optarg);
>              }

-- 
Anthony PERARD

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 2/5] xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
  2014-02-21  6:44   ` Yang Zhang
@ 2014-03-21 17:26     ` Anthony PERARD
  -1 siblings, 0 replies; 32+ messages in thread
From: Anthony PERARD @ 2014-03-21 17:26 UTC (permalink / raw)
  To: Yang Zhang
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, qemu-devel, jean.guyader, anthony

On Fri, Feb 21, 2014 at 02:44:10PM +0800, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> Some VBIOSs and drivers assume the IGD BDF (bus:device:function) is
> always 00:02.0, so this patch reserves 00:02.0 for assigned IGD in
> guest.
> 
> The original patch is from Weidong Han <weidong.han@intel.com>
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc: Weidong Han <weidong.han@intel.com>
> ---
>  hw/pci/pci.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)
> 
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 4e0701d..e81816e 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -808,6 +808,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
>      if (devfn < 0) {
>          for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
>              devfn += PCI_FUNC_MAX) {
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +            /* If gfx_passthru is in use, reserve 00:02.* for the IGD */
> +            if (gfx_passthru && devfn == 0x10) {
> +                continue;
> +            }
> +#endif
>              if (!bus->devices[devfn])
>                  goto found;
>          }

This does not look quite right, there is maybe another way to reserve a
devfn.

-- 
Anthony PERARD

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 2/5] xen, gfx passthrough: reserve 00:02.0 for INTEL IGD
@ 2014-03-21 17:26     ` Anthony PERARD
  0 siblings, 0 replies; 32+ messages in thread
From: Anthony PERARD @ 2014-03-21 17:26 UTC (permalink / raw)
  To: Yang Zhang
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, qemu-devel, jean.guyader, anthony

On Fri, Feb 21, 2014 at 02:44:10PM +0800, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> Some VBIOSs and drivers assume the IGD BDF (bus:device:function) is
> always 00:02.0, so this patch reserves 00:02.0 for assigned IGD in
> guest.
> 
> The original patch is from Weidong Han <weidong.han@intel.com>
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc: Weidong Han <weidong.han@intel.com>
> ---
>  hw/pci/pci.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)
> 
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 4e0701d..e81816e 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -808,6 +808,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
>      if (devfn < 0) {
>          for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
>              devfn += PCI_FUNC_MAX) {
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +            /* If gfx_passthru is in use, reserve 00:02.* for the IGD */
> +            if (gfx_passthru && devfn == 0x10) {
> +                continue;
> +            }
> +#endif
>              if (!bus->devices[devfn])
>                  goto found;
>          }

This does not look quite right, there is maybe another way to reserve a
devfn.

-- 
Anthony PERARD

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D
  2014-02-21  6:44   ` Yang Zhang
@ 2014-03-27 18:21     ` Stefano Stabellini
  -1 siblings, 0 replies; 32+ messages in thread
From: Stefano Stabellini @ 2014-03-27 18:21 UTC (permalink / raw)
  To: mst
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, qemu-devel, yang.z.zhang, Anthony Liguori,
	anthony.perard

CC'ing Michael.

On Fri, 21 Feb 2014, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> 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 >
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc:Weidong Han <weidong.han@intel.com>
> ---
>  hw/pci-host/piix.c       |   15 ++++++
>  hw/pci/pci.c             |   13 +++++
>  hw/xen/xen_pt.h          |    5 ++
>  hw/xen/xen_pt_graphics.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 160 insertions(+), 0 deletions(-)
> 
> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> index ffdc853..68cf756 100644
> --- a/hw/pci-host/piix.c
> +++ b/hw/pci-host/piix.c
> @@ -34,6 +34,9 @@
>  #include "sysemu/sysemu.h"
>  #include "hw/i386/ioapic.h"
>  #include "qapi/visitor.h"
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +#include "hw/xen/xen_pt.h"
> +#endif
>  
>  /*
>   * I440FX chipset data sheet.
> @@ -389,6 +392,18 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
>  
>      i440fx_update_memory_mappings(f);
>  
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +    /*
> +     * 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.
> +     */
> +    if (intel_pch_init(b) == 0) {
> +        d->config_read = igd_pci_read;
> +        d->config_write = igd_pci_write;
> +    }
> +#endif

I can't see the other QEMU maintainers being happy with these changes.
Michael, do you have a suggestion on how to do this in a better way?


>      return b;
>  }
>  
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index e81816e..7016b71 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -36,6 +36,9 @@
>  #include "hw/pci/msix.h"
>  #include "exec/address-spaces.h"
>  #include "hw/hotplug.h"
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +#include "hw/xen/xen_pt.h"
> +#endif
>  
>  //#define DEBUG_PCI
>  #ifdef DEBUG_PCI
> @@ -805,6 +808,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
>      PCIConfigWriteFunc *config_write = pc->config_write;
>      AddressSpace *dma_as;
>  
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +    /*
> +     * Some video bioses and gfx drivers will assume the bdf of IGD is 00:02.0.
> +     * So user need to set it to 00:02.0 in Xen configure file explicitly,
> +     * otherwise IGD will fail to work.
> +     */
> +    if (gfx_passthru && devfn == 0x10)
> +        igd_passthru = 1;
> +    else
> +#endif
>      if (devfn < 0) {
>          for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
>              devfn += PCI_FUNC_MAX) {

Same here


> diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
> index c04bbfd..92e4d51 100644
> --- a/hw/xen/xen_pt.h
> +++ b/hw/xen/xen_pt.h
> @@ -299,8 +299,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
>  }
>  
>  extern int gfx_passthru;
> +extern int igd_passthru;
>  int register_vga_regions(XenHostPCIDevice *dev);
>  int unregister_vga_regions(XenHostPCIDevice *dev);
>  int setup_vga_pt(XenHostPCIDevice *dev);
> +int intel_pch_init(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 */
> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
> index 54f16cf..2a01406 100644
> --- a/hw/xen/xen_pt_graphics.c
> +++ b/hw/xen/xen_pt_graphics.c
> @@ -5,6 +5,8 @@
>  #include "xen-host-pci-device.h"
>  #include "hw/xen/xen_backend.h"
>  
> +int igd_passthru;
> +
>  /*
>   * register VGA resources for the domain with assigned gfx
>   */
> @@ -233,3 +235,128 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
>      XEN_PT_LOG(dev, "Intel PCH ISA bridge is created.\n");
>      return 0;
>  }
> +
> +int intel_pch_init(PCIBus *bus)
> +{
> +    XenHostPCIDevice hdev;
> +    int r = 0;
> +
> +    if (!gfx_passthru) {
> +        return -1;
> +    }
> +
> +    r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0);
> +    if (r) {
> +        XEN_PT_ERR(NULL, "Fail to find intel PCH in host\n");
> +        goto err;
> +    }
> +
> +    if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) {
> +        r = create_pch_isa_bridge(bus, &hdev);
> +        if (r) {
> +            XEN_PT_ERR(NULL, "Fail to create PCH ISA bridge.\n");
> +            goto err;
> +        }
> +    }
> +
> +    xen_host_pci_device_put(&hdev);
> +
> +    return  r;
> +
> +err:
> +    return r;
> +}
> +
> +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
> +                   uint32_t val, int len)
> +{
> +    XenHostPCIDevice dev;
> +    int r;
> +
> +    assert(pci_dev->devfn == 0x00);
> +
> +    if (!igd_passthru) {
> +        goto write_default;
> +    }
> +
> +    switch (config_addr) {
> +    case 0x58:      /* PAVPC Offset */
> +        break;
> +    default:
> +        goto write_default;
> +    }
> +
> +    /* Host write */
> +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> +    if (r) {
> +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> +        abort();
> +    }
> +
> +    r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len);
> +    if (r) {
> +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> +        abort();
> +    }
> +
> +    xen_host_pci_device_put(&dev);
> +
> +    return;
> +
> +write_default:
> +    pci_default_write_config(pci_dev, config_addr, val, len);
> +}
> +
> +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
> +{
> +    XenHostPCIDevice dev;
> +    uint32_t val;
> +    int r;
> +
> +    assert(pci_dev->devfn == 0x00);
> +
> +    if (!igd_passthru) {
> +        goto read_default;
> +    }
> +
> +    switch (config_addr) {
> +    case 0x00:        /* vendor id */
> +    case 0x02:        /* device id */
> +    case 0x08:        /* revision id */
> +    case 0x2c:        /* sybsystem vendor id */
> +    case 0x2e:        /* sybsystem id */
> +    case 0x50:        /* SNB: processor graphics control register */
> +    case 0x52:        /* processor graphics control register */
> +    case 0xa0:        /* top of memory */
> +    case 0xb0:        /* ILK: BSM: should read from dev 2 offset 0x5c */
> +    case 0x58:        /* SNB: PAVPC Offset */
> +    case 0xa4:        /* SNB: graphics base of stolen memory */
> +    case 0xa8:        /* SNB: base of GTT stolen memory */
> +        break;
> +    default:
> +        goto read_default;
> +    }
> +
> +    /* Host read */
> +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> +    if (r) {
> +        goto err_out;
> +    }
> +
> +    r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len);
> +    if (r) {
> +        goto err_out;
> +    }
> +
> +    xen_host_pci_device_put(&dev);
> +
> +    return val;
> +
> +read_default:
> +    return pci_default_read_config(pci_dev, config_addr, len);
> +
> +err_out:
> +    XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> +    return -1;
> +}

The Xen specific part is OK.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D
@ 2014-03-27 18:21     ` Stefano Stabellini
  0 siblings, 0 replies; 32+ messages in thread
From: Stefano Stabellini @ 2014-03-27 18:21 UTC (permalink / raw)
  To: mst
  Cc: peter.maydell, xen-devel, stefano.stabellini, allen.m.kay,
	weidong.han, qemu-devel, yang.z.zhang, Anthony Liguori,
	anthony.perard

CC'ing Michael.

On Fri, 21 Feb 2014, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> 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 >
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc:Weidong Han <weidong.han@intel.com>
> ---
>  hw/pci-host/piix.c       |   15 ++++++
>  hw/pci/pci.c             |   13 +++++
>  hw/xen/xen_pt.h          |    5 ++
>  hw/xen/xen_pt_graphics.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 160 insertions(+), 0 deletions(-)
> 
> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> index ffdc853..68cf756 100644
> --- a/hw/pci-host/piix.c
> +++ b/hw/pci-host/piix.c
> @@ -34,6 +34,9 @@
>  #include "sysemu/sysemu.h"
>  #include "hw/i386/ioapic.h"
>  #include "qapi/visitor.h"
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +#include "hw/xen/xen_pt.h"
> +#endif
>  
>  /*
>   * I440FX chipset data sheet.
> @@ -389,6 +392,18 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
>  
>      i440fx_update_memory_mappings(f);
>  
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +    /*
> +     * 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.
> +     */
> +    if (intel_pch_init(b) == 0) {
> +        d->config_read = igd_pci_read;
> +        d->config_write = igd_pci_write;
> +    }
> +#endif

I can't see the other QEMU maintainers being happy with these changes.
Michael, do you have a suggestion on how to do this in a better way?


>      return b;
>  }
>  
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index e81816e..7016b71 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -36,6 +36,9 @@
>  #include "hw/pci/msix.h"
>  #include "exec/address-spaces.h"
>  #include "hw/hotplug.h"
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +#include "hw/xen/xen_pt.h"
> +#endif
>  
>  //#define DEBUG_PCI
>  #ifdef DEBUG_PCI
> @@ -805,6 +808,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
>      PCIConfigWriteFunc *config_write = pc->config_write;
>      AddressSpace *dma_as;
>  
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +    /*
> +     * Some video bioses and gfx drivers will assume the bdf of IGD is 00:02.0.
> +     * So user need to set it to 00:02.0 in Xen configure file explicitly,
> +     * otherwise IGD will fail to work.
> +     */
> +    if (gfx_passthru && devfn == 0x10)
> +        igd_passthru = 1;
> +    else
> +#endif
>      if (devfn < 0) {
>          for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
>              devfn += PCI_FUNC_MAX) {

Same here


> diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
> index c04bbfd..92e4d51 100644
> --- a/hw/xen/xen_pt.h
> +++ b/hw/xen/xen_pt.h
> @@ -299,8 +299,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
>  }
>  
>  extern int gfx_passthru;
> +extern int igd_passthru;
>  int register_vga_regions(XenHostPCIDevice *dev);
>  int unregister_vga_regions(XenHostPCIDevice *dev);
>  int setup_vga_pt(XenHostPCIDevice *dev);
> +int intel_pch_init(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 */
> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
> index 54f16cf..2a01406 100644
> --- a/hw/xen/xen_pt_graphics.c
> +++ b/hw/xen/xen_pt_graphics.c
> @@ -5,6 +5,8 @@
>  #include "xen-host-pci-device.h"
>  #include "hw/xen/xen_backend.h"
>  
> +int igd_passthru;
> +
>  /*
>   * register VGA resources for the domain with assigned gfx
>   */
> @@ -233,3 +235,128 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
>      XEN_PT_LOG(dev, "Intel PCH ISA bridge is created.\n");
>      return 0;
>  }
> +
> +int intel_pch_init(PCIBus *bus)
> +{
> +    XenHostPCIDevice hdev;
> +    int r = 0;
> +
> +    if (!gfx_passthru) {
> +        return -1;
> +    }
> +
> +    r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0);
> +    if (r) {
> +        XEN_PT_ERR(NULL, "Fail to find intel PCH in host\n");
> +        goto err;
> +    }
> +
> +    if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) {
> +        r = create_pch_isa_bridge(bus, &hdev);
> +        if (r) {
> +            XEN_PT_ERR(NULL, "Fail to create PCH ISA bridge.\n");
> +            goto err;
> +        }
> +    }
> +
> +    xen_host_pci_device_put(&hdev);
> +
> +    return  r;
> +
> +err:
> +    return r;
> +}
> +
> +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
> +                   uint32_t val, int len)
> +{
> +    XenHostPCIDevice dev;
> +    int r;
> +
> +    assert(pci_dev->devfn == 0x00);
> +
> +    if (!igd_passthru) {
> +        goto write_default;
> +    }
> +
> +    switch (config_addr) {
> +    case 0x58:      /* PAVPC Offset */
> +        break;
> +    default:
> +        goto write_default;
> +    }
> +
> +    /* Host write */
> +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> +    if (r) {
> +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> +        abort();
> +    }
> +
> +    r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len);
> +    if (r) {
> +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> +        abort();
> +    }
> +
> +    xen_host_pci_device_put(&dev);
> +
> +    return;
> +
> +write_default:
> +    pci_default_write_config(pci_dev, config_addr, val, len);
> +}
> +
> +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
> +{
> +    XenHostPCIDevice dev;
> +    uint32_t val;
> +    int r;
> +
> +    assert(pci_dev->devfn == 0x00);
> +
> +    if (!igd_passthru) {
> +        goto read_default;
> +    }
> +
> +    switch (config_addr) {
> +    case 0x00:        /* vendor id */
> +    case 0x02:        /* device id */
> +    case 0x08:        /* revision id */
> +    case 0x2c:        /* sybsystem vendor id */
> +    case 0x2e:        /* sybsystem id */
> +    case 0x50:        /* SNB: processor graphics control register */
> +    case 0x52:        /* processor graphics control register */
> +    case 0xa0:        /* top of memory */
> +    case 0xb0:        /* ILK: BSM: should read from dev 2 offset 0x5c */
> +    case 0x58:        /* SNB: PAVPC Offset */
> +    case 0xa4:        /* SNB: graphics base of stolen memory */
> +    case 0xa8:        /* SNB: base of GTT stolen memory */
> +        break;
> +    default:
> +        goto read_default;
> +    }
> +
> +    /* Host read */
> +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> +    if (r) {
> +        goto err_out;
> +    }
> +
> +    r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len);
> +    if (r) {
> +        goto err_out;
> +    }
> +
> +    xen_host_pci_device_put(&dev);
> +
> +    return val;
> +
> +read_default:
> +    return pci_default_read_config(pci_dev, config_addr, len);
> +
> +err_out:
> +    XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> +    return -1;
> +}

The Xen specific part is OK.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D
  2014-03-27 18:21     ` Stefano Stabellini
@ 2014-03-27 19:10       ` Michael S. Tsirkin
  -1 siblings, 0 replies; 32+ messages in thread
From: Michael S. Tsirkin @ 2014-03-27 19:10 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: peter.maydell, xen-devel, allen.m.kay, weidong.han, qemu-devel,
	yang.z.zhang, Anthony Liguori, anthony.perard

On Thu, Mar 27, 2014 at 06:21:08PM +0000, Stefano Stabellini wrote:
> CC'ing Michael.
> 
> On Fri, 21 Feb 2014, Yang Zhang wrote:
> > From: Yang Zhang <yang.z.zhang@Intel.com>
> > 
> > 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 >
> > 
> > Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> > Cc:Weidong Han <weidong.han@intel.com>
> > ---
> >  hw/pci-host/piix.c       |   15 ++++++
> >  hw/pci/pci.c             |   13 +++++
> >  hw/xen/xen_pt.h          |    5 ++
> >  hw/xen/xen_pt_graphics.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 160 insertions(+), 0 deletions(-)
> > 
> > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > index ffdc853..68cf756 100644
> > --- a/hw/pci-host/piix.c
> > +++ b/hw/pci-host/piix.c
> > @@ -34,6 +34,9 @@
> >  #include "sysemu/sysemu.h"
> >  #include "hw/i386/ioapic.h"
> >  #include "qapi/visitor.h"
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +#include "hw/xen/xen_pt.h"
> > +#endif
> >  
> >  /*
> >   * I440FX chipset data sheet.
> > @@ -389,6 +392,18 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> >  
> >      i440fx_update_memory_mappings(f);
> >  
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +    /*
> > +     * 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.
> > +     */
> > +    if (intel_pch_init(b) == 0) {
> > +        d->config_read = igd_pci_read;
> > +        d->config_write = igd_pci_write;
> > +    }
> > +#endif
> 
> I can't see the other QEMU maintainers being happy with these changes.
> Michael, do you have a suggestion on how to do this in a better way?

Implement your own pci host bridge, inherit the standard one.


> 
> >      return b;
> >  }
> >  
> > diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> > index e81816e..7016b71 100644
> > --- a/hw/pci/pci.c
> > +++ b/hw/pci/pci.c
> > @@ -36,6 +36,9 @@
> >  #include "hw/pci/msix.h"
> >  #include "exec/address-spaces.h"
> >  #include "hw/hotplug.h"
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +#include "hw/xen/xen_pt.h"
> > +#endif
> >  
> >  //#define DEBUG_PCI
> >  #ifdef DEBUG_PCI
> > @@ -805,6 +808,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
> >      PCIConfigWriteFunc *config_write = pc->config_write;
> >      AddressSpace *dma_as;
> >  
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +    /*
> > +     * Some video bioses and gfx drivers will assume the bdf of IGD is 00:02.0.
> > +     * So user need to set it to 00:02.0 in Xen configure file explicitly,
> > +     * otherwise IGD will fail to work.
> > +     */
> > +    if (gfx_passthru && devfn == 0x10)
> > +        igd_passthru = 1;
> > +    else
> > +#endif
> >      if (devfn < 0) {
> >          for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
> >              devfn += PCI_FUNC_MAX) {
> 
> Same here
> 

So just set the address property to 00:02.0.


> > diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
> > index c04bbfd..92e4d51 100644
> > --- a/hw/xen/xen_pt.h
> > +++ b/hw/xen/xen_pt.h
> > @@ -299,8 +299,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
> >  }
> >  
> >  extern int gfx_passthru;
> > +extern int igd_passthru;
> >  int register_vga_regions(XenHostPCIDevice *dev);
> >  int unregister_vga_regions(XenHostPCIDevice *dev);
> >  int setup_vga_pt(XenHostPCIDevice *dev);
> > +int intel_pch_init(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 */
> > diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
> > index 54f16cf..2a01406 100644
> > --- a/hw/xen/xen_pt_graphics.c
> > +++ b/hw/xen/xen_pt_graphics.c
> > @@ -5,6 +5,8 @@
> >  #include "xen-host-pci-device.h"
> >  #include "hw/xen/xen_backend.h"
> >  
> > +int igd_passthru;
> > +
> >  /*
> >   * register VGA resources for the domain with assigned gfx
> >   */
> > @@ -233,3 +235,128 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
> >      XEN_PT_LOG(dev, "Intel PCH ISA bridge is created.\n");
> >      return 0;
> >  }
> > +
> > +int intel_pch_init(PCIBus *bus)
> > +{
> > +    XenHostPCIDevice hdev;
> > +    int r = 0;
> > +
> > +    if (!gfx_passthru) {
> > +        return -1;
> > +    }
> > +
> > +    r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0);
> > +    if (r) {
> > +        XEN_PT_ERR(NULL, "Fail to find intel PCH in host\n");
> > +        goto err;
> > +    }
> > +
> > +    if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) {
> > +        r = create_pch_isa_bridge(bus, &hdev);
> > +        if (r) {
> > +            XEN_PT_ERR(NULL, "Fail to create PCH ISA bridge.\n");
> > +            goto err;
> > +        }
> > +    }
> > +
> > +    xen_host_pci_device_put(&hdev);
> > +
> > +    return  r;
> > +
> > +err:
> > +    return r;
> > +}
> > +
> > +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
> > +                   uint32_t val, int len)
> > +{
> > +    XenHostPCIDevice dev;
> > +    int r;
> > +
> > +    assert(pci_dev->devfn == 0x00);
> > +
> > +    if (!igd_passthru) {
> > +        goto write_default;
> > +    }
> > +
> > +    switch (config_addr) {
> > +    case 0x58:      /* PAVPC Offset */
> > +        break;
> > +    default:
> > +        goto write_default;
> > +    }
> > +
> > +    /* Host write */
> > +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> > +    if (r) {
> > +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> > +        abort();
> > +    }
> > +
> > +    r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len);
> > +    if (r) {
> > +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> > +        abort();
> > +    }
> > +
> > +    xen_host_pci_device_put(&dev);
> > +
> > +    return;
> > +
> > +write_default:
> > +    pci_default_write_config(pci_dev, config_addr, val, len);
> > +}
> > +
> > +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
> > +{
> > +    XenHostPCIDevice dev;
> > +    uint32_t val;
> > +    int r;
> > +
> > +    assert(pci_dev->devfn == 0x00);
> > +
> > +    if (!igd_passthru) {
> > +        goto read_default;
> > +    }
> > +
> > +    switch (config_addr) {
> > +    case 0x00:        /* vendor id */
> > +    case 0x02:        /* device id */
> > +    case 0x08:        /* revision id */
> > +    case 0x2c:        /* sybsystem vendor id */
> > +    case 0x2e:        /* sybsystem id */
> > +    case 0x50:        /* SNB: processor graphics control register */
> > +    case 0x52:        /* processor graphics control register */
> > +    case 0xa0:        /* top of memory */
> > +    case 0xb0:        /* ILK: BSM: should read from dev 2 offset 0x5c */
> > +    case 0x58:        /* SNB: PAVPC Offset */
> > +    case 0xa4:        /* SNB: graphics base of stolen memory */
> > +    case 0xa8:        /* SNB: base of GTT stolen memory */
> > +        break;
> > +    default:
> > +        goto read_default;
> > +    }
> > +
> > +    /* Host read */
> > +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> > +    if (r) {
> > +        goto err_out;
> > +    }
> > +
> > +    r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len);
> > +    if (r) {
> > +        goto err_out;
> > +    }
> > +
> > +    xen_host_pci_device_put(&dev);
> > +
> > +    return val;
> > +
> > +read_default:
> > +    return pci_default_read_config(pci_dev, config_addr, len);
> > +
> > +err_out:
> > +    XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> > +    return -1;
> > +}
> 
> The Xen specific part is OK.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D
@ 2014-03-27 19:10       ` Michael S. Tsirkin
  0 siblings, 0 replies; 32+ messages in thread
From: Michael S. Tsirkin @ 2014-03-27 19:10 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: peter.maydell, xen-devel, allen.m.kay, weidong.han, qemu-devel,
	yang.z.zhang, Anthony Liguori, anthony.perard

On Thu, Mar 27, 2014 at 06:21:08PM +0000, Stefano Stabellini wrote:
> CC'ing Michael.
> 
> On Fri, 21 Feb 2014, Yang Zhang wrote:
> > From: Yang Zhang <yang.z.zhang@Intel.com>
> > 
> > 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 >
> > 
> > Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> > Cc:Weidong Han <weidong.han@intel.com>
> > ---
> >  hw/pci-host/piix.c       |   15 ++++++
> >  hw/pci/pci.c             |   13 +++++
> >  hw/xen/xen_pt.h          |    5 ++
> >  hw/xen/xen_pt_graphics.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 160 insertions(+), 0 deletions(-)
> > 
> > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > index ffdc853..68cf756 100644
> > --- a/hw/pci-host/piix.c
> > +++ b/hw/pci-host/piix.c
> > @@ -34,6 +34,9 @@
> >  #include "sysemu/sysemu.h"
> >  #include "hw/i386/ioapic.h"
> >  #include "qapi/visitor.h"
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +#include "hw/xen/xen_pt.h"
> > +#endif
> >  
> >  /*
> >   * I440FX chipset data sheet.
> > @@ -389,6 +392,18 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> >  
> >      i440fx_update_memory_mappings(f);
> >  
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +    /*
> > +     * 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.
> > +     */
> > +    if (intel_pch_init(b) == 0) {
> > +        d->config_read = igd_pci_read;
> > +        d->config_write = igd_pci_write;
> > +    }
> > +#endif
> 
> I can't see the other QEMU maintainers being happy with these changes.
> Michael, do you have a suggestion on how to do this in a better way?

Implement your own pci host bridge, inherit the standard one.


> 
> >      return b;
> >  }
> >  
> > diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> > index e81816e..7016b71 100644
> > --- a/hw/pci/pci.c
> > +++ b/hw/pci/pci.c
> > @@ -36,6 +36,9 @@
> >  #include "hw/pci/msix.h"
> >  #include "exec/address-spaces.h"
> >  #include "hw/hotplug.h"
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +#include "hw/xen/xen_pt.h"
> > +#endif
> >  
> >  //#define DEBUG_PCI
> >  #ifdef DEBUG_PCI
> > @@ -805,6 +808,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
> >      PCIConfigWriteFunc *config_write = pc->config_write;
> >      AddressSpace *dma_as;
> >  
> > +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> > +    /*
> > +     * Some video bioses and gfx drivers will assume the bdf of IGD is 00:02.0.
> > +     * So user need to set it to 00:02.0 in Xen configure file explicitly,
> > +     * otherwise IGD will fail to work.
> > +     */
> > +    if (gfx_passthru && devfn == 0x10)
> > +        igd_passthru = 1;
> > +    else
> > +#endif
> >      if (devfn < 0) {
> >          for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
> >              devfn += PCI_FUNC_MAX) {
> 
> Same here
> 

So just set the address property to 00:02.0.


> > diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
> > index c04bbfd..92e4d51 100644
> > --- a/hw/xen/xen_pt.h
> > +++ b/hw/xen/xen_pt.h
> > @@ -299,8 +299,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
> >  }
> >  
> >  extern int gfx_passthru;
> > +extern int igd_passthru;
> >  int register_vga_regions(XenHostPCIDevice *dev);
> >  int unregister_vga_regions(XenHostPCIDevice *dev);
> >  int setup_vga_pt(XenHostPCIDevice *dev);
> > +int intel_pch_init(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 */
> > diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
> > index 54f16cf..2a01406 100644
> > --- a/hw/xen/xen_pt_graphics.c
> > +++ b/hw/xen/xen_pt_graphics.c
> > @@ -5,6 +5,8 @@
> >  #include "xen-host-pci-device.h"
> >  #include "hw/xen/xen_backend.h"
> >  
> > +int igd_passthru;
> > +
> >  /*
> >   * register VGA resources for the domain with assigned gfx
> >   */
> > @@ -233,3 +235,128 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev)
> >      XEN_PT_LOG(dev, "Intel PCH ISA bridge is created.\n");
> >      return 0;
> >  }
> > +
> > +int intel_pch_init(PCIBus *bus)
> > +{
> > +    XenHostPCIDevice hdev;
> > +    int r = 0;
> > +
> > +    if (!gfx_passthru) {
> > +        return -1;
> > +    }
> > +
> > +    r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0);
> > +    if (r) {
> > +        XEN_PT_ERR(NULL, "Fail to find intel PCH in host\n");
> > +        goto err;
> > +    }
> > +
> > +    if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) {
> > +        r = create_pch_isa_bridge(bus, &hdev);
> > +        if (r) {
> > +            XEN_PT_ERR(NULL, "Fail to create PCH ISA bridge.\n");
> > +            goto err;
> > +        }
> > +    }
> > +
> > +    xen_host_pci_device_put(&hdev);
> > +
> > +    return  r;
> > +
> > +err:
> > +    return r;
> > +}
> > +
> > +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr,
> > +                   uint32_t val, int len)
> > +{
> > +    XenHostPCIDevice dev;
> > +    int r;
> > +
> > +    assert(pci_dev->devfn == 0x00);
> > +
> > +    if (!igd_passthru) {
> > +        goto write_default;
> > +    }
> > +
> > +    switch (config_addr) {
> > +    case 0x58:      /* PAVPC Offset */
> > +        break;
> > +    default:
> > +        goto write_default;
> > +    }
> > +
> > +    /* Host write */
> > +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> > +    if (r) {
> > +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> > +        abort();
> > +    }
> > +
> > +    r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len);
> > +    if (r) {
> > +        XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> > +        abort();
> > +    }
> > +
> > +    xen_host_pci_device_put(&dev);
> > +
> > +    return;
> > +
> > +write_default:
> > +    pci_default_write_config(pci_dev, config_addr, val, len);
> > +}
> > +
> > +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
> > +{
> > +    XenHostPCIDevice dev;
> > +    uint32_t val;
> > +    int r;
> > +
> > +    assert(pci_dev->devfn == 0x00);
> > +
> > +    if (!igd_passthru) {
> > +        goto read_default;
> > +    }
> > +
> > +    switch (config_addr) {
> > +    case 0x00:        /* vendor id */
> > +    case 0x02:        /* device id */
> > +    case 0x08:        /* revision id */
> > +    case 0x2c:        /* sybsystem vendor id */
> > +    case 0x2e:        /* sybsystem id */
> > +    case 0x50:        /* SNB: processor graphics control register */
> > +    case 0x52:        /* processor graphics control register */
> > +    case 0xa0:        /* top of memory */
> > +    case 0xb0:        /* ILK: BSM: should read from dev 2 offset 0x5c */
> > +    case 0x58:        /* SNB: PAVPC Offset */
> > +    case 0xa4:        /* SNB: graphics base of stolen memory */
> > +    case 0xa8:        /* SNB: base of GTT stolen memory */
> > +        break;
> > +    default:
> > +        goto read_default;
> > +    }
> > +
> > +    /* Host read */
> > +    r = xen_host_pci_device_get(&dev, 0, 0, 0, 0);
> > +    if (r) {
> > +        goto err_out;
> > +    }
> > +
> > +    r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len);
> > +    if (r) {
> > +        goto err_out;
> > +    }
> > +
> > +    xen_host_pci_device_put(&dev);
> > +
> > +    return val;
> > +
> > +read_default:
> > +    return pci_default_read_config(pci_dev, config_addr, len);
> > +
> > +err_out:
> > +    XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n");
> > +    return -1;
> > +}
> 
> The Xen specific part is OK.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [Xen-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
  2014-02-21  6:44   ` Yang Zhang
@ 2014-04-02 15:19     ` Zytaruk, Kelly
  -1 siblings, 0 replies; 32+ messages in thread
From: Zytaruk, Kelly @ 2014-04-02 15:19 UTC (permalink / raw)
  To: Yang Zhang, qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, weidong.han,
	allen.m.kay, jean.guyader, anthony, anthony.perard



> -----Original Message-----
> From: xen-devel-bounces@lists.xen.org [mailto:xen-devel-
> bounces@lists.xen.org] On Behalf Of Yang Zhang
> Sent: Friday, February 21, 2014 1:44 AM
> To: qemu-devel@nongnu.org
> Cc: peter.maydell@linaro.org; xen-devel@lists.xensource.com;
> stefano.stabellini@eu.citrix.com; allen.m.kay@intel.com;
> weidong.han@intel.com; jean.guyader@eu.citrix.com; Yang Zhang;
> anthony@codemonkey.ws; anthony.perard@citrix.com
> Subject: [Xen-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics
> passthrough support
> 
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> basic gfx passthrough support:
> - add a vga type for gfx passthrough
> - retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc: Weidong Han <weidong.han@intel.com>
> ---
>  configure                    |    2 +-
>  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     |  164
> ++++++++++++++++++++++++++++++++++++++++++
>  qemu-options.hx              |    9 +++
>  vl.c                         |    8 ++
>  9 files changed, 203 insertions(+), 2 deletions(-)  create mode 100644
> hw/xen/xen_pt_graphics.c
> 
> diff --git a/configure b/configure
> index 4648117..19525ab 100755
> --- a/configure
> +++ b/configure
> @@ -4608,7 +4608,7 @@ case "$target_name" in
>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
>        echo "CONFIG_XEN=y" >> $config_target_mak
>        if test "$xen_pci_passthrough" = yes; then
> -        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
> +        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_host_mak"
>        fi
>      fi
>      ;;
> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index
> ce640c6..350d337 100644
> --- a/hw/xen/Makefile.objs
> +++ b/hw/xen/Makefile.objs
> @@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o
> xen_devconfig.o
> 
>  obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
> diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c index
> 743b37b..a54b7de 100644
> --- a/hw/xen/xen-host-pci-device.c
> +++ b/hw/xen/xen-host-pci-device.c
> @@ -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;
> diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h index
> c2486f0..f1e1c30 100644
> --- a/hw/xen/xen-host-pci-device.h
> +++ b/hw/xen/xen-host-pci-device.h
> @@ -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]; diff --git
> a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index be4220b..5a36902 100644
> --- a/hw/xen/xen_pt.c
> +++ b/hw/xen/xen_pt.c
> @@ -450,6 +450,7 @@ static int
> xen_pt_register_regions(XenPCIPassthroughState *s)
>                     d->rom.size, d->rom.base_addr);
>      }
> 
> +    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);
>      }
> +
> +    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 (setup_vga_pt(&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"); diff --git
> a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 942dc60..c04bbfd 100644
> --- a/hw/xen/xen_pt.h
> +++ b/hw/xen/xen_pt.h
> @@ -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 gfx_passthru;
> +int register_vga_regions(XenHostPCIDevice *dev); int
> +unregister_vga_regions(XenHostPCIDevice *dev); int
> +setup_vga_pt(XenHostPCIDevice *dev);
> 
>  #endif /* !XEN_PT_H */
> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c new file
> mode 100644 index 0000000..9ad8a74
> --- /dev/null
> +++ b/hw/xen/xen_pt_graphics.c
> @@ -0,0 +1,164 @@
> +/*
> + * graphics passthrough
> + */
> +#include "xen_pt.h"
> +#include "xen-host-pci-device.h"
> +#include "hw/xen/xen_backend.h"
> +
> +/*
> + * register VGA resources for the domain with assigned gfx  */ int
> +register_vga_regions(XenHostPCIDevice *dev) {
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xA, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0x20,
> +            DPCI_ADD_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region mapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +/*
> + * unregister VGA resources for the domain with assigned gfx  */ int
> +unregister_vga_regions(XenHostPCIDevice *dev) {
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            20,
> +            DPCI_REMOVE_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region unmapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +static int get_vgabios(unsigned char *buf) {
> +    int fd;
> +    uint32_t bios_size = 0;
> +    uint32_t start = 0xC0000;
> +    uint16_t magic = 0;
> +

There is an inherent logic problem with this function.  This logic will not work if there are multiple graphics adapters in the system and you are passing the secondary graphics adapter to the guest as a primary.  Chances are very good that the VBios image at 0xC0000 does not match with the VBios image in the secondary adapter (unless they are absolutely identical and have the same VBios versions).

The proper way to do a get_vgabios() is to extract the VBios from the OPTION_ROM of the graphics device that is being passed into the guest.  You cannot assume that the image at 0xC0000 is a valid image for the device that is being passed into the guest when there are multiple adapters.

The logic that you present will work only if the primary graphics boot adapter is being passed into the guest but this is not always the case.


> +    fd = open("/dev/mem", O_RDONLY);
> +    if (fd < 0) {
> +        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
> +        return 0;
> +    }
> +
> +    /*
> +     * Check if it a real bios extension.
> +     * The magic number is 0xAA55.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (read(fd, &magic, 2) != 2) {
> +        goto out;
> +    }
> +    if (magic != 0xAA55) {
> +        goto out;
> +    }
> +
> +    /* Find the size of the rom extension */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) {
> +        goto out;
> +    }
> +    if (read(fd, &bios_size, 1) != 1) {
> +        goto out;
> +    }
> +
> +    /* This size is in 512 bytes */
> +    bios_size *= 512;
> +
> +    /*
> +     * Set the file to the begining of the rombios,
> +     * to start the copy.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +
> +    if (bios_size != read(fd, buf, bios_size)) {
> +        bios_size = 0;
> +    }
> +
> +out:
> +    close(fd);
> +    return bios_size;
> +}
> +
> +int setup_vga_pt(XenHostPCIDevice *dev) {
> +    unsigned char *bios = NULL;
> +    int bios_size = 0;
> +    char *c = NULL;
> +    char checksum = 0;
> +    int rc = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return rc;
> +    }
> +
> +    bios = malloc(64 * 1024);
> +    /* Allocated 64K for the vga bios */
> +    if (!bios) {
> +        return -1;
> +    }
> +
> +    bios_size = get_vgabios(bios);
> +    if (bios_size == 0 || bios_size > 64 * 1024) {
> +        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
> +        rc = -1;
> +        goto out;
> +    }
> +
> +    /* Adjust the bios checksum */
> +    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
> +        checksum += *c;
> +    }
> +    if (checksum) {
> +        bios[bios_size - 1] -= checksum;
> +        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
> +    }
> +
> +    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
> +out:
> +    free(bios);
> +    return rc;
> +}
> diff --git a/qemu-options.hx b/qemu-options.hx index 56e5fdf..95de002 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1034,6 +1034,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|none]\n"
>      "                select video card type\n", QEMU_ARCH_ALL)
> diff --git a/vl.c b/vl.c
> index 316de54..8a91054 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -215,6 +215,9 @@ static bool tcg_allowed = true;  bool xen_allowed;
> uint32_t xen_domid;  enum xen_mode xen_mode = XEN_EMULATE;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +int gfx_passthru = 0;
> +#endif
>  static int tcg_tb_size;
> 
>  static int default_serial = 1;
> @@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
>                  }
>                  configure_msg(opts);
>                  break;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +            case QEMU_OPTION_gfx_passthru:
> +                gfx_passthru = 1;
> +                break;
> +#endif
>              default:
>                  os_parse_cmd_args(popt->index, optarg);
>              }
> --
> 1.7.1
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel


Thanks,
Kelly

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
@ 2014-04-02 15:19     ` Zytaruk, Kelly
  0 siblings, 0 replies; 32+ messages in thread
From: Zytaruk, Kelly @ 2014-04-02 15:19 UTC (permalink / raw)
  To: Yang Zhang, qemu-devel
  Cc: peter.maydell, xen-devel, stefano.stabellini, weidong.han,
	allen.m.kay, jean.guyader, anthony, anthony.perard



> -----Original Message-----
> From: xen-devel-bounces@lists.xen.org [mailto:xen-devel-
> bounces@lists.xen.org] On Behalf Of Yang Zhang
> Sent: Friday, February 21, 2014 1:44 AM
> To: qemu-devel@nongnu.org
> Cc: peter.maydell@linaro.org; xen-devel@lists.xensource.com;
> stefano.stabellini@eu.citrix.com; allen.m.kay@intel.com;
> weidong.han@intel.com; jean.guyader@eu.citrix.com; Yang Zhang;
> anthony@codemonkey.ws; anthony.perard@citrix.com
> Subject: [Xen-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics
> passthrough support
> 
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> basic gfx passthrough support:
> - add a vga type for gfx passthrough
> - retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>
> 
> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
> Cc: Weidong Han <weidong.han@intel.com>
> ---
>  configure                    |    2 +-
>  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     |  164
> ++++++++++++++++++++++++++++++++++++++++++
>  qemu-options.hx              |    9 +++
>  vl.c                         |    8 ++
>  9 files changed, 203 insertions(+), 2 deletions(-)  create mode 100644
> hw/xen/xen_pt_graphics.c
> 
> diff --git a/configure b/configure
> index 4648117..19525ab 100755
> --- a/configure
> +++ b/configure
> @@ -4608,7 +4608,7 @@ case "$target_name" in
>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
>        echo "CONFIG_XEN=y" >> $config_target_mak
>        if test "$xen_pci_passthrough" = yes; then
> -        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
> +        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_host_mak"
>        fi
>      fi
>      ;;
> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index
> ce640c6..350d337 100644
> --- a/hw/xen/Makefile.objs
> +++ b/hw/xen/Makefile.objs
> @@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o
> xen_devconfig.o
> 
>  obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
> diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c index
> 743b37b..a54b7de 100644
> --- a/hw/xen/xen-host-pci-device.c
> +++ b/hw/xen/xen-host-pci-device.c
> @@ -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;
> diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h index
> c2486f0..f1e1c30 100644
> --- a/hw/xen/xen-host-pci-device.h
> +++ b/hw/xen/xen-host-pci-device.h
> @@ -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]; diff --git
> a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index be4220b..5a36902 100644
> --- a/hw/xen/xen_pt.c
> +++ b/hw/xen/xen_pt.c
> @@ -450,6 +450,7 @@ static int
> xen_pt_register_regions(XenPCIPassthroughState *s)
>                     d->rom.size, d->rom.base_addr);
>      }
> 
> +    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);
>      }
> +
> +    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 (setup_vga_pt(&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"); diff --git
> a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 942dc60..c04bbfd 100644
> --- a/hw/xen/xen_pt.h
> +++ b/hw/xen/xen_pt.h
> @@ -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 gfx_passthru;
> +int register_vga_regions(XenHostPCIDevice *dev); int
> +unregister_vga_regions(XenHostPCIDevice *dev); int
> +setup_vga_pt(XenHostPCIDevice *dev);
> 
>  #endif /* !XEN_PT_H */
> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c new file
> mode 100644 index 0000000..9ad8a74
> --- /dev/null
> +++ b/hw/xen/xen_pt_graphics.c
> @@ -0,0 +1,164 @@
> +/*
> + * graphics passthrough
> + */
> +#include "xen_pt.h"
> +#include "xen-host-pci-device.h"
> +#include "hw/xen/xen_backend.h"
> +
> +/*
> + * register VGA resources for the domain with assigned gfx  */ int
> +register_vga_regions(XenHostPCIDevice *dev) {
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xA, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_ADD_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0x20,
> +            DPCI_ADD_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region mapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +/*
> + * unregister VGA resources for the domain with assigned gfx  */ int
> +unregister_vga_regions(XenHostPCIDevice *dev) {
> +    int ret = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return ret;
> +    }
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0,
> +            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0,
> +            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
> +
> +    ret |= xc_domain_memory_mapping(xen_xc, xen_domid,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            0xa0000 >> XC_PAGE_SHIFT,
> +            20,
> +            DPCI_REMOVE_MAPPING);
> +
> +    if (ret != 0) {
> +        XEN_PT_ERR(NULL, "VGA region unmapping failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +static int get_vgabios(unsigned char *buf) {
> +    int fd;
> +    uint32_t bios_size = 0;
> +    uint32_t start = 0xC0000;
> +    uint16_t magic = 0;
> +

There is an inherent logic problem with this function.  This logic will not work if there are multiple graphics adapters in the system and you are passing the secondary graphics adapter to the guest as a primary.  Chances are very good that the VBios image at 0xC0000 does not match with the VBios image in the secondary adapter (unless they are absolutely identical and have the same VBios versions).

The proper way to do a get_vgabios() is to extract the VBios from the OPTION_ROM of the graphics device that is being passed into the guest.  You cannot assume that the image at 0xC0000 is a valid image for the device that is being passed into the guest when there are multiple adapters.

The logic that you present will work only if the primary graphics boot adapter is being passed into the guest but this is not always the case.


> +    fd = open("/dev/mem", O_RDONLY);
> +    if (fd < 0) {
> +        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
> +        return 0;
> +    }
> +
> +    /*
> +     * Check if it a real bios extension.
> +     * The magic number is 0xAA55.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (read(fd, &magic, 2) != 2) {
> +        goto out;
> +    }
> +    if (magic != 0xAA55) {
> +        goto out;
> +    }
> +
> +    /* Find the size of the rom extension */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) {
> +        goto out;
> +    }
> +    if (read(fd, &bios_size, 1) != 1) {
> +        goto out;
> +    }
> +
> +    /* This size is in 512 bytes */
> +    bios_size *= 512;
> +
> +    /*
> +     * Set the file to the begining of the rombios,
> +     * to start the copy.
> +     */
> +    if (start != lseek(fd, start, SEEK_SET)) {
> +        goto out;
> +    }
> +
> +    if (bios_size != read(fd, buf, bios_size)) {
> +        bios_size = 0;
> +    }
> +
> +out:
> +    close(fd);
> +    return bios_size;
> +}
> +
> +int setup_vga_pt(XenHostPCIDevice *dev) {
> +    unsigned char *bios = NULL;
> +    int bios_size = 0;
> +    char *c = NULL;
> +    char checksum = 0;
> +    int rc = 0;
> +
> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> +        return rc;
> +    }
> +
> +    bios = malloc(64 * 1024);
> +    /* Allocated 64K for the vga bios */
> +    if (!bios) {
> +        return -1;
> +    }
> +
> +    bios_size = get_vgabios(bios);
> +    if (bios_size == 0 || bios_size > 64 * 1024) {
> +        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
> +        rc = -1;
> +        goto out;
> +    }
> +
> +    /* Adjust the bios checksum */
> +    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
> +        checksum += *c;
> +    }
> +    if (checksum) {
> +        bios[bios_size - 1] -= checksum;
> +        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
> +    }
> +
> +    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
> +out:
> +    free(bios);
> +    return rc;
> +}
> diff --git a/qemu-options.hx b/qemu-options.hx index 56e5fdf..95de002 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1034,6 +1034,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|none]\n"
>      "                select video card type\n", QEMU_ARCH_ALL)
> diff --git a/vl.c b/vl.c
> index 316de54..8a91054 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -215,6 +215,9 @@ static bool tcg_allowed = true;  bool xen_allowed;
> uint32_t xen_domid;  enum xen_mode xen_mode = XEN_EMULATE;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +int gfx_passthru = 0;
> +#endif
>  static int tcg_tb_size;
> 
>  static int default_serial = 1;
> @@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
>                  }
>                  configure_msg(opts);
>                  break;
> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
> +            case QEMU_OPTION_gfx_passthru:
> +                gfx_passthru = 1;
> +                break;
> +#endif
>              default:
>                  os_parse_cmd_args(popt->index, optarg);
>              }
> --
> 1.7.1
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel


Thanks,
Kelly

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] xen: add Intel IGD passthrough support
  2014-02-21  6:44 ` Yang Zhang
@ 2014-04-04 22:46   ` Kevin O'Connor
  -1 siblings, 0 replies; 32+ messages in thread
From: Kevin O'Connor @ 2014-04-04 22:46 UTC (permalink / raw)
  To: Yang Zhang
  Cc: peter.maydell, xen-devel, stefano.stabellini, weidong.han,
	allen.m.kay, qemu-devel, jean.guyader, anthony, anthony.perard

On Fri, Feb 21, 2014 at 02:44:08PM +0800, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> The following patches are ported 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@2']
> 
> Besides, since Xen + Qemu upstream is requiring seabios, user also need to
> recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow IGD pass through
> successfully:

I'm not familiar with the Xen parts of your patch series.  However, I
don't think one should be compiling SeaBIOS with
CONFIG_OPTIONROMS_DEPLOYED enabled.  That option was for very old
versions of Bochs and QEMU that did not support fetching of optionroms
directly from PCI config space nor from fw_cfg.

That compile time option is no longer well supported and it may be
removed in the future.  I suggest looking at getting one of the other
mechanisms working instead of using CONFIG_OPTIONROMS_DEPLOYED.

-Kevin

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 0/5] xen: add Intel IGD passthrough support
@ 2014-04-04 22:46   ` Kevin O'Connor
  0 siblings, 0 replies; 32+ messages in thread
From: Kevin O'Connor @ 2014-04-04 22:46 UTC (permalink / raw)
  To: Yang Zhang
  Cc: peter.maydell, xen-devel, stefano.stabellini, weidong.han,
	allen.m.kay, qemu-devel, jean.guyader, anthony, anthony.perard

On Fri, Feb 21, 2014 at 02:44:08PM +0800, Yang Zhang wrote:
> From: Yang Zhang <yang.z.zhang@Intel.com>
> 
> The following patches are ported 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@2']
> 
> Besides, since Xen + Qemu upstream is requiring seabios, user also need to
> recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow IGD pass through
> successfully:

I'm not familiar with the Xen parts of your patch series.  However, I
don't think one should be compiling SeaBIOS with
CONFIG_OPTIONROMS_DEPLOYED enabled.  That option was for very old
versions of Bochs and QEMU that did not support fetching of optionroms
directly from PCI config space nor from fw_cfg.

That compile time option is no longer well supported and it may be
removed in the future.  I suggest looking at getting one of the other
mechanisms working instead of using CONFIG_OPTIONROMS_DEPLOYED.

-Kevin

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [Xen-devel] [PATCH 0/5] xen: add Intel IGD passthrough support
  2014-04-04 22:46   ` Kevin O'Connor
@ 2014-04-07  8:36     ` Ian Campbell
  -1 siblings, 0 replies; 32+ messages in thread
From: Ian Campbell @ 2014-04-07  8:36 UTC (permalink / raw)
  To: Kevin O'Connor
  Cc: peter.maydell, xen-devel, stefano.stabellini, weidong.han,
	allen.m.kay, qemu-devel, jean.guyader, anthony.perard, anthony,
	Yang Zhang

On Fri, 2014-04-04 at 18:46 -0400, Kevin O'Connor wrote:
> On Fri, Feb 21, 2014 at 02:44:08PM +0800, Yang Zhang wrote:
> > From: Yang Zhang <yang.z.zhang@Intel.com>
> > 
> > The following patches are ported 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@2']
> > 
> > Besides, since Xen + Qemu upstream is requiring seabios, user also need to
> > recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow IGD pass through
> > successfully:
> 
> I'm not familiar with the Xen parts of your patch series.  However, I
> don't think one should be compiling SeaBIOS with
> CONFIG_OPTIONROMS_DEPLOYED enabled.

I agree, thanks for spotting this. I would nack any patch which tried to
enable this option in the Xen build of SeaBIOS.

>   That option was for very old
> versions of Bochs and QEMU that did not support fetching of optionroms
> directly from PCI config space nor from fw_cfg.
> 
> That compile time option is no longer well supported and it may be
> removed in the future.  I suggest looking at getting one of the other
> mechanisms working instead of using CONFIG_OPTIONROMS_DEPLOYED.

AFAIK the usual mechanisms already work for SeaBIOS under Xen, e.g. for
the video BIOS of the emulated VGA it Just Works. I've no idea what
makes Intel IGD passthrough special.

Ian.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Xen-devel] [PATCH 0/5] xen: add Intel IGD passthrough support
@ 2014-04-07  8:36     ` Ian Campbell
  0 siblings, 0 replies; 32+ messages in thread
From: Ian Campbell @ 2014-04-07  8:36 UTC (permalink / raw)
  To: Kevin O'Connor
  Cc: peter.maydell, xen-devel, stefano.stabellini, weidong.han,
	allen.m.kay, qemu-devel, jean.guyader, anthony.perard, anthony,
	Yang Zhang

On Fri, 2014-04-04 at 18:46 -0400, Kevin O'Connor wrote:
> On Fri, Feb 21, 2014 at 02:44:08PM +0800, Yang Zhang wrote:
> > From: Yang Zhang <yang.z.zhang@Intel.com>
> > 
> > The following patches are ported 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@2']
> > 
> > Besides, since Xen + Qemu upstream is requiring seabios, user also need to
> > recompile seabios with CONFIG_OPTIONROMS_DEPLOYED=y to allow IGD pass through
> > successfully:
> 
> I'm not familiar with the Xen parts of your patch series.  However, I
> don't think one should be compiling SeaBIOS with
> CONFIG_OPTIONROMS_DEPLOYED enabled.

I agree, thanks for spotting this. I would nack any patch which tried to
enable this option in the Xen build of SeaBIOS.

>   That option was for very old
> versions of Bochs and QEMU that did not support fetching of optionroms
> directly from PCI config space nor from fw_cfg.
> 
> That compile time option is no longer well supported and it may be
> removed in the future.  I suggest looking at getting one of the other
> mechanisms working instead of using CONFIG_OPTIONROMS_DEPLOYED.

AFAIK the usual mechanisms already work for SeaBIOS under Xen, e.g. for
the video BIOS of the emulated VGA it Just Works. I've no idea what
makes Intel IGD passthrough special.

Ian.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [Qemu-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
  2014-03-21 16:24     ` Anthony PERARD
@ 2014-05-09  7:27       ` Zhang, Yang Z
  -1 siblings, 0 replies; 32+ messages in thread
From: Zhang, Yang Z @ 2014-05-09  7:27 UTC (permalink / raw)
  To: Anthony PERARD, stefano.stabellini, Michael S. Tsirkin, Zytaruk, Kelly
  Cc: peter.maydell, xen-devel, weidong.han, Kay, Allen M, qemu-devel,
	jean.guyader, anthony, Chen, Tiejun

Anthony PERARD wrote on 2014-03-22:
> On Fri, Feb 21, 2014 at 02:44:09PM +0800, Yang Zhang wrote:
>> From: Yang Zhang <yang.z.zhang@Intel.com>
>> 
>> basic gfx passthrough support:
>> - add a vga type for gfx passthrough
>> - retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>
>> 
>> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
>> Cc: Weidong Han <weidong.han@intel.com>

Hi all, 

Thanks for your comments. 

I am sorry for late reply. I have been busy working on other task so that I have no time to push this patch in the past two months. Now I and Tiejun will continue working on this and will send out the second version which is modified according your previous comments. Please help to review the second one again.

>> ---
>>  configure                    |    2 +- 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 
>>     |  164 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx  
>>             |    9 +++ vl.c                         |    8 ++ 9 files
>>  changed, 203 insertions(+), 2 deletions(-)  create mode
>> 100644 hw/xen/xen_pt_graphics.c
>> 
>> diff --git a/configure b/configure
>> index 4648117..19525ab 100755
>> --- a/configure
>> +++ b/configure
>> @@ -4608,7 +4608,7 @@ case "$target_name" in
>>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
>>        echo "CONFIG_XEN=y" >> $config_target_mak
>>        if test "$xen_pci_passthrough" = yes; then
>> -        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak" + 
>>       echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >>
> "$config_host_mak"
> 
> Why do you need to move this option from config_target to config_host?
> 
>>        fi
>>      fi
>>      ;;
>> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index
>> ce640c6..350d337 100644 --- a/hw/xen/Makefile.objs +++
>> b/hw/xen/Makefile.objs @@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND)
>> += xen_backend.o xen_devconfig.o
>> 
>>  obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
>> diff --git a/hw/xen/xen-host-pci-device.c
>> b/hw/xen/xen-host-pci-device.c index 743b37b..a54b7de 100644
>> --- a/hw/xen/xen-host-pci-device.c
>> +++ b/hw/xen/xen-host-pci-device.c
>> @@ -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;
>> diff --git a/hw/xen/xen-host-pci-device.h
>> b/hw/xen/xen-host-pci-device.h index c2486f0..f1e1c30 100644
>> --- a/hw/xen/xen-host-pci-device.h
>> +++ b/hw/xen/xen-host-pci-device.h
>> @@ -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]; diff --git
>> a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index be4220b..5a36902 100644
>> --- a/hw/xen/xen_pt.c
>> +++ b/hw/xen/xen_pt.c
>> @@ -450,6 +450,7 @@ static int
> xen_pt_register_regions(XenPCIPassthroughState *s)
>>                     d->rom.size, d->rom.base_addr);
>>      }
>> +    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);
>>      }
>> +
>> +    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 (setup_vga_pt(&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");
>> diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index
>> 942dc60..c04bbfd
>> 100644
>> --- a/hw/xen/xen_pt.h
>> +++ b/hw/xen/xen_pt.h
>> @@ -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 gfx_passthru;
>> +int register_vga_regions(XenHostPCIDevice *dev); int
>> +unregister_vga_regions(XenHostPCIDevice *dev); int
>> +setup_vga_pt(XenHostPCIDevice *dev);
> 
> I believe those function names need to be prefix with xen_pt_ (e.g.
> xen_pt_register_vga_regions).
> 
>>  #endif /* !XEN_PT_H */
>> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c new
>> file mode 100644 index 0000000..9ad8a74
>> --- /dev/null
>> +++ b/hw/xen/xen_pt_graphics.c
>> @@ -0,0 +1,164 @@
>> +/*
>> + * graphics passthrough
>> + */
>> +#include "xen_pt.h"
>> +#include "xen-host-pci-device.h"
>> +#include "hw/xen/xen_backend.h"
>> +
>> +/*
>> + * register VGA resources for the domain with assigned gfx  */ int
>> +register_vga_regions(XenHostPCIDevice *dev) {
>> +    int ret = 0;
>> +
>> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> 
> Instead of 0x0300, you can use PCI_CLASS_DISPLAY_VGA. The same apply
> to the few other places.
> 
>> +        return ret; +    } + +    ret |=
>> xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0, +            0x3B0,
>> 0xA, DPCI_ADD_MAPPING); + +    ret |= xc_domain_ioport_mapping(xen_xc,
>> xen_domid, 0x3C0, +            0x3C0, 0x20, DPCI_ADD_MAPPING); + +   
>> ret |= xc_domain_memory_mapping(xen_xc, xen_domid, +            0xa0000
>> >> XC_PAGE_SHIFT, +            0xa0000 >> XC_PAGE_SHIFT, +           
>> 0x20, +            DPCI_ADD_MAPPING); + +    if (ret != 0) { +       
>> XEN_PT_ERR(NULL, "VGA region mapping failed\n"); +    } + +    return
>> ret; +} + +/* + * unregister VGA resources for the domain with assigned
>> gfx  */ +int unregister_vga_regions(XenHostPCIDevice *dev) { +    int
>> ret = 0; + +    if (!gfx_passthru || ((dev->class_code >> 0x8) !=
>> 0x0300)) { +        return ret; +    } + +    ret |=
>> xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0, +            0x3B0,
>> 0xC, DPCI_REMOVE_MAPPING); + +    ret |=
>> xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0, +            0x3C0,
>> 0x20, DPCI_REMOVE_MAPPING); + +    ret |=
>> xc_domain_memory_mapping(xen_xc, xen_domid, +            0xa0000 >>
>> XC_PAGE_SHIFT, +            0xa0000 >> XC_PAGE_SHIFT, +            20,
>> +            DPCI_REMOVE_MAPPING); + +    if (ret != 0) { +       
>> XEN_PT_ERR(NULL, "VGA region unmapping failed\n"); +    } + +    return
>> ret; +} + +static int get_vgabios(unsigned char *buf) { +    int fd; + 
>>   uint32_t bios_size = 0; +    uint32_t start = 0xC0000; +    uint16_t
>> magic = 0; + +    fd = open("/dev/mem", O_RDONLY); +    if (fd < 0) { +
>>        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
>> +        return 0; +    } + +    /* +     * Check if it a real bios
>> extension. +     * The magic number is 0xAA55. +     */ +    if (start
>> != lseek(fd, start, SEEK_SET)) { +        goto out; +    } +    if
>> (read(fd, &magic, 2) != 2) { +        goto out; +    } +    if (magic
>> != 0xAA55) { +        goto out; +    } + +    /* Find the size of the
>> rom extension */ +    if (start != lseek(fd, start, SEEK_SET)) { +     
>>   goto out; +    } +    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) { + 
>>       goto out; +    } +    if (read(fd, &bios_size, 1) != 1) { +      
>>  goto out; +    } + +    /* This size is in 512 bytes */ +    bios_size
>> *= 512; + +    /* +     * Set the file to the begining of the rombios,
>> +     * to start the copy. +     */ +    if (start != lseek(fd, start,
>> SEEK_SET)) { +        goto out; +    } + +    if (bios_size != read(fd,
>> buf, bios_size)) { +        bios_size = 0; +    } + +out: +   
>> close(fd); +    return bios_size; +} + +int
>> setup_vga_pt(XenHostPCIDevice *dev) { +    unsigned char *bios = NULL;
>> +    int bios_size = 0; +    char *c = NULL; +    char checksum = 0; + 
>>   int rc = 0; + +    if (!gfx_passthru || ((dev->class_code >> 0x8) !=
>> 0x0300)) { +        return rc; +    } + +    bios = malloc(64 * 1024);
> 
> I think g_malloc should be used here, instead of malloc, and g_malloc
> always return an allocated buffer. (it never fail, or it don't return)
> 
>> +    /* Allocated 64K for the vga bios */
>> +    if (!bios) {
>> +        return -1;
>> +    }
>> +
>> +    bios_size = get_vgabios(bios);
>> +    if (bios_size == 0 || bios_size > 64 * 1024) {
>> +        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
>> +        rc = -1;
>> +        goto out;
>> +    }
>> +
>> +    /* Adjust the bios checksum */
>> +    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
>> +        checksum += *c;
>> +    }
>> +    if (checksum) {
>> +        bios[bios_size - 1] -= checksum;
>> +        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
>> +    }
>> +
>> +    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
>> +out:
>> +    free(bios);
>> +    return rc;
>> +}
>> diff --git a/qemu-options.hx b/qemu-options.hx index
>> 56e5fdf..95de002
>> 100644
>> --- a/qemu-options.hx
>> +++ b/qemu-options.hx
>> @@ -1034,6 +1034,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
>> +
> 
> Is this options really necessary?  If someone is passing-through a
> graphic card, he propably want to pass it through as a graphic card,
> without having to enable yet another option.
> 
>>  DEF("vga", HAS_ARG, QEMU_OPTION_vga,
>>      "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
>>      "                select video card type\n", QEMU_ARCH_ALL)
>> diff --git a/vl.c b/vl.c
>> index 316de54..8a91054 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -215,6 +215,9 @@ static bool tcg_allowed = true;  bool
>> xen_allowed; uint32_t xen_domid;  enum xen_mode xen_mode =
>> XEN_EMULATE;
>> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
>> +int gfx_passthru = 0;
>> +#endif
>>  static int tcg_tb_size;
>>  
>>  static int default_serial = 1;
>> @@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
>>                  }
>>                  configure_msg(opts);
>>                  break;
>> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
>> +            case QEMU_OPTION_gfx_passthru:
>> +                gfx_passthru = 1;
>> +                break;
>> +#endif
>>              default:
>>                  os_parse_cmd_args(popt->index, optarg);
>>              }
>


Best regards,
Yang

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support
@ 2014-05-09  7:27       ` Zhang, Yang Z
  0 siblings, 0 replies; 32+ messages in thread
From: Zhang, Yang Z @ 2014-05-09  7:27 UTC (permalink / raw)
  To: Anthony PERARD, stefano.stabellini, Michael S. Tsirkin, Zytaruk, Kelly
  Cc: peter.maydell, xen-devel, weidong.han, Kay, Allen M, qemu-devel,
	jean.guyader, anthony, Chen, Tiejun

Anthony PERARD wrote on 2014-03-22:
> On Fri, Feb 21, 2014 at 02:44:09PM +0800, Yang Zhang wrote:
>> From: Yang Zhang <yang.z.zhang@Intel.com>
>> 
>> basic gfx passthrough support:
>> - add a vga type for gfx passthrough
>> - retrieve VGA bios from host 0xC0000, 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 <weidong.han@intel.com>
>> 
>> Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
>> Cc: Weidong Han <weidong.han@intel.com>

Hi all, 

Thanks for your comments. 

I am sorry for late reply. I have been busy working on other task so that I have no time to push this patch in the past two months. Now I and Tiejun will continue working on this and will send out the second version which is modified according your previous comments. Please help to review the second one again.

>> ---
>>  configure                    |    2 +- 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 
>>     |  164 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx  
>>             |    9 +++ vl.c                         |    8 ++ 9 files
>>  changed, 203 insertions(+), 2 deletions(-)  create mode
>> 100644 hw/xen/xen_pt_graphics.c
>> 
>> diff --git a/configure b/configure
>> index 4648117..19525ab 100755
>> --- a/configure
>> +++ b/configure
>> @@ -4608,7 +4608,7 @@ case "$target_name" in
>>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
>>        echo "CONFIG_XEN=y" >> $config_target_mak
>>        if test "$xen_pci_passthrough" = yes; then
>> -        echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak" + 
>>       echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >>
> "$config_host_mak"
> 
> Why do you need to move this option from config_target to config_host?
> 
>>        fi
>>      fi
>>      ;;
>> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index
>> ce640c6..350d337 100644 --- a/hw/xen/Makefile.objs +++
>> b/hw/xen/Makefile.objs @@ -3,4 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND)
>> += xen_backend.o xen_devconfig.o
>> 
>>  obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.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
>> diff --git a/hw/xen/xen-host-pci-device.c
>> b/hw/xen/xen-host-pci-device.c index 743b37b..a54b7de 100644
>> --- a/hw/xen/xen-host-pci-device.c
>> +++ b/hw/xen/xen-host-pci-device.c
>> @@ -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;
>> diff --git a/hw/xen/xen-host-pci-device.h
>> b/hw/xen/xen-host-pci-device.h index c2486f0..f1e1c30 100644
>> --- a/hw/xen/xen-host-pci-device.h
>> +++ b/hw/xen/xen-host-pci-device.h
>> @@ -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]; diff --git
>> a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index be4220b..5a36902 100644
>> --- a/hw/xen/xen_pt.c
>> +++ b/hw/xen/xen_pt.c
>> @@ -450,6 +450,7 @@ static int
> xen_pt_register_regions(XenPCIPassthroughState *s)
>>                     d->rom.size, d->rom.base_addr);
>>      }
>> +    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);
>>      }
>> +
>> +    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 (setup_vga_pt(&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");
>> diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index
>> 942dc60..c04bbfd
>> 100644
>> --- a/hw/xen/xen_pt.h
>> +++ b/hw/xen/xen_pt.h
>> @@ -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 gfx_passthru;
>> +int register_vga_regions(XenHostPCIDevice *dev); int
>> +unregister_vga_regions(XenHostPCIDevice *dev); int
>> +setup_vga_pt(XenHostPCIDevice *dev);
> 
> I believe those function names need to be prefix with xen_pt_ (e.g.
> xen_pt_register_vga_regions).
> 
>>  #endif /* !XEN_PT_H */
>> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c new
>> file mode 100644 index 0000000..9ad8a74
>> --- /dev/null
>> +++ b/hw/xen/xen_pt_graphics.c
>> @@ -0,0 +1,164 @@
>> +/*
>> + * graphics passthrough
>> + */
>> +#include "xen_pt.h"
>> +#include "xen-host-pci-device.h"
>> +#include "hw/xen/xen_backend.h"
>> +
>> +/*
>> + * register VGA resources for the domain with assigned gfx  */ int
>> +register_vga_regions(XenHostPCIDevice *dev) {
>> +    int ret = 0;
>> +
>> +    if (!gfx_passthru || ((dev->class_code >> 0x8) != 0x0300)) {
> 
> Instead of 0x0300, you can use PCI_CLASS_DISPLAY_VGA. The same apply
> to the few other places.
> 
>> +        return ret; +    } + +    ret |=
>> xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0, +            0x3B0,
>> 0xA, DPCI_ADD_MAPPING); + +    ret |= xc_domain_ioport_mapping(xen_xc,
>> xen_domid, 0x3C0, +            0x3C0, 0x20, DPCI_ADD_MAPPING); + +   
>> ret |= xc_domain_memory_mapping(xen_xc, xen_domid, +            0xa0000
>> >> XC_PAGE_SHIFT, +            0xa0000 >> XC_PAGE_SHIFT, +           
>> 0x20, +            DPCI_ADD_MAPPING); + +    if (ret != 0) { +       
>> XEN_PT_ERR(NULL, "VGA region mapping failed\n"); +    } + +    return
>> ret; +} + +/* + * unregister VGA resources for the domain with assigned
>> gfx  */ +int unregister_vga_regions(XenHostPCIDevice *dev) { +    int
>> ret = 0; + +    if (!gfx_passthru || ((dev->class_code >> 0x8) !=
>> 0x0300)) { +        return ret; +    } + +    ret |=
>> xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3B0, +            0x3B0,
>> 0xC, DPCI_REMOVE_MAPPING); + +    ret |=
>> xc_domain_ioport_mapping(xen_xc, xen_domid, 0x3C0, +            0x3C0,
>> 0x20, DPCI_REMOVE_MAPPING); + +    ret |=
>> xc_domain_memory_mapping(xen_xc, xen_domid, +            0xa0000 >>
>> XC_PAGE_SHIFT, +            0xa0000 >> XC_PAGE_SHIFT, +            20,
>> +            DPCI_REMOVE_MAPPING); + +    if (ret != 0) { +       
>> XEN_PT_ERR(NULL, "VGA region unmapping failed\n"); +    } + +    return
>> ret; +} + +static int get_vgabios(unsigned char *buf) { +    int fd; + 
>>   uint32_t bios_size = 0; +    uint32_t start = 0xC0000; +    uint16_t
>> magic = 0; + +    fd = open("/dev/mem", O_RDONLY); +    if (fd < 0) { +
>>        XEN_PT_ERR(NULL, "Can't open /dev/mem: %s\n", strerror(errno));
>> +        return 0; +    } + +    /* +     * Check if it a real bios
>> extension. +     * The magic number is 0xAA55. +     */ +    if (start
>> != lseek(fd, start, SEEK_SET)) { +        goto out; +    } +    if
>> (read(fd, &magic, 2) != 2) { +        goto out; +    } +    if (magic
>> != 0xAA55) { +        goto out; +    } + +    /* Find the size of the
>> rom extension */ +    if (start != lseek(fd, start, SEEK_SET)) { +     
>>   goto out; +    } +    if (lseek(fd, 2, SEEK_CUR) != (start + 2)) { + 
>>       goto out; +    } +    if (read(fd, &bios_size, 1) != 1) { +      
>>  goto out; +    } + +    /* This size is in 512 bytes */ +    bios_size
>> *= 512; + +    /* +     * Set the file to the begining of the rombios,
>> +     * to start the copy. +     */ +    if (start != lseek(fd, start,
>> SEEK_SET)) { +        goto out; +    } + +    if (bios_size != read(fd,
>> buf, bios_size)) { +        bios_size = 0; +    } + +out: +   
>> close(fd); +    return bios_size; +} + +int
>> setup_vga_pt(XenHostPCIDevice *dev) { +    unsigned char *bios = NULL;
>> +    int bios_size = 0; +    char *c = NULL; +    char checksum = 0; + 
>>   int rc = 0; + +    if (!gfx_passthru || ((dev->class_code >> 0x8) !=
>> 0x0300)) { +        return rc; +    } + +    bios = malloc(64 * 1024);
> 
> I think g_malloc should be used here, instead of malloc, and g_malloc
> always return an allocated buffer. (it never fail, or it don't return)
> 
>> +    /* Allocated 64K for the vga bios */
>> +    if (!bios) {
>> +        return -1;
>> +    }
>> +
>> +    bios_size = get_vgabios(bios);
>> +    if (bios_size == 0 || bios_size > 64 * 1024) {
>> +        XEN_PT_ERR(NULL, "vga bios size (0x%x) is invalid!\n", bios_size);
>> +        rc = -1;
>> +        goto out;
>> +    }
>> +
>> +    /* Adjust the bios checksum */
>> +    for (c = (char *)bios; c < ((char *)bios + bios_size); c++) {
>> +        checksum += *c;
>> +    }
>> +    if (checksum) {
>> +        bios[bios_size - 1] -= checksum;
>> +        XEN_PT_LOG(NULL, "vga bios checksum is adjusted!\n");
>> +    }
>> +
>> +    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
>> +out:
>> +    free(bios);
>> +    return rc;
>> +}
>> diff --git a/qemu-options.hx b/qemu-options.hx index
>> 56e5fdf..95de002
>> 100644
>> --- a/qemu-options.hx
>> +++ b/qemu-options.hx
>> @@ -1034,6 +1034,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
>> +
> 
> Is this options really necessary?  If someone is passing-through a
> graphic card, he propably want to pass it through as a graphic card,
> without having to enable yet another option.
> 
>>  DEF("vga", HAS_ARG, QEMU_OPTION_vga,
>>      "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
>>      "                select video card type\n", QEMU_ARCH_ALL)
>> diff --git a/vl.c b/vl.c
>> index 316de54..8a91054 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -215,6 +215,9 @@ static bool tcg_allowed = true;  bool
>> xen_allowed; uint32_t xen_domid;  enum xen_mode xen_mode =
>> XEN_EMULATE;
>> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
>> +int gfx_passthru = 0;
>> +#endif
>>  static int tcg_tb_size;
>>  
>>  static int default_serial = 1;
>> @@ -3775,6 +3778,11 @@ int main(int argc, char **argv, char **envp)
>>                  }
>>                  configure_msg(opts);
>>                  break;
>> +#if defined(CONFIG_XEN_PCI_PASSTHROUGH)
>> +            case QEMU_OPTION_gfx_passthru:
>> +                gfx_passthru = 1;
>> +                break;
>> +#endif
>>              default:
>>                  os_parse_cmd_args(popt->index, optarg);
>>              }
>


Best regards,
Yang

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2014-05-09  7:28 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-21  6:44 [Qemu-devel] [PATCH 0/5] xen: add Intel IGD passthrough support Yang Zhang
2014-02-21  6:44 ` Yang Zhang
2014-02-21  6:44 ` [Qemu-devel] [PATCH 1/5] xen, gfx passthrough: basic graphics " Yang Zhang
2014-02-21  6:44   ` Yang Zhang
2014-03-21 16:24   ` [Qemu-devel] " Anthony PERARD
2014-03-21 16:24     ` Anthony PERARD
2014-05-09  7:27     ` [Qemu-devel] " Zhang, Yang Z
2014-05-09  7:27       ` Zhang, Yang Z
2014-04-02 15:19   ` [Qemu-devel] [Xen-devel] " Zytaruk, Kelly
2014-04-02 15:19     ` Zytaruk, Kelly
2014-02-21  6:44 ` [Qemu-devel] [PATCH 2/5] xen, gfx passthrough: reserve 00:02.0 for INTEL IGD Yang Zhang
2014-02-21  6:44   ` Yang Zhang
2014-03-21 17:26   ` [Qemu-devel] " Anthony PERARD
2014-03-21 17:26     ` Anthony PERARD
2014-02-21  6:44 ` [Qemu-devel] [PATCH 3/5] xen, gfx passthrough: create intel isa bridge Yang Zhang
2014-02-21  6:44   ` Yang Zhang
2014-02-21  6:44 ` [Qemu-devel] [PATCH 4/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D Yang Zhang
2014-02-21  6:44   ` Yang Zhang
2014-03-27 18:21   ` [Qemu-devel] " Stefano Stabellini
2014-03-27 18:21     ` Stefano Stabellini
2014-03-27 19:10     ` [Qemu-devel] " Michael S. Tsirkin
2014-03-27 19:10       ` Michael S. Tsirkin
2014-02-21  6:44 ` [Qemu-devel] [PATCH 5/5] xen, gfx passthrough: add opregion mapping Yang Zhang
2014-02-21  6:44   ` Yang Zhang
2014-02-27  5:38 ` [Qemu-devel] [PATCH 0/5] xen: add Intel IGD passthrough support Zhang, Yang Z
2014-02-27  5:38   ` Zhang, Yang Z
2014-02-27 12:47   ` [Qemu-devel] " Stefano Stabellini
2014-02-27 12:47     ` Stefano Stabellini
2014-04-04 22:46 ` [Qemu-devel] " Kevin O'Connor
2014-04-04 22:46   ` Kevin O'Connor
2014-04-07  8:36   ` [Qemu-devel] [Xen-devel] " Ian Campbell
2014-04-07  8:36     ` Ian Campbell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.