[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |