[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [qemu-xen-unstable] passthrough: basic graphics passthrough support



commit f09a5ba89434bb3f28172640354258d1d6cd8579
Author: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Date:   Fri Sep 18 16:41:42 2009 +0100

    passthrough: basic graphics passthrough support
    
    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
    
    Signed-off-by: Ben Lin <ben.y.lin@xxxxxxxxx>
    Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
    Acked-by: Jean Guyader <jean.guyader@xxxxxxxxxx>
    Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---
 hw/pass-through.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 sysemu.h          |    1 +
 vl.c              |   13 ++++-
 3 files changed, 170 insertions(+), 1 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/sysemu.h b/sysemu.h
index fb44005..d4e7514 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -85,6 +85,7 @@ extern int bios_size;
 extern int cirrus_vga_enabled;
 extern int std_vga_enabled;
 extern int vmsvga_enabled;
+extern int gfx_passthru;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
diff --git a/vl.c b/vl.c
index 4a331f8..e916561 100644
--- a/vl.c
+++ b/vl.c
@@ -213,6 +213,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;
@@ -4042,7 +4043,7 @@ static void help(int exitcode)
 #endif
 #endif
            "-portrait       rotate graphical output 90 deg left (only PXA 
LCD)\n"
-           "-vga [std|cirrus|vmware|none]\n"
+           "-vga [std|cirrus|vmware|passthrough|none]\n"
            "                select video card type\n"
            "-full-screen    start in full screen\n"
 #if defined(TARGET_PPC) || defined(TARGET_SPARC)
@@ -4269,6 +4270,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 +4449,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", 0, QEMU_OPTION_gfx_passthru},
     { "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation },
     { "vncunused", 0, QEMU_OPTION_vncunused },
     { "vcpus", HAS_ARG, QEMU_OPTION_vcpus },
@@ -4623,6 +4626,11 @@ static void select_vgahw (const char *p)
         cirrus_vga_enabled = 0;
         std_vga_enabled = 0;
         vmsvga_enabled = 1;
+    } else if (strstart(p, "passthrough", &opts)) {
+        cirrus_vga_enabled = 0;
+        std_vga_enabled = 0;
+        vmsvga_enabled = 0;
+        gfx_passthru = 1;
     } else if (strstart(p, "none", &opts)) {
         cirrus_vga_enabled = 0;
         std_vga_enabled = 0;
@@ -5485,6 +5493,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_runas:
                 run_as = optarg;
                 break;
+            case QEMU_OPTION_gfx_passthru:
+                select_vgahw("passthrough");
+                break;
             }
         }
     }
--
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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.