aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/xen/xen_pt.c10
-rw-r--r--hw/xen/xen_pt.h5
-rw-r--r--hw/xen/xen_pt_graphics.c79
3 files changed, 94 insertions, 0 deletions
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index 42380c3976..15b02cbd98 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -725,6 +725,16 @@ static int xen_pt_initfn(PCIDevice *d)
s->memory_listener = xen_pt_memory_listener;
s->io_listener = xen_pt_io_listener;
+ /* Setup VGA bios for passthrough GFX */
+ if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
+ (s->real_device.dev == 2) && (s->real_device.func == 0)) {
+ if (xen_pt_setup_vga(s, &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;
+ }
+ }
+
/* Handle real device's MMIO/PIO BARs */
xen_pt_register_regions(s, &cmd);
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 5eb3c52546..a33e95ceb2 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -305,6 +305,11 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
return s->msix && s->msix->bar_index == bar;
}
+extern void *pci_assign_dev_load_option_rom(PCIDevice *dev,
+ struct Object *owner, int *size,
+ unsigned int domain,
+ unsigned int bus, unsigned int slot,
+ unsigned int function);
extern bool has_igd_gfx_passthru;
static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
{
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 9b3df811b1..3232296bf8 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -109,3 +109,82 @@ int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
return 0;
}
+
+static void *get_vgabios(XenPCIPassthroughState *s, int *size,
+ XenHostPCIDevice *dev)
+{
+ return pci_assign_dev_load_option_rom(&s->dev, OBJECT(&s->dev), size,
+ dev->domain, dev->bus,
+ dev->dev, dev->func);
+}
+
+/* Refer to Seabios. */
+struct rom_header {
+ uint16_t signature;
+ uint8_t size;
+ uint8_t initVector[4];
+ uint8_t reserved[17];
+ uint16_t pcioffset;
+ uint16_t pnpoffset;
+} __attribute__((packed));
+
+struct pci_data {
+ uint32_t signature;
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t vitaldata;
+ uint16_t dlen;
+ uint8_t drevision;
+ uint8_t class_lo;
+ uint16_t class_hi;
+ uint16_t ilen;
+ uint16_t irevision;
+ uint8_t type;
+ uint8_t indicator;
+ uint16_t reserved;
+} __attribute__((packed));
+
+int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev)
+{
+ unsigned char *bios = NULL;
+ struct rom_header *rom;
+ int bios_size;
+ char *c = NULL;
+ char checksum = 0;
+ uint32_t len = 0;
+ struct pci_data *pd = NULL;
+
+ if (!is_igd_vga_passthrough(dev)) {
+ return -1;
+ }
+
+ bios = get_vgabios(s, &bios_size, dev);
+ if (!bios) {
+ XEN_PT_ERR(&s->dev, "VGA: Can't getting VBIOS!\n");
+ return -1;
+ }
+
+ /* Currently we fixed this address as a primary. */
+ rom = (struct rom_header *)bios;
+ pd = (void *)(bios + (unsigned char)rom->pcioffset);
+
+ /* We may need to fixup Device Identification. */
+ if (pd->device != s->real_device.device_id) {
+ pd->device = s->real_device.device_id;
+
+ len = rom->size * 512;
+ /* Then adjust the bios checksum */
+ for (c = (char *)bios; c < ((char *)bios + len); c++) {
+ checksum += *c;
+ }
+ if (checksum) {
+ bios[len - 1] -= checksum;
+ XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
+ checksum);
+ }
+ }
+
+ /* Currently we fixed this address as a primary for legacy BIOS. */
+ cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
+ return 0;
+}