WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [qemu-xen-unstable] graphics passthrough with VT-d

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [qemu-xen-unstable] graphics passthrough with VT-d
From: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>
Date: Fri, 4 Sep 2009 08:36:06 -0700
Delivery-date: Fri, 04 Sep 2009 08:36:08 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
commit 3e37644fcde724433454440a61b22d3f7f9932bb
Author: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Date:   Fri Sep 4 16:21:25 2009 +0100

    graphics passthrough with VT-d
    
    This patch supports basic gfx passthrough on QEMU:
      - disable emulated VGA adpater if there is passthroughed gfx
      - retrieve VGA bios from host 0xC0000, then load it to guest 0xC0000
      - register/unregister legacy VGA I/O ports and MMIOs for passthroughed gfx
    
    Signed-off-by: Ben Lin <ben.y.lin@xxxxxxxxx>
    Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>x
    
    [PATCH 2/2 v2]; [1/2 already applied to xen-unstable -iwj]
---
 hw/pass-through.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pass-through.h |    6 ++
 hw/pc.c           |   51 ++++++++++--------
 vl.c              |   32 ++++++++++--
 4 files changed, 220 insertions(+), 26 deletions(-)

diff --git a/hw/pass-through.c b/hw/pass-through.c
index 8d80755..a97368a 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -93,6 +93,8 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 
+extern int gfx_passthru;
+
 struct php_dev {
     struct pt_dev *pt_dev;
     uint8_t valid;
@@ -1781,12 +1783,57 @@ static int pt_dev_is_virtfn(struct pci_dev *dev)
     return rc;
 }
 
+/*
+ * register VGA resources for the domain with assigned gfx
+ */
+static int register_vga_regions(struct pt_dev *real_device)
+{
+    int ret = 0;
+
+    ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3B0,
+            0x3B0, 0xC, DPCI_ADD_MAPPING);
+
+    ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3C0,
+            0x3C0, 0x20, DPCI_ADD_MAPPING);
+
+    ret |= xc_domain_memory_mapping(xc_handle, domid,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0x20,
+            DPCI_ADD_MAPPING);
+
+    return ret;
+}
+
+/*
+ * unregister VGA resources for the domain with assigned gfx
+ */
+static int unregister_vga_regions(struct pt_dev *real_device)
+{
+    int ret = 0;
+
+    ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3B0,
+            0x3B0, 0xC, DPCI_REMOVE_MAPPING);
+
+    ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3C0,
+            0x3C0, 0x20, DPCI_REMOVE_MAPPING);
+
+    ret |= xc_domain_memory_mapping(xc_handle, domid,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0xa0000 >> XC_PAGE_SHIFT,
+            0x20,
+            DPCI_REMOVE_MAPPING);
+
+    return ret;
+}
+
 static int pt_register_regions(struct pt_dev *assigned_device)
 {
     int i = 0;
     uint32_t bar_data = 0;
     struct pci_dev *pci_dev = assigned_device->pci_dev;
     PCIDevice *d = &assigned_device->dev;
+    int ret;
 
     /* Register PIO/MMIO BARs */
     for ( i = 0; i < PCI_BAR_ENTRIES; i++ )
@@ -1842,6 +1889,16 @@ static int pt_register_regions(struct pt_dev 
*assigned_device)
             (uint32_t)(pci_dev->rom_size), (uint32_t)(pci_dev->rom_base_addr));
     }
 
+    if ( gfx_passthru && (pci_dev->device_class == 0x0300) )
+    {
+        ret = register_vga_regions(assigned_device);
+        if ( ret != 0 )
+        {
+            PT_LOG("VGA region mapping failed\n");
+            return ret;
+        }
+    }
+
     return 0;
 }
 
@@ -1891,6 +1948,12 @@ static void pt_unregister_regions(struct pt_dev 
*assigned_device)
 
     }
 
+    if ( gfx_passthru && (assigned_device->pci_dev->device_class == 0x0300) )
+    {
+        ret = unregister_vga_regions(assigned_device);
+        if ( ret != 0 )
+            PT_LOG("VGA region unmapping failed\n");
+    }
 }
 
 static uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
@@ -4013,6 +4076,89 @@ static int pt_pmcsr_reg_restore(struct pt_dev *ptdev,
     return 0;
 }
 
+static int get_vgabios(unsigned char *buf)
+{
+    int fd;
+    uint32_t bios_size = 0;
+    uint32_t start = 0xC0000;
+    uint16_t magic = 0;
+
+    if ( (fd = open("/dev/mem", O_RDONLY)) < 0 )
+    {
+        PT_LOG("Error: 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;
+}
+
+static int setup_vga_pt(void)
+{
+    unsigned char *bios = NULL;
+    int bios_size = 0;
+    char *c = NULL;
+    char checksum = 0;
+    int rc = 0;
+
+    /* Allocated 64K for the vga bios */
+    if ( !(bios = malloc(64 * 1024)) )
+        return -1;
+
+    bios_size = get_vgabios(bios);
+    if ( bios_size == 0 || bios_size > 64 * 1024)
+    {
+        PT_LOG("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;
+
+    cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
+
+out:
+    free(bios);
+    return rc;
+}
+
 static struct pt_dev * register_real_device(PCIBus *e_bus,
         const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev,
         uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access,
@@ -4123,6 +4269,17 @@ static struct pt_dev * register_real_device(PCIBus 
*e_bus,
     /* Handle real device's MMIO/PIO BARs */
     pt_register_regions(assigned_device);
 
+    /* Setup VGA bios for passthroughed gfx */
+    if ( gfx_passthru && (assigned_device->pci_dev->device_class == 0x0300) )
+    {
+        rc = setup_vga_pt();
+        if ( rc < 0 )
+        {
+            PT_LOG("Setup VGA BIOS of passthroughed gfx failed!\n");
+            return NULL;
+        }
+    }
+
     /* reinitialize each config register to be emulated */
     rc = pt_config_init(assigned_device);
     if ( rc < 0 ) {
diff --git a/hw/pass-through.h b/hw/pass-through.h
index 028a03e..956e228 100644
--- a/hw/pass-through.h
+++ b/hw/pass-through.h
@@ -142,6 +142,12 @@ enum {
     GRP_TYPE_EMU,                               /* emul reg group */
 };
 
+enum {
+    GFX_NO_PASSTHRU = 0,                        /* No gfx pass-through */
+    GFX_IGD_PASSTHRU,                           /* IGD pass-through */
+    GFX_DISCRETE_PASSTHRU,                      /* Discrete gfx pass-through */
+};
+
 #define PT_GET_EMUL_SIZE(flag, r_size) do { \
     if (flag == PT_BAR_FLAG_MEM) {\
         r_size = (((r_size) + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1)); \
diff --git a/hw/pc.c b/hw/pc.c
index 129e9d9..53b59c0 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -41,6 +41,7 @@
 #include "virtio-balloon.h"
 #include "virtio-console.h"
 #include "hpet_emul.h"
+#include "pass-through.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -65,6 +66,8 @@ void tpm_tis_init(SetIRQFunc *set_irq, void *opaque, int irq);
 extern uint8_t *acpi_tables;
 extern size_t acpi_tables_len;
 
+extern int gfx_passthru;
+
 static fdctrl_t *floppy_controller;
 static RTCState *rtc_state;
 static PITState *pit;
@@ -983,30 +986,34 @@ vga_bios_error:
 
     register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
 
-    if (cirrus_vga_enabled) {
-        if (pci_enabled) {
-            pci_cirrus_vga_init(pci_bus,
-                                phys_ram_base + vga_ram_addr,
-                                vga_ram_addr, vga_ram_size);
-        } else {
-            isa_cirrus_vga_init(phys_ram_base + vga_ram_addr,
-                                vga_ram_addr, vga_ram_size);
-        }
+    if (gfx_passthru == GFX_NO_PASSTHRU) {
+       if (cirrus_vga_enabled) {
+            fprintf(logfile,"cirrus_vga_enabled\n");
+            if (pci_enabled) {
+                pci_cirrus_vga_init(pci_bus,
+                                    phys_ram_base + vga_ram_addr,
+                                    vga_ram_addr, vga_ram_size);
+            } else {
+                isa_cirrus_vga_init(phys_ram_base + vga_ram_addr,
+                                    vga_ram_addr, vga_ram_size);
+            }
 #ifndef CONFIG_DM
-    } else if (vmsvga_enabled) {
-        if (pci_enabled)
-            pci_vmsvga_init(pci_bus, phys_ram_base + vga_ram_addr,
-                            vga_ram_addr, vga_ram_size);
-        else
-            fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+        } else if (vmsvga_enabled) {
+            if (pci_enabled)
+                pci_vmsvga_init(pci_bus, phys_ram_base + vga_ram_addr,
+                                vga_ram_addr, vga_ram_size);
+            else
+                fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
 #endif
-    } else if (std_vga_enabled) {
-        if (pci_enabled) {
-            pci_vga_init(pci_bus, phys_ram_base + vga_ram_addr,
-                         vga_ram_addr, vga_ram_size, 0, 0);
-        } else {
-            isa_vga_init(phys_ram_base + vga_ram_addr,
-                         vga_ram_addr, vga_ram_size);
+        } else if (std_vga_enabled) {
+            fprintf(logfile,"std_vga_enabled\n");
+            if (pci_enabled) {
+                pci_vga_init(pci_bus, phys_ram_base + vga_ram_addr,
+                             vga_ram_addr, vga_ram_size, 0, 0);
+            } else {
+                isa_vga_init(phys_ram_base + vga_ram_addr,
+                             vga_ram_addr, vga_ram_size);
+            }
         }
     }
 
diff --git a/vl.c b/vl.c
index 06d9662..2f60aa5 100644
--- a/vl.c
+++ b/vl.c
@@ -48,6 +48,7 @@
 #include <stdlib.h>
 
 #include "qemu-xen.h"
+#include "hw/pass-through.h"
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -213,6 +214,7 @@ static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;
 int std_vga_enabled = 0;
 int vmsvga_enabled = 0;
+int gfx_passthru = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
@@ -4269,6 +4271,7 @@ enum {
     /* Xen tree: */
     QEMU_OPTION_disable_opengl,
     QEMU_OPTION_direct_pci,
+    QEMU_OPTION_gfx_passthru,
     QEMU_OPTION_pci_emulation,
     QEMU_OPTION_vncunused,
     QEMU_OPTION_videoram,
@@ -4447,6 +4450,7 @@ static const QEMUOption qemu_options[] = {
 #endif
     { "acpi", 0, QEMU_OPTION_acpi }, /* deprecated, for xend compatibility */
     { "direct_pci", HAS_ARG, QEMU_OPTION_direct_pci },
+    { "gfx_passthru", HAS_ARG, QEMU_OPTION_gfx_passthru},
     { "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation },
     { "vncunused", 0, QEMU_OPTION_vncunused },
     { "vcpus", HAS_ARG, QEMU_OPTION_vcpus },
@@ -5485,6 +5489,22 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_runas:
                 run_as = optarg;
                 break;
+            case QEMU_OPTION_gfx_passthru:
+                gfx_passthru = atoi(optarg);
+                switch (gfx_passthru) {
+                case GFX_NO_PASSTHRU:
+                    break;
+                case GFX_IGD_PASSTHRU:
+                    fprintf(logfile, "IGD graphics card passthrough\n");
+                    break;
+                case GFX_DISCRETE_PASSTHRU:
+                    fprintf(logfile, "Discrete graphics card passthrough\n");
+                    break;
+                default:
+                    fprintf(stderr, "unsupported gfx_passthru option: %d\n",
+                            gfx_passthru);
+                }
+                break;
             }
         }
     }
@@ -5898,13 +5918,17 @@ int main(int argc, char **argv, char **envp)
                         exit(1);
                    xenstore_write_vncport(vnc_display_port);
                 }
+
+                if (gfx_passthru == GFX_NO_PASSTHRU)
+                {
 #if defined(CONFIG_SDL)
-                if (sdl || !vnc_display)
-                    sdl_display_init(ds, full_screen, no_frame, 
opengl_enabled);
+                    if (sdl || !vnc_display)
+                        sdl_display_init(ds, full_screen, no_frame, 
opengl_enabled);
 #elif defined(CONFIG_COCOA)
-                if (sdl || !vnc_display)
-                    cocoa_display_init(ds, full_screen);
+                    if (sdl || !vnc_display)
+                        cocoa_display_init(ds, full_screen);
 #endif
+                }
             }
     }
     dpy_resize(ds);
--
generated by git-patchbot for /home/xen/git/qemu-xen-unstable.git

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [qemu-xen-unstable] graphics passthrough with VT-d, Ian Jackson <=