From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58019) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WzjAh-0004NP-1Y for qemu-devel@nongnu.org; Wed, 25 Jun 2014 05:07:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WzjAa-0005zv-Vr for qemu-devel@nongnu.org; Wed, 25 Jun 2014 05:07:14 -0400 Received: from mga09.intel.com ([134.134.136.24]:5012) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WzjAa-0005zp-HP for qemu-devel@nongnu.org; Wed, 25 Jun 2014 05:07:08 -0400 Message-ID: <53AA911D.1030008@intel.com> Date: Wed, 25 Jun 2014 17:06:37 +0800 From: "Chen, Tiejun" MIME-Version: 1.0 References: <1403662641-28526-1-git-send-email-tiejun.chen@intel.com> <1403662641-28526-2-git-send-email-tiejun.chen@intel.com> <20140625063545.GA25563@redhat.com> In-Reply-To: <20140625063545.GA25563@redhat.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [v5][PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "Michael S. Tsirkin" Cc: peter.maydell@linaro.org, xen-devel@lists.xensource.com, stefano.stabellini@eu.citrix.com, allen.m.kay@intel.com, qemu-devel@nongnu.org, Kelly.Zytaruk@amd.com, yang.z.zhang@intel.com, anthony@codemonkey.ws, anthony.perard@citrix.com, pbonzini@redhat.com On 2014/6/25 14:35, Michael S. Tsirkin wrote: > On Wed, Jun 25, 2014 at 10:17:17AM +0800, Tiejun Chen wrote: >> basic gfx passthrough support: >> - add a vga type for gfx passthrough >> - retrieve VGA bios from sysfs, then load it to guest at 0xC0000 >> - register/unregister legacy VGA I/O ports and MMIOs for passthrough GFX >> >> The original patch is from Weidong Han >> >> Signed-off-by: Yang Zhang >> Signed-off-by: Tiejun Chen >> Cc: Weidong Han > > ROM loading code is duplicated from assigned_dev_load_option_rom. Yes. Do you hint we need to split this? > Would it be a problem for you to create a memory region holding > the ROM? Sorry, could you tell me what should do exactly? > You won't need cpu_physical_memory_rw then, either, or need How to make sure this is fixed at 0xc0000? Thanks Tiejun > the VGA_BIOS_DEFAULT_SIZE hack. > > > > >> --- >> v5: >> >> * Just rebase. >> >> v4: >> >> * Fix some typos in the patch head description. >> * Improve some comments. >> * Given that xen_pt_register_vga_regions()/xen_pt_unregister_vga_regions() >> are called unconditionally, so we just return 0 there. >> * Remove one spurious change. >> >> v3: >> >> * Fix some typos. >> * Add more comments to make that readable. >> * Improve some return paths. >> >> v2: >> >> * retrieve VGA bios from sysfs properly. >> * redefine some function name. >> >> hw/xen/Makefile.objs | 2 +- >> hw/xen/xen-host-pci-device.c | 5 + >> hw/xen/xen-host-pci-device.h | 1 + >> hw/xen/xen_pt.c | 10 ++ >> hw/xen/xen_pt.h | 4 + >> hw/xen/xen_pt_graphics.c | 232 +++++++++++++++++++++++++++++++++++++++++++ >> qemu-options.hx | 9 ++ >> vl.c | 10 ++ >> 8 files changed, 272 insertions(+), 1 deletion(-) >> create mode 100644 hw/xen/xen_pt_graphics.c >> >> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs >> index a0ca0aa..77b7dae 100644 >> --- a/hw/xen/Makefile.objs >> +++ b/hw/xen/Makefile.objs >> @@ -2,4 +2,4 @@ >> common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o >> >> obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o >> -obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o >> +obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_pt_graphics.o >> 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..dac4238 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); >> } >> >> + xen_pt_register_vga_regions(d); >> return 0; >> } >> >> @@ -470,6 +471,8 @@ static void xen_pt_unregister_regions(XenPCIPassthroughState *s) >> if (d->rom.base_addr && d->rom.size) { >> memory_region_destroy(&s->rom); >> } >> + >> + xen_pt_unregister_vga_regions(d); >> } >> >> /* region mapping */ >> @@ -693,6 +696,13 @@ static int xen_pt_initfn(PCIDevice *d) >> /* Handle real device's MMIO/PIO BARs */ >> xen_pt_register_regions(s); >> >> + /* Setup VGA bios for passthrough GFX */ >> + if (xen_pt_setup_vga(&s->real_device) < 0) { >> + XEN_PT_ERR(d, "Setup VGA BIOS of passthrough 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..4d3a18d 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 xen_has_gfx_passthru; >> +int xen_pt_register_vga_regions(XenHostPCIDevice *dev); >> +int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); >> +int xen_pt_setup_vga(XenHostPCIDevice *dev); >> >> #endif /* !XEN_PT_H */ >> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c >> new file mode 100644 >> index 0000000..461e526 >> --- /dev/null >> +++ b/hw/xen/xen_pt_graphics.c >> @@ -0,0 +1,232 @@ >> +/* >> + * graphics passthrough >> + */ >> +#include "xen_pt.h" >> +#include "xen-host-pci-device.h" >> +#include "hw/xen/xen_backend.h" >> + >> +static int is_vga_passthrough(XenHostPCIDevice *dev) >> +{ >> + return (xen_has_gfx_passthru >> + && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA)); >> +} >> + >> +typedef struct VGARegion { >> + int type; /* Memory or port I/O */ >> + uint64_t guest_base_addr; >> + uint64_t machine_base_addr; >> + uint64_t size; /* size of the region */ >> + int rc; >> +} VGARegion; >> + >> +#define IORESOURCE_IO 0x00000100 >> +#define IORESOURCE_MEM 0x00000200 >> + >> +static struct VGARegion vga_args[] = { >> + { >> + .type = IORESOURCE_IO, >> + .guest_base_addr = 0x3B0, >> + .machine_base_addr = 0x3B0, >> + .size = 0xC, >> + .rc = -1, >> + }, >> + { >> + .type = IORESOURCE_IO, >> + .guest_base_addr = 0x3C0, >> + .machine_base_addr = 0x3C0, >> + .size = 0x20, >> + .rc = -1, >> + }, >> + { >> + .type = IORESOURCE_MEM, >> + .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT, >> + .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT, >> + .size = 0x20, >> + .rc = -1, >> + }, >> +}; >> + >> +/* >> + * register VGA resources for the domain with assigned gfx >> + */ >> +int xen_pt_register_vga_regions(XenHostPCIDevice *dev) >> +{ >> + int i = 0; >> + >> + if (!is_vga_passthrough(dev)) { >> + return 0; >> + } >> + >> + for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) { >> + if (vga_args[i].type == IORESOURCE_IO) { >> + vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_ADD_MAPPING); >> + } else { >> + vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_ADD_MAPPING); >> + } >> + >> + if (vga_args[i].rc) { >> + XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n", >> + vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory", >> + vga_args[i].rc); >> + return vga_args[i].rc; >> + } >> + } >> + >> + return 0; >> +} >> + >> +/* >> + * unregister VGA resources for the domain with assigned gfx >> + */ >> +int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev) >> +{ >> + int i = 0; >> + >> + if (!is_vga_passthrough(dev)) { >> + return 0; >> + } >> + >> + for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) { >> + if (vga_args[i].type == IORESOURCE_IO) { >> + vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_REMOVE_MAPPING); >> + } else { >> + vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_REMOVE_MAPPING); >> + } >> + >> + if (vga_args[i].rc) { >> + XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n", >> + vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory", >> + vga_args[i].rc); >> + return vga_args[i].rc; >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int get_vgabios(unsigned char *buf, XenHostPCIDevice *dev) >> +{ >> + char rom_file[64]; >> + FILE *fp; >> + uint8_t val; >> + struct stat st; >> + uint16_t magic = 0; >> + int ret = 0; >> + >> + snprintf(rom_file, sizeof(rom_file), >> + "/sys/bus/pci/devices/%04x:%02x:%02x.%d/rom", >> + dev->domain, dev->bus, dev->dev, >> + dev->func); >> + >> + if (stat(rom_file, &st)) { >> + return -ENODEV; >> + } >> + >> + if (access(rom_file, F_OK)) { >> + XEN_PT_ERR(NULL, "pci-assign: Insufficient privileges for %s", >> + rom_file); >> + return -ENODEV; >> + } >> + >> + /* Write "1" to the ROM file to enable it */ >> + fp = fopen(rom_file, "r+"); >> + if (fp == NULL) { >> + return -EACCES; >> + } >> + val = 1; >> + if (fwrite(&val, 1, 1, fp) != 1) { >> + XEN_PT_LOG("%s\n", "Failed to enable pci-sysfs rom file"); >> + ret = -EIO; >> + goto close_rom; >> + } >> + fseek(fp, 0, SEEK_SET); >> + >> + /* >> + * Check if it a real bios extension. >> + * The magic number is 0xAA55. >> + */ >> + if (!fread(&magic, sizeof(magic), 1, fp)) { >> + XEN_PT_ERR(NULL, "VGA: can't get magic.\n"); >> + ret = -ENODEV; >> + goto close_rom; >> + } >> + if (magic != 0xAA55) { >> + XEN_PT_ERR(NULL, "VGA: wrong magic %x.\n", magic); >> + ret = -ENODEV; >> + goto close_rom; >> + } >> + fseek(fp, 0, SEEK_SET); >> + >> + if (!fread(buf, 1, st.st_size, fp)) { >> + XEN_PT_ERR(NULL, "VGA: pci-assign: Cannot read from host %s", rom_file); >> + XEN_PT_LOG(NULL, "VGA: Device option ROM contents are probably invalid " >> + "(check dmesg).\nSkip option ROM probe with rombar=0, " >> + "or load from file with romfile=\n"); >> + } >> + >> +close_rom: >> + /* Write "0" to disable ROM */ >> + fseek(fp, 0, SEEK_SET); >> + val = 0; >> + if (!fwrite(&val, 1, 1, fp)) { >> + ret = -EIO; >> + XEN_PT_LOG("%s\n", "Failed to disable pci-sysfs rom file"); >> + } >> + fclose(fp); >> + return ret; >> +} >> + >> +/* Allocated 128K for the vga bios */ >> +#define VGA_BIOS_DEFAULT_SIZE (0x20000) >> + >> +int xen_pt_setup_vga(XenHostPCIDevice *dev) >> +{ >> + unsigned char *bios = NULL; >> + int bios_size = 0; >> + char *c = NULL; >> + char checksum = 0; >> + int rc = 0; >> + >> + if (!is_vga_passthrough(dev)) { >> + return rc; >> + } >> + >> + bios = g_malloc0(VGA_BIOS_DEFAULT_SIZE); >> + >> + bios_size = get_vgabios(bios, dev); >> + if (bios_size) { >> + XEN_PT_ERR(NULL, "VGA: Error %d getting VBIOS!\n", bios_size); >> + if (bios_size < 0) { >> + XEN_PT_ERR(NULL, "VGA: Error (%s).\n", strerror(bios_size)); >> + } >> + rc = -1; >> + goto out; >> + } >> + >> + /* Adjust the bios checksum */ > > It's easy to see that you do this here, but *why* do you do it? > That's what the comment should explain. > Do you see many ROMs with an invalid checksum > in the field? > >> + 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"); >> + } >> + >> + /* Currently we fixed this address as a primary. */ >> + cpu_physical_memory_rw(0xc0000, bios, bios_size, 1); >> +out: >> + g_free(bios); >> + return rc; >> +} >> diff --git a/qemu-options.hx b/qemu-options.hx >> index ff76ad4..1c77baa 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -1066,6 +1066,15 @@ STEXI >> Rotate graphical output some deg left (only PXA LCD). >> ETEXI >> >> +DEF("gfx_passthru", 0, QEMU_OPTION_gfx_passthru, >> + "-gfx_passthru enable Intel IGD passthrough by XEN\n", >> + QEMU_ARCH_ALL) >> +STEXI >> +@item -gfx_passthru >> +@findex -gfx_passthru >> +Enable Intel IGD passthrough by XEN >> +ETEXI >> + >> DEF("vga", HAS_ARG, QEMU_OPTION_vga, >> "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|none]\n" >> " select video card type\n", QEMU_ARCH_ALL) >> diff --git a/vl.c b/vl.c >> index a1686ef..c5b572d 100644 >> --- a/vl.c >> +++ b/vl.c >> @@ -1418,6 +1418,13 @@ static void configure_msg(QemuOpts *opts) >> enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true); >> } >> >> +/* We still need this for compatibility with XEN. */ >> +int xen_has_gfx_passthru; >> +static void xen_gfx_passthru(const char *optarg) >> +{ >> + xen_has_gfx_passthru = 1; >> +} >> + >> /***********************************************************/ >> /* USB devices */ >> >> @@ -3945,6 +3952,9 @@ int main(int argc, char **argv, char **envp) >> exit(1); >> } >> break; >> + case QEMU_OPTION_gfx_passthru: >> + xen_gfx_passthru(optarg); >> + break; >> default: >> os_parse_cmd_args(popt->index, optarg); >> } >> -- >> 1.9.1 > > From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Chen, Tiejun" Subject: Re: [v5][PATCH 1/5] xen, gfx passthrough: basic graphics passthrough support Date: Wed, 25 Jun 2014 17:06:37 +0800 Message-ID: <53AA911D.1030008@intel.com> References: <1403662641-28526-1-git-send-email-tiejun.chen@intel.com> <1403662641-28526-2-git-send-email-tiejun.chen@intel.com> <20140625063545.GA25563@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; Format="flowed" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20140625063545.GA25563@redhat.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: "Michael S. Tsirkin" Cc: peter.maydell@linaro.org, xen-devel@lists.xensource.com, stefano.stabellini@eu.citrix.com, allen.m.kay@intel.com, qemu-devel@nongnu.org, Kelly.Zytaruk@amd.com, yang.z.zhang@intel.com, anthony@codemonkey.ws, anthony.perard@citrix.com, pbonzini@redhat.com List-Id: xen-devel@lists.xenproject.org On 2014/6/25 14:35, Michael S. Tsirkin wrote: > On Wed, Jun 25, 2014 at 10:17:17AM +0800, Tiejun Chen wrote: >> basic gfx passthrough support: >> - add a vga type for gfx passthrough >> - retrieve VGA bios from sysfs, then load it to guest at 0xC0000 >> - register/unregister legacy VGA I/O ports and MMIOs for passthrough GFX >> >> The original patch is from Weidong Han >> >> Signed-off-by: Yang Zhang >> Signed-off-by: Tiejun Chen >> Cc: Weidong Han > > ROM loading code is duplicated from assigned_dev_load_option_rom. Yes. Do you hint we need to split this? > Would it be a problem for you to create a memory region holding > the ROM? Sorry, could you tell me what should do exactly? > You won't need cpu_physical_memory_rw then, either, or need How to make sure this is fixed at 0xc0000? Thanks Tiejun > the VGA_BIOS_DEFAULT_SIZE hack. > > > > >> --- >> v5: >> >> * Just rebase. >> >> v4: >> >> * Fix some typos in the patch head description. >> * Improve some comments. >> * Given that xen_pt_register_vga_regions()/xen_pt_unregister_vga_regions() >> are called unconditionally, so we just return 0 there. >> * Remove one spurious change. >> >> v3: >> >> * Fix some typos. >> * Add more comments to make that readable. >> * Improve some return paths. >> >> v2: >> >> * retrieve VGA bios from sysfs properly. >> * redefine some function name. >> >> hw/xen/Makefile.objs | 2 +- >> hw/xen/xen-host-pci-device.c | 5 + >> hw/xen/xen-host-pci-device.h | 1 + >> hw/xen/xen_pt.c | 10 ++ >> hw/xen/xen_pt.h | 4 + >> hw/xen/xen_pt_graphics.c | 232 +++++++++++++++++++++++++++++++++++++++++++ >> qemu-options.hx | 9 ++ >> vl.c | 10 ++ >> 8 files changed, 272 insertions(+), 1 deletion(-) >> create mode 100644 hw/xen/xen_pt_graphics.c >> >> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs >> index a0ca0aa..77b7dae 100644 >> --- a/hw/xen/Makefile.objs >> +++ b/hw/xen/Makefile.objs >> @@ -2,4 +2,4 @@ >> common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o >> >> obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o >> -obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o >> +obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_pt_graphics.o >> 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..dac4238 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); >> } >> >> + xen_pt_register_vga_regions(d); >> return 0; >> } >> >> @@ -470,6 +471,8 @@ static void xen_pt_unregister_regions(XenPCIPassthroughState *s) >> if (d->rom.base_addr && d->rom.size) { >> memory_region_destroy(&s->rom); >> } >> + >> + xen_pt_unregister_vga_regions(d); >> } >> >> /* region mapping */ >> @@ -693,6 +696,13 @@ static int xen_pt_initfn(PCIDevice *d) >> /* Handle real device's MMIO/PIO BARs */ >> xen_pt_register_regions(s); >> >> + /* Setup VGA bios for passthrough GFX */ >> + if (xen_pt_setup_vga(&s->real_device) < 0) { >> + XEN_PT_ERR(d, "Setup VGA BIOS of passthrough 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..4d3a18d 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 xen_has_gfx_passthru; >> +int xen_pt_register_vga_regions(XenHostPCIDevice *dev); >> +int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); >> +int xen_pt_setup_vga(XenHostPCIDevice *dev); >> >> #endif /* !XEN_PT_H */ >> diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c >> new file mode 100644 >> index 0000000..461e526 >> --- /dev/null >> +++ b/hw/xen/xen_pt_graphics.c >> @@ -0,0 +1,232 @@ >> +/* >> + * graphics passthrough >> + */ >> +#include "xen_pt.h" >> +#include "xen-host-pci-device.h" >> +#include "hw/xen/xen_backend.h" >> + >> +static int is_vga_passthrough(XenHostPCIDevice *dev) >> +{ >> + return (xen_has_gfx_passthru >> + && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA)); >> +} >> + >> +typedef struct VGARegion { >> + int type; /* Memory or port I/O */ >> + uint64_t guest_base_addr; >> + uint64_t machine_base_addr; >> + uint64_t size; /* size of the region */ >> + int rc; >> +} VGARegion; >> + >> +#define IORESOURCE_IO 0x00000100 >> +#define IORESOURCE_MEM 0x00000200 >> + >> +static struct VGARegion vga_args[] = { >> + { >> + .type = IORESOURCE_IO, >> + .guest_base_addr = 0x3B0, >> + .machine_base_addr = 0x3B0, >> + .size = 0xC, >> + .rc = -1, >> + }, >> + { >> + .type = IORESOURCE_IO, >> + .guest_base_addr = 0x3C0, >> + .machine_base_addr = 0x3C0, >> + .size = 0x20, >> + .rc = -1, >> + }, >> + { >> + .type = IORESOURCE_MEM, >> + .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT, >> + .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT, >> + .size = 0x20, >> + .rc = -1, >> + }, >> +}; >> + >> +/* >> + * register VGA resources for the domain with assigned gfx >> + */ >> +int xen_pt_register_vga_regions(XenHostPCIDevice *dev) >> +{ >> + int i = 0; >> + >> + if (!is_vga_passthrough(dev)) { >> + return 0; >> + } >> + >> + for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) { >> + if (vga_args[i].type == IORESOURCE_IO) { >> + vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_ADD_MAPPING); >> + } else { >> + vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_ADD_MAPPING); >> + } >> + >> + if (vga_args[i].rc) { >> + XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n", >> + vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory", >> + vga_args[i].rc); >> + return vga_args[i].rc; >> + } >> + } >> + >> + return 0; >> +} >> + >> +/* >> + * unregister VGA resources for the domain with assigned gfx >> + */ >> +int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev) >> +{ >> + int i = 0; >> + >> + if (!is_vga_passthrough(dev)) { >> + return 0; >> + } >> + >> + for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) { >> + if (vga_args[i].type == IORESOURCE_IO) { >> + vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_REMOVE_MAPPING); >> + } else { >> + vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid, >> + vga_args[i].guest_base_addr, >> + vga_args[i].machine_base_addr, >> + vga_args[i].size, DPCI_REMOVE_MAPPING); >> + } >> + >> + if (vga_args[i].rc) { >> + XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n", >> + vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory", >> + vga_args[i].rc); >> + return vga_args[i].rc; >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int get_vgabios(unsigned char *buf, XenHostPCIDevice *dev) >> +{ >> + char rom_file[64]; >> + FILE *fp; >> + uint8_t val; >> + struct stat st; >> + uint16_t magic = 0; >> + int ret = 0; >> + >> + snprintf(rom_file, sizeof(rom_file), >> + "/sys/bus/pci/devices/%04x:%02x:%02x.%d/rom", >> + dev->domain, dev->bus, dev->dev, >> + dev->func); >> + >> + if (stat(rom_file, &st)) { >> + return -ENODEV; >> + } >> + >> + if (access(rom_file, F_OK)) { >> + XEN_PT_ERR(NULL, "pci-assign: Insufficient privileges for %s", >> + rom_file); >> + return -ENODEV; >> + } >> + >> + /* Write "1" to the ROM file to enable it */ >> + fp = fopen(rom_file, "r+"); >> + if (fp == NULL) { >> + return -EACCES; >> + } >> + val = 1; >> + if (fwrite(&val, 1, 1, fp) != 1) { >> + XEN_PT_LOG("%s\n", "Failed to enable pci-sysfs rom file"); >> + ret = -EIO; >> + goto close_rom; >> + } >> + fseek(fp, 0, SEEK_SET); >> + >> + /* >> + * Check if it a real bios extension. >> + * The magic number is 0xAA55. >> + */ >> + if (!fread(&magic, sizeof(magic), 1, fp)) { >> + XEN_PT_ERR(NULL, "VGA: can't get magic.\n"); >> + ret = -ENODEV; >> + goto close_rom; >> + } >> + if (magic != 0xAA55) { >> + XEN_PT_ERR(NULL, "VGA: wrong magic %x.\n", magic); >> + ret = -ENODEV; >> + goto close_rom; >> + } >> + fseek(fp, 0, SEEK_SET); >> + >> + if (!fread(buf, 1, st.st_size, fp)) { >> + XEN_PT_ERR(NULL, "VGA: pci-assign: Cannot read from host %s", rom_file); >> + XEN_PT_LOG(NULL, "VGA: Device option ROM contents are probably invalid " >> + "(check dmesg).\nSkip option ROM probe with rombar=0, " >> + "or load from file with romfile=\n"); >> + } >> + >> +close_rom: >> + /* Write "0" to disable ROM */ >> + fseek(fp, 0, SEEK_SET); >> + val = 0; >> + if (!fwrite(&val, 1, 1, fp)) { >> + ret = -EIO; >> + XEN_PT_LOG("%s\n", "Failed to disable pci-sysfs rom file"); >> + } >> + fclose(fp); >> + return ret; >> +} >> + >> +/* Allocated 128K for the vga bios */ >> +#define VGA_BIOS_DEFAULT_SIZE (0x20000) >> + >> +int xen_pt_setup_vga(XenHostPCIDevice *dev) >> +{ >> + unsigned char *bios = NULL; >> + int bios_size = 0; >> + char *c = NULL; >> + char checksum = 0; >> + int rc = 0; >> + >> + if (!is_vga_passthrough(dev)) { >> + return rc; >> + } >> + >> + bios = g_malloc0(VGA_BIOS_DEFAULT_SIZE); >> + >> + bios_size = get_vgabios(bios, dev); >> + if (bios_size) { >> + XEN_PT_ERR(NULL, "VGA: Error %d getting VBIOS!\n", bios_size); >> + if (bios_size < 0) { >> + XEN_PT_ERR(NULL, "VGA: Error (%s).\n", strerror(bios_size)); >> + } >> + rc = -1; >> + goto out; >> + } >> + >> + /* Adjust the bios checksum */ > > It's easy to see that you do this here, but *why* do you do it? > That's what the comment should explain. > Do you see many ROMs with an invalid checksum > in the field? > >> + 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"); >> + } >> + >> + /* Currently we fixed this address as a primary. */ >> + cpu_physical_memory_rw(0xc0000, bios, bios_size, 1); >> +out: >> + g_free(bios); >> + return rc; >> +} >> diff --git a/qemu-options.hx b/qemu-options.hx >> index ff76ad4..1c77baa 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -1066,6 +1066,15 @@ STEXI >> Rotate graphical output some deg left (only PXA LCD). >> ETEXI >> >> +DEF("gfx_passthru", 0, QEMU_OPTION_gfx_passthru, >> + "-gfx_passthru enable Intel IGD passthrough by XEN\n", >> + QEMU_ARCH_ALL) >> +STEXI >> +@item -gfx_passthru >> +@findex -gfx_passthru >> +Enable Intel IGD passthrough by XEN >> +ETEXI >> + >> DEF("vga", HAS_ARG, QEMU_OPTION_vga, >> "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|none]\n" >> " select video card type\n", QEMU_ARCH_ALL) >> diff --git a/vl.c b/vl.c >> index a1686ef..c5b572d 100644 >> --- a/vl.c >> +++ b/vl.c >> @@ -1418,6 +1418,13 @@ static void configure_msg(QemuOpts *opts) >> enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true); >> } >> >> +/* We still need this for compatibility with XEN. */ >> +int xen_has_gfx_passthru; >> +static void xen_gfx_passthru(const char *optarg) >> +{ >> + xen_has_gfx_passthru = 1; >> +} >> + >> /***********************************************************/ >> /* USB devices */ >> >> @@ -3945,6 +3952,9 @@ int main(int argc, char **argv, char **envp) >> exit(1); >> } >> break; >> + case QEMU_OPTION_gfx_passthru: >> + xen_gfx_passthru(optarg); >> + break; >> default: >> os_parse_cmd_args(popt->index, optarg); >> } >> -- >> 1.9.1 > >