| 
									
										
										
										
											2015-07-15 13:37:45 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * graphics passthrough | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:06 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
											  
											
												include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef.  Since then, we've moved to include qemu/osdep.h
everywhere.  Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h.  That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h.  Include qapi/error.h in .c files that need it and don't
get it now.  Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly.  Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h.  Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third.  Unfortunately, the number depending on
qapi-types.h shrinks only a little.  More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
											
										 
											2016-03-14 09:01:28 +01:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:45 +08:00
										 |  |  | #include "xen_pt.h"
 | 
					
						
							|  |  |  | #include "xen-host-pci-device.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  | #include "hw/xen/xen-legacy-backend.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:50 +08:00
										 |  |  | static unsigned long igd_guest_opregion; | 
					
						
							|  |  |  | static unsigned long igd_host_opregion; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define XEN_PCI_INTEL_OPREGION_MASK 0xfff
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:45 +08:00
										 |  |  | 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_igd_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; | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:50 +08:00
										 |  |  |     int ret = 0; | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!is_igd_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; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:50 +08:00
										 |  |  |     if (igd_guest_opregion) { | 
					
						
							|  |  |  |         ret = xc_domain_memory_mapping(xen_xc, xen_domid, | 
					
						
							|  |  |  |                 (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |                 (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |                 3, | 
					
						
							|  |  |  |                 DPCI_REMOVE_MAPPING); | 
					
						
							|  |  |  |         if (ret) { | 
					
						
							|  |  |  |             return ret; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:45 +08:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void *get_vgabios(XenPCIPassthroughState *s, int *size, | 
					
						
							|  |  |  |                        XenHostPCIDevice *dev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-06-22 13:28:42 +01:00
										 |  |  |     return pci_assign_dev_load_option_rom(&s->dev, size, | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  |                                           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)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-17 20:13:13 +08:00
										 |  |  | void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev, | 
					
						
							|  |  |  |                      Error **errp) | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     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)) { | 
					
						
							| 
									
										
										
										
											2016-01-17 20:13:13 +08:00
										 |  |  |         error_setg(errp, "Need to enable igd-passthrough"); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bios = get_vgabios(s, &bios_size, dev); | 
					
						
							|  |  |  |     if (!bios) { | 
					
						
							| 
									
										
										
										
											2016-01-17 20:13:13 +08:00
										 |  |  |         error_setg(errp, "VGA: Can't get VBIOS"); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 16:26:58 +00:00
										 |  |  |     if (bios_size < sizeof(struct rom_header)) { | 
					
						
							|  |  |  |         error_setg(errp, "VGA: VBIOS image corrupt (too small)"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  |     /* Currently we fixed this address as a primary. */ | 
					
						
							|  |  |  |     rom = (struct rom_header *)bios; | 
					
						
							| 
									
										
										
										
											2018-11-19 16:26:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (rom->pcioffset + sizeof(struct pci_data) > bios_size) { | 
					
						
							|  |  |  |         error_setg(errp, "VGA: VBIOS image corrupt (bad pcioffset field)"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2018-11-19 16:26:58 +00:00
										 |  |  |         if (len > bios_size) { | 
					
						
							|  |  |  |             error_setg(errp, "VGA: VBIOS image corrupt (bad size field)"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:46 +08:00
										 |  |  |         /* 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); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-15 13:37:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | uint32_t igd_read_opregion(XenPCIPassthroughState *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t val = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!igd_guest_opregion) { | 
					
						
							|  |  |  |         return val; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     val = igd_guest_opregion; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val); | 
					
						
							|  |  |  |     return val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define XEN_PCI_INTEL_OPREGION_PAGES 0x3
 | 
					
						
							|  |  |  | #define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
 | 
					
						
							|  |  |  | void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (igd_guest_opregion) { | 
					
						
							|  |  |  |         XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n", | 
					
						
							|  |  |  |                    val); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* We just work with LE. */ | 
					
						
							|  |  |  |     xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION, | 
					
						
							|  |  |  |             (uint8_t *)&igd_host_opregion, 4); | 
					
						
							|  |  |  |     igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK) | 
					
						
							|  |  |  |                             | (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = xc_domain_iomem_permission(xen_xc, xen_domid, | 
					
						
							|  |  |  |             (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |             XEN_PCI_INTEL_OPREGION_PAGES, | 
					
						
							|  |  |  |             XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ret) { | 
					
						
							|  |  |  |         XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:" | 
					
						
							|  |  |  |                     " 0x%lx.\n", ret, | 
					
						
							|  |  |  |                     (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)), | 
					
						
							|  |  |  |         igd_guest_opregion = 0; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = xc_domain_memory_mapping(xen_xc, xen_domid, | 
					
						
							|  |  |  |             (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |             (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |             XEN_PCI_INTEL_OPREGION_PAGES, | 
					
						
							|  |  |  |             DPCI_ADD_MAPPING); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ret) { | 
					
						
							|  |  |  |         XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to" | 
					
						
							|  |  |  |                     " guest opregion:0x%lx.\n", ret, | 
					
						
							|  |  |  |                     (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |                     (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT)); | 
					
						
							|  |  |  |         igd_guest_opregion = 0; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n", | 
					
						
							|  |  |  |                     (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), | 
					
						
							|  |  |  |                     (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT)); | 
					
						
							|  |  |  | } |