]>
Commit | Line | Data |
---|---|---|
79814179 TC |
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 | } | |
881213f1 TC |
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 | } |