]> git.proxmox.com Git - mirror_qemu.git/blob - hw/xen/xen_pt_graphics.c
xen, gfx passthrough: retrieve VGA BIOS to work
[mirror_qemu.git] / hw / xen / xen_pt_graphics.c
1 /*
2 * graphics passthrough
3 */
4 #include "xen_pt.h"
5 #include "xen-host-pci-device.h"
6 #include "hw/xen/xen_backend.h"
7
8 typedef struct VGARegion {
9 int type; /* Memory or port I/O */
10 uint64_t guest_base_addr;
11 uint64_t machine_base_addr;
12 uint64_t size; /* size of the region */
13 int rc;
14 } VGARegion;
15
16 #define IORESOURCE_IO 0x00000100
17 #define IORESOURCE_MEM 0x00000200
18
19 static struct VGARegion vga_args[] = {
20 {
21 .type = IORESOURCE_IO,
22 .guest_base_addr = 0x3B0,
23 .machine_base_addr = 0x3B0,
24 .size = 0xC,
25 .rc = -1,
26 },
27 {
28 .type = IORESOURCE_IO,
29 .guest_base_addr = 0x3C0,
30 .machine_base_addr = 0x3C0,
31 .size = 0x20,
32 .rc = -1,
33 },
34 {
35 .type = IORESOURCE_MEM,
36 .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
37 .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
38 .size = 0x20,
39 .rc = -1,
40 },
41 };
42
43 /*
44 * register VGA resources for the domain with assigned gfx
45 */
46 int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
47 {
48 int i = 0;
49
50 if (!is_igd_vga_passthrough(dev)) {
51 return 0;
52 }
53
54 for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
55 if (vga_args[i].type == IORESOURCE_IO) {
56 vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
57 vga_args[i].guest_base_addr,
58 vga_args[i].machine_base_addr,
59 vga_args[i].size, DPCI_ADD_MAPPING);
60 } else {
61 vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
62 vga_args[i].guest_base_addr,
63 vga_args[i].machine_base_addr,
64 vga_args[i].size, DPCI_ADD_MAPPING);
65 }
66
67 if (vga_args[i].rc) {
68 XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
69 vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
70 vga_args[i].rc);
71 return vga_args[i].rc;
72 }
73 }
74
75 return 0;
76 }
77
78 /*
79 * unregister VGA resources for the domain with assigned gfx
80 */
81 int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
82 {
83 int i = 0;
84
85 if (!is_igd_vga_passthrough(dev)) {
86 return 0;
87 }
88
89 for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
90 if (vga_args[i].type == IORESOURCE_IO) {
91 vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
92 vga_args[i].guest_base_addr,
93 vga_args[i].machine_base_addr,
94 vga_args[i].size, DPCI_REMOVE_MAPPING);
95 } else {
96 vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
97 vga_args[i].guest_base_addr,
98 vga_args[i].machine_base_addr,
99 vga_args[i].size, DPCI_REMOVE_MAPPING);
100 }
101
102 if (vga_args[i].rc) {
103 XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
104 vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
105 vga_args[i].rc);
106 return vga_args[i].rc;
107 }
108 }
109
110 return 0;
111 }
112
113 static void *get_vgabios(XenPCIPassthroughState *s, int *size,
114 XenHostPCIDevice *dev)
115 {
116 return pci_assign_dev_load_option_rom(&s->dev, OBJECT(&s->dev), size,
117 dev->domain, dev->bus,
118 dev->dev, dev->func);
119 }
120
121 /* Refer to Seabios. */
122 struct rom_header {
123 uint16_t signature;
124 uint8_t size;
125 uint8_t initVector[4];
126 uint8_t reserved[17];
127 uint16_t pcioffset;
128 uint16_t pnpoffset;
129 } __attribute__((packed));
130
131 struct pci_data {
132 uint32_t signature;
133 uint16_t vendor;
134 uint16_t device;
135 uint16_t vitaldata;
136 uint16_t dlen;
137 uint8_t drevision;
138 uint8_t class_lo;
139 uint16_t class_hi;
140 uint16_t ilen;
141 uint16_t irevision;
142 uint8_t type;
143 uint8_t indicator;
144 uint16_t reserved;
145 } __attribute__((packed));
146
147 int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev)
148 {
149 unsigned char *bios = NULL;
150 struct rom_header *rom;
151 int bios_size;
152 char *c = NULL;
153 char checksum = 0;
154 uint32_t len = 0;
155 struct pci_data *pd = NULL;
156
157 if (!is_igd_vga_passthrough(dev)) {
158 return -1;
159 }
160
161 bios = get_vgabios(s, &bios_size, dev);
162 if (!bios) {
163 XEN_PT_ERR(&s->dev, "VGA: Can't getting VBIOS!\n");
164 return -1;
165 }
166
167 /* Currently we fixed this address as a primary. */
168 rom = (struct rom_header *)bios;
169 pd = (void *)(bios + (unsigned char)rom->pcioffset);
170
171 /* We may need to fixup Device Identification. */
172 if (pd->device != s->real_device.device_id) {
173 pd->device = s->real_device.device_id;
174
175 len = rom->size * 512;
176 /* Then adjust the bios checksum */
177 for (c = (char *)bios; c < ((char *)bios + len); c++) {
178 checksum += *c;
179 }
180 if (checksum) {
181 bios[len - 1] -= checksum;
182 XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
183 checksum);
184 }
185 }
186
187 /* Currently we fixed this address as a primary for legacy BIOS. */
188 cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
189 return 0;
190 }