]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/QemuVideoDxe/Driver.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
CommitLineData
eaf4f336 1/** @file\r
2 This driver is a sample implementation of the Graphics Output Protocol for\r
3 the QEMU (Cirrus Logic 5446) video controller.\r
4\r
cd514773 5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
eaf4f336 6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
eaf4f336 8\r
9**/\r
10\r
2e77f0e7 11#include "Qemu.h"\r
1358ecb7 12#include <IndustryStandard/Acpi.h>\r
eaf4f336 13\r
ac0a286f 14EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {\r
eaf4f336 15 QemuVideoControllerDriverSupported,\r
16 QemuVideoControllerDriverStart,\r
17 QemuVideoControllerDriverStop,\r
18 0x10,\r
19 NULL,\r
20 NULL\r
21};\r
22\r
ac0a286f
MK
23QEMU_VIDEO_CARD gQemuVideoCardList[] = {\r
24 {\r
25 PCI_CLASS_DISPLAY_VGA,\r
26 CIRRUS_LOGIC_VENDOR_ID,\r
27 CIRRUS_LOGIC_5430_DEVICE_ID,\r
28 QEMU_VIDEO_CIRRUS_5430,\r
29 L"Cirrus 5430"\r
30 },{\r
31 PCI_CLASS_DISPLAY_VGA,\r
32 CIRRUS_LOGIC_VENDOR_ID,\r
33 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,\r
34 QEMU_VIDEO_CIRRUS_5430,\r
35 L"Cirrus 5430"\r
36 },{\r
37 PCI_CLASS_DISPLAY_VGA,\r
38 CIRRUS_LOGIC_VENDOR_ID,\r
39 CIRRUS_LOGIC_5446_DEVICE_ID,\r
40 QEMU_VIDEO_CIRRUS_5446,\r
41 L"Cirrus 5446"\r
42 },{\r
43 PCI_CLASS_DISPLAY_VGA,\r
44 0x1234,\r
45 0x1111,\r
46 QEMU_VIDEO_BOCHS_MMIO,\r
47 L"QEMU Standard VGA"\r
48 },{\r
49 PCI_CLASS_DISPLAY_OTHER,\r
50 0x1234,\r
51 0x1111,\r
52 QEMU_VIDEO_BOCHS_MMIO,\r
53 L"QEMU Standard VGA (secondary)"\r
54 },{\r
55 PCI_CLASS_DISPLAY_VGA,\r
56 0x1b36,\r
57 0x0100,\r
58 QEMU_VIDEO_BOCHS,\r
59 L"QEMU QXL VGA"\r
60 },{\r
61 PCI_CLASS_DISPLAY_VGA,\r
62 0x1af4,\r
63 0x1050,\r
64 QEMU_VIDEO_BOCHS_MMIO,\r
65 L"QEMU VirtIO VGA"\r
66 },{\r
67 PCI_CLASS_DISPLAY_VGA,\r
68 0x15ad,\r
69 0x0405,\r
70 QEMU_VIDEO_VMWARE_SVGA,\r
71 L"QEMU VMWare SVGA"\r
72 },{\r
73 0 /* end of list */\r
74 }\r
212aac55 75};\r
76\r
ac0a286f
MK
77static QEMU_VIDEO_CARD *\r
78QemuVideoDetect (\r
79 IN UINT8 SubClass,\r
80 IN UINT16 VendorId,\r
81 IN UINT16 DeviceId\r
212aac55 82 )\r
83{\r
ac0a286f 84 UINTN Index = 0;\r
212aac55 85\r
86 while (gQemuVideoCardList[Index].VendorId != 0) {\r
ac0a286f
MK
87 if ((gQemuVideoCardList[Index].SubClass == SubClass) &&\r
88 (gQemuVideoCardList[Index].VendorId == VendorId) &&\r
89 (gQemuVideoCardList[Index].DeviceId == DeviceId))\r
90 {\r
212aac55 91 return gQemuVideoCardList + Index;\r
92 }\r
ac0a286f 93\r
212aac55 94 Index++;\r
95 }\r
ac0a286f 96\r
212aac55 97 return NULL;\r
98}\r
99\r
eaf4f336 100/**\r
101 Check if this device is supported.\r
102\r
103 @param This The driver binding protocol.\r
104 @param Controller The controller handle to check.\r
105 @param RemainingDevicePath The remaining device path.\r
106\r
107 @retval EFI_SUCCESS The bus supports this controller.\r
108 @retval EFI_UNSUPPORTED This device isn't supported.\r
109\r
110**/\r
111EFI_STATUS\r
112EFIAPI\r
113QemuVideoControllerDriverSupported (\r
ac0a286f
MK
114 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
115 IN EFI_HANDLE Controller,\r
116 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
eaf4f336 117 )\r
118{\r
ac0a286f
MK
119 EFI_STATUS Status;\r
120 EFI_PCI_IO_PROTOCOL *PciIo;\r
121 PCI_TYPE00 Pci;\r
122 QEMU_VIDEO_CARD *Card;\r
eaf4f336 123\r
124 //\r
125 // Open the PCI I/O Protocol\r
126 //\r
127 Status = gBS->OpenProtocol (\r
128 Controller,\r
129 &gEfiPciIoProtocolGuid,\r
ac0a286f 130 (VOID **)&PciIo,\r
eaf4f336 131 This->DriverBindingHandle,\r
132 Controller,\r
133 EFI_OPEN_PROTOCOL_BY_DRIVER\r
134 );\r
135 if (EFI_ERROR (Status)) {\r
136 return Status;\r
137 }\r
138\r
139 //\r
140 // Read the PCI Configuration Header from the PCI Device\r
141 //\r
142 Status = PciIo->Pci.Read (\r
143 PciIo,\r
144 EfiPciIoWidthUint32,\r
145 0,\r
146 sizeof (Pci) / sizeof (UINT32),\r
147 &Pci\r
148 );\r
149 if (EFI_ERROR (Status)) {\r
150 goto Done;\r
151 }\r
152\r
153 Status = EFI_UNSUPPORTED;\r
70dbd163 154 if (!IS_PCI_DISPLAY (&Pci)) {\r
442c2ab8
LE
155 goto Done;\r
156 }\r
ac0a286f
MK
157\r
158 Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
212aac55 159 if (Card != NULL) {\r
70d5086c 160 DEBUG ((DEBUG_INFO, "QemuVideo: %s detected\n", Card->Name));\r
212aac55 161 Status = EFI_SUCCESS;\r
eaf4f336 162 }\r
163\r
164Done:\r
165 //\r
166 // Close the PCI I/O Protocol\r
167 //\r
168 gBS->CloseProtocol (\r
ac0a286f
MK
169 Controller,\r
170 &gEfiPciIoProtocolGuid,\r
171 This->DriverBindingHandle,\r
172 Controller\r
173 );\r
eaf4f336 174\r
175 return Status;\r
176}\r
177\r
178/**\r
179 Start to process the controller.\r
180\r
181 @param This The USB bus driver binding instance.\r
182 @param Controller The controller to check.\r
183 @param RemainingDevicePath The remaining device patch.\r
184\r
185 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
186 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r
187 bus.\r
188 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
189\r
190**/\r
191EFI_STATUS\r
192EFIAPI\r
193QemuVideoControllerDriverStart (\r
ac0a286f
MK
194 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
195 IN EFI_HANDLE Controller,\r
196 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
eaf4f336 197 )\r
198{\r
ac0a286f
MK
199 EFI_TPL OldTpl;\r
200 EFI_STATUS Status;\r
201 QEMU_VIDEO_PRIVATE_DATA *Private;\r
202 BOOLEAN IsQxl;\r
203 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
204 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;\r
205 PCI_TYPE00 Pci;\r
206 QEMU_VIDEO_CARD *Card;\r
207 EFI_PCI_IO_PROTOCOL *ChildPciIo;\r
208 UINT64 SupportedVgaIo;\r
54f9b9ac 209\r
9c08bbe5
LE
210 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
211\r
eaf4f336 212 //\r
a2e75595 213 // Allocate Private context data for GOP interface.\r
eaf4f336 214 //\r
215 Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));\r
216 if (Private == NULL) {\r
9c08bbe5
LE
217 Status = EFI_OUT_OF_RESOURCES;\r
218 goto RestoreTpl;\r
eaf4f336 219 }\r
220\r
221 //\r
222 // Set up context record\r
223 //\r
ac0a286f 224 Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;\r
eaf4f336 225\r
226 //\r
227 // Open PCI I/O Protocol\r
228 //\r
229 Status = gBS->OpenProtocol (\r
230 Controller,\r
231 &gEfiPciIoProtocolGuid,\r
ac0a286f 232 (VOID **)&Private->PciIo,\r
eaf4f336 233 This->DriverBindingHandle,\r
234 Controller,\r
235 EFI_OPEN_PROTOCOL_BY_DRIVER\r
236 );\r
237 if (EFI_ERROR (Status)) {\r
d89186bc 238 goto FreePrivate;\r
eaf4f336 239 }\r
240\r
212aac55 241 //\r
242 // Read the PCI Configuration Header from the PCI Device\r
243 //\r
244 Status = Private->PciIo->Pci.Read (\r
ac0a286f
MK
245 Private->PciIo,\r
246 EfiPciIoWidthUint32,\r
247 0,\r
248 sizeof (Pci) / sizeof (UINT32),\r
249 &Pci\r
250 );\r
212aac55 251 if (EFI_ERROR (Status)) {\r
d89186bc 252 goto ClosePciIo;\r
212aac55 253 }\r
254\r
d89186bc
LE
255 //\r
256 // Determine card variant.\r
257 //\r
ac0a286f 258 Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
212aac55 259 if (Card == NULL) {\r
260 Status = EFI_DEVICE_ERROR;\r
d89186bc 261 goto ClosePciIo;\r
212aac55 262 }\r
ac0a286f 263\r
212aac55 264 Private->Variant = Card->Variant;\r
265\r
b37bcfd6
LE
266 //\r
267 // IsQxl is based on the detected Card->Variant, which at a later point might\r
268 // not match Private->Variant.\r
269 //\r
270 IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);\r
271\r
eaf4f336 272 //\r
273 // Save original PCI attributes\r
274 //\r
275 Status = Private->PciIo->Attributes (\r
ac0a286f
MK
276 Private->PciIo,\r
277 EfiPciIoAttributeOperationGet,\r
278 0,\r
279 &Private->OriginalPciAttributes\r
280 );\r
eaf4f336 281\r
282 if (EFI_ERROR (Status)) {\r
d89186bc 283 goto ClosePciIo;\r
eaf4f336 284 }\r
eaf4f336 285\r
662bd0da
MC
286 //\r
287 // Get supported PCI attributes\r
288 //\r
289 Status = Private->PciIo->Attributes (\r
290 Private->PciIo,\r
291 EfiPciIoAttributeOperationSupported,\r
292 0,\r
293 &SupportedVgaIo\r
294 );\r
295 if (EFI_ERROR (Status)) {\r
296 goto ClosePciIo;\r
297 }\r
298\r
299 SupportedVgaIo &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
ac0a286f 300 if ((SupportedVgaIo == 0) && IS_PCI_VGA (&Pci)) {\r
662bd0da
MC
301 Status = EFI_UNSUPPORTED;\r
302 goto ClosePciIo;\r
303 }\r
304\r
d89186bc
LE
305 //\r
306 // Set new PCI attributes\r
307 //\r
eaf4f336 308 Status = Private->PciIo->Attributes (\r
ac0a286f
MK
309 Private->PciIo,\r
310 EfiPciIoAttributeOperationEnable,\r
311 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | SupportedVgaIo,\r
312 NULL\r
313 );\r
eaf4f336 314 if (EFI_ERROR (Status)) {\r
d89186bc 315 goto ClosePciIo;\r
eaf4f336 316 }\r
317\r
cdb4f5dc 318 //\r
319 // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).\r
320 //\r
321 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
ac0a286f 322 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;\r
d89186bc 323\r
cdb4f5dc 324 Status = Private->PciIo->GetBarAttributes (\r
ac0a286f
MK
325 Private->PciIo,\r
326 PCI_BAR_IDX2,\r
327 NULL,\r
328 (VOID **)&MmioDesc\r
329 );\r
cdb4f5dc 330 if (EFI_ERROR (Status) ||\r
ac0a286f
MK
331 (MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM))\r
332 {\r
70d5086c 333 DEBUG ((DEBUG_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));\r
cdb4f5dc 334 Private->Variant = QEMU_VIDEO_BOCHS;\r
335 } else {\r
ac0a286f
MK
336 DEBUG ((\r
337 DEBUG_INFO,\r
338 "QemuVideo: Using mmio bar @ 0x%lx\n",\r
339 MmioDesc->AddrRangeMin\r
340 ));\r
cdb4f5dc 341 }\r
5cdb96fa
LE
342\r
343 if (!EFI_ERROR (Status)) {\r
344 FreePool (MmioDesc);\r
345 }\r
cdb4f5dc 346 }\r
347\r
d021868c
YCL
348 //\r
349 // VMWare SVGA is handled like Bochs (with port IO only).\r
350 //\r
351 if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {\r
ac0a286f 352 Private->Variant = QEMU_VIDEO_BOCHS;\r
d021868c
YCL
353 Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;\r
354 }\r
355\r
54f9b9ac 356 //\r
357 // Check if accessing the bochs interface works.\r
358 //\r
ac0a286f
MK
359 if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) ||\r
360 (Private->Variant == QEMU_VIDEO_BOCHS))\r
361 {\r
362 UINT16 BochsId;\r
363 BochsId = BochsRead (Private, VBE_DISPI_INDEX_ID);\r
54f9b9ac 364 if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {\r
70d5086c 365 DEBUG ((DEBUG_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));\r
54f9b9ac 366 Status = EFI_DEVICE_ERROR;\r
d89186bc 367 goto RestoreAttributes;\r
54f9b9ac 368 }\r
369 }\r
370\r
eaf4f336 371 //\r
372 // Get ParentDevicePath\r
373 //\r
374 Status = gBS->HandleProtocol (\r
375 Controller,\r
376 &gEfiDevicePathProtocolGuid,\r
ac0a286f 377 (VOID **)&ParentDevicePath\r
eaf4f336 378 );\r
379 if (EFI_ERROR (Status)) {\r
d89186bc 380 goto RestoreAttributes;\r
eaf4f336 381 }\r
382\r
383 //\r
384 // Set Gop Device Path\r
385 //\r
42d0cad7 386 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
ac0a286f 387 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
42d0cad7 388 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
ac0a286f 389 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
42d0cad7
LE
390 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
391\r
392 Private->GopDevicePath = AppendDevicePathNode (\r
ac0a286f
MK
393 ParentDevicePath,\r
394 (EFI_DEVICE_PATH_PROTOCOL *)&AcpiDeviceNode\r
395 );\r
42d0cad7
LE
396 if (Private->GopDevicePath == NULL) {\r
397 Status = EFI_OUT_OF_RESOURCES;\r
398 goto RestoreAttributes;\r
eaf4f336 399 }\r
d89186bc
LE
400\r
401 //\r
42d0cad7 402 // Create new child handle and install the device path protocol on it.\r
d89186bc 403 //\r
42d0cad7
LE
404 Status = gBS->InstallMultipleProtocolInterfaces (\r
405 &Private->Handle,\r
406 &gEfiDevicePathProtocolGuid,\r
407 Private->GopDevicePath,\r
408 NULL\r
409 );\r
410 if (EFI_ERROR (Status)) {\r
411 goto FreeGopDevicePath;\r
eaf4f336 412 }\r
413\r
414 //\r
415 // Construct video mode buffer\r
416 //\r
212aac55 417 switch (Private->Variant) {\r
ac0a286f
MK
418 case QEMU_VIDEO_CIRRUS_5430:\r
419 case QEMU_VIDEO_CIRRUS_5446:\r
420 Status = QemuVideoCirrusModeSetup (Private);\r
421 break;\r
422 case QEMU_VIDEO_BOCHS_MMIO:\r
423 case QEMU_VIDEO_BOCHS:\r
424 Status = QemuVideoBochsModeSetup (Private, IsQxl);\r
425 break;\r
426 default:\r
427 ASSERT (FALSE);\r
428 Status = EFI_DEVICE_ERROR;\r
429 break;\r
212aac55 430 }\r
ac0a286f 431\r
eaf4f336 432 if (EFI_ERROR (Status)) {\r
d89186bc 433 goto UninstallGopDevicePath;\r
eaf4f336 434 }\r
435\r
d89186bc
LE
436 //\r
437 // Start the GOP software stack.\r
438 //\r
439 Status = QemuVideoGraphicsOutputConstructor (Private);\r
440 if (EFI_ERROR (Status)) {\r
441 goto FreeModeData;\r
442 }\r
4374c2e5 443\r
d89186bc
LE
444 Status = gBS->InstallMultipleProtocolInterfaces (\r
445 &Private->Handle,\r
446 &gEfiGraphicsOutputProtocolGuid,\r
447 &Private->GraphicsOutput,\r
448 NULL\r
4374c2e5 449 );\r
d89186bc
LE
450 if (EFI_ERROR (Status)) {\r
451 goto DestructQemuVideoGraphics;\r
eaf4f336 452 }\r
453\r
d89186bc
LE
454 //\r
455 // Reference parent handle from child handle.\r
456 //\r
457 Status = gBS->OpenProtocol (\r
ac0a286f
MK
458 Controller,\r
459 &gEfiPciIoProtocolGuid,\r
460 (VOID **)&ChildPciIo,\r
461 This->DriverBindingHandle,\r
462 Private->Handle,\r
463 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
464 );\r
eaf4f336 465 if (EFI_ERROR (Status)) {\r
d89186bc
LE
466 goto UninstallGop;\r
467 }\r
eaf4f336 468\r
ac0a286f
MK
469 #if defined MDE_CPU_IA32 || defined MDE_CPU_X64\r
470 if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) ||\r
471 (Private->Variant == QEMU_VIDEO_BOCHS))\r
472 {\r
90803342
LE
473 InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);\r
474 }\r
ac0a286f
MK
475\r
476 #endif\r
90803342 477\r
9c08bbe5 478 gBS->RestoreTPL (OldTpl);\r
d89186bc
LE
479 return EFI_SUCCESS;\r
480\r
481UninstallGop:\r
ac0a286f
MK
482 gBS->UninstallProtocolInterface (\r
483 Private->Handle,\r
484 &gEfiGraphicsOutputProtocolGuid,\r
485 &Private->GraphicsOutput\r
486 );\r
d89186bc
LE
487\r
488DestructQemuVideoGraphics:\r
489 QemuVideoGraphicsOutputDestructor (Private);\r
490\r
491FreeModeData:\r
492 FreePool (Private->ModeData);\r
493\r
494UninstallGopDevicePath:\r
ac0a286f
MK
495 gBS->UninstallProtocolInterface (\r
496 Private->Handle,\r
497 &gEfiDevicePathProtocolGuid,\r
498 Private->GopDevicePath\r
499 );\r
d89186bc
LE
500\r
501FreeGopDevicePath:\r
42d0cad7 502 FreePool (Private->GopDevicePath);\r
eaf4f336 503\r
d89186bc 504RestoreAttributes:\r
ac0a286f
MK
505 Private->PciIo->Attributes (\r
506 Private->PciIo,\r
507 EfiPciIoAttributeOperationSet,\r
508 Private->OriginalPciAttributes,\r
509 NULL\r
510 );\r
d89186bc
LE
511\r
512ClosePciIo:\r
ac0a286f
MK
513 gBS->CloseProtocol (\r
514 Controller,\r
515 &gEfiPciIoProtocolGuid,\r
516 This->DriverBindingHandle,\r
517 Controller\r
518 );\r
d89186bc
LE
519\r
520FreePrivate:\r
521 FreePool (Private);\r
522\r
9c08bbe5
LE
523RestoreTpl:\r
524 gBS->RestoreTPL (OldTpl);\r
525\r
eaf4f336 526 return Status;\r
527}\r
528\r
529/**\r
530 Stop this device\r
531\r
532 @param This The USB bus driver binding protocol.\r
533 @param Controller The controller to release.\r
534 @param NumberOfChildren The number of children of this device that\r
535 opened the controller BY_CHILD.\r
536 @param ChildHandleBuffer The array of child handle.\r
537\r
538 @retval EFI_SUCCESS The controller or children are stopped.\r
539 @retval EFI_DEVICE_ERROR Failed to stop the driver.\r
540\r
541**/\r
542EFI_STATUS\r
543EFIAPI\r
544QemuVideoControllerDriverStop (\r
ac0a286f
MK
545 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
546 IN EFI_HANDLE Controller,\r
547 IN UINTN NumberOfChildren,\r
548 IN EFI_HANDLE *ChildHandleBuffer\r
eaf4f336 549 )\r
550{\r
ac0a286f 551 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
eaf4f336 552\r
ac0a286f 553 EFI_STATUS Status;\r
eaf4f336 554 QEMU_VIDEO_PRIVATE_DATA *Private;\r
555\r
99a6dce3
LE
556 if (NumberOfChildren == 0) {\r
557 //\r
558 // Close the PCI I/O Protocol\r
559 //\r
560 gBS->CloseProtocol (\r
ac0a286f
MK
561 Controller,\r
562 &gEfiPciIoProtocolGuid,\r
563 This->DriverBindingHandle,\r
564 Controller\r
565 );\r
99a6dce3
LE
566 return EFI_SUCCESS;\r
567 }\r
568\r
569 //\r
570 // free all resources for whose access we need the child handle, because the\r
571 // child handle is going away\r
572 //\r
573 ASSERT (NumberOfChildren == 1);\r
eaf4f336 574 Status = gBS->OpenProtocol (\r
99a6dce3 575 ChildHandleBuffer[0],\r
eaf4f336 576 &gEfiGraphicsOutputProtocolGuid,\r
ac0a286f 577 (VOID **)&GraphicsOutput,\r
eaf4f336 578 This->DriverBindingHandle,\r
579 Controller,\r
580 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
581 );\r
582 if (EFI_ERROR (Status)) {\r
583 return Status;\r
584 }\r
585\r
586 //\r
587 // Get our private context information\r
588 //\r
589 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);\r
99a6dce3 590 ASSERT (Private->Handle == ChildHandleBuffer[0]);\r
eaf4f336 591\r
592 QemuVideoGraphicsOutputDestructor (Private);\r
593 //\r
594 // Remove the GOP protocol interface from the system\r
595 //\r
596 Status = gBS->UninstallMultipleProtocolInterfaces (\r
597 Private->Handle,\r
598 &gEfiGraphicsOutputProtocolGuid,\r
599 &Private->GraphicsOutput,\r
600 NULL\r
601 );\r
602\r
603 if (EFI_ERROR (Status)) {\r
604 return Status;\r
605 }\r
606\r
607 //\r
608 // Restore original PCI attributes\r
609 //\r
610 Private->PciIo->Attributes (\r
ac0a286f
MK
611 Private->PciIo,\r
612 EfiPciIoAttributeOperationSet,\r
613 Private->OriginalPciAttributes,\r
614 NULL\r
615 );\r
eaf4f336 616\r
4374c2e5 617 gBS->CloseProtocol (\r
ac0a286f
MK
618 Controller,\r
619 &gEfiPciIoProtocolGuid,\r
620 This->DriverBindingHandle,\r
621 Private->Handle\r
622 );\r
4374c2e5 623\r
847e4c34 624 FreePool (Private->ModeData);\r
ac0a286f
MK
625 gBS->UninstallProtocolInterface (\r
626 Private->Handle,\r
627 &gEfiDevicePathProtocolGuid,\r
628 Private->GopDevicePath\r
629 );\r
847e4c34
LE
630 FreePool (Private->GopDevicePath);\r
631\r
eaf4f336 632 //\r
633 // Free our instance data\r
634 //\r
635 gBS->FreePool (Private);\r
636\r
637 return EFI_SUCCESS;\r
638}\r
639\r
640/**\r
641 TODO: Add function description\r
642\r
643 @param Private TODO: add argument description\r
644 @param Address TODO: add argument description\r
645 @param Data TODO: add argument description\r
646\r
647 TODO: add return values\r
648\r
649**/\r
650VOID\r
651outb (\r
652 QEMU_VIDEO_PRIVATE_DATA *Private,\r
ac0a286f
MK
653 UINTN Address,\r
654 UINT8 Data\r
eaf4f336 655 )\r
656{\r
657 Private->PciIo->Io.Write (\r
ac0a286f
MK
658 Private->PciIo,\r
659 EfiPciIoWidthUint8,\r
660 EFI_PCI_IO_PASS_THROUGH_BAR,\r
661 Address,\r
662 1,\r
663 &Data\r
664 );\r
eaf4f336 665}\r
666\r
667/**\r
668 TODO: Add function description\r
669\r
670 @param Private TODO: add argument description\r
671 @param Address TODO: add argument description\r
672 @param Data TODO: add argument description\r
673\r
674 TODO: add return values\r
675\r
676**/\r
677VOID\r
678outw (\r
679 QEMU_VIDEO_PRIVATE_DATA *Private,\r
ac0a286f
MK
680 UINTN Address,\r
681 UINT16 Data\r
eaf4f336 682 )\r
683{\r
684 Private->PciIo->Io.Write (\r
ac0a286f
MK
685 Private->PciIo,\r
686 EfiPciIoWidthUint16,\r
687 EFI_PCI_IO_PASS_THROUGH_BAR,\r
688 Address,\r
689 1,\r
690 &Data\r
691 );\r
eaf4f336 692}\r
693\r
694/**\r
695 TODO: Add function description\r
696\r
697 @param Private TODO: add argument description\r
698 @param Address TODO: add argument description\r
699\r
700 TODO: add return values\r
701\r
702**/\r
703UINT8\r
704inb (\r
705 QEMU_VIDEO_PRIVATE_DATA *Private,\r
ac0a286f 706 UINTN Address\r
eaf4f336 707 )\r
708{\r
ac0a286f 709 UINT8 Data;\r
eaf4f336 710\r
711 Private->PciIo->Io.Read (\r
ac0a286f
MK
712 Private->PciIo,\r
713 EfiPciIoWidthUint8,\r
714 EFI_PCI_IO_PASS_THROUGH_BAR,\r
715 Address,\r
716 1,\r
717 &Data\r
718 );\r
eaf4f336 719 return Data;\r
720}\r
721\r
722/**\r
723 TODO: Add function description\r
724\r
725 @param Private TODO: add argument description\r
726 @param Address TODO: add argument description\r
727\r
728 TODO: add return values\r
729\r
730**/\r
731UINT16\r
732inw (\r
733 QEMU_VIDEO_PRIVATE_DATA *Private,\r
ac0a286f 734 UINTN Address\r
eaf4f336 735 )\r
736{\r
737 UINT16 Data;\r
738\r
739 Private->PciIo->Io.Read (\r
ac0a286f
MK
740 Private->PciIo,\r
741 EfiPciIoWidthUint16,\r
742 EFI_PCI_IO_PASS_THROUGH_BAR,\r
743 Address,\r
744 1,\r
745 &Data\r
746 );\r
eaf4f336 747 return Data;\r
748}\r
749\r
750/**\r
751 TODO: Add function description\r
752\r
753 @param Private TODO: add argument description\r
754 @param Index TODO: add argument description\r
755 @param Red TODO: add argument description\r
756 @param Green TODO: add argument description\r
757 @param Blue TODO: add argument description\r
758\r
759 TODO: add return values\r
760\r
761**/\r
762VOID\r
763SetPaletteColor (\r
764 QEMU_VIDEO_PRIVATE_DATA *Private,\r
ac0a286f
MK
765 UINTN Index,\r
766 UINT8 Red,\r
767 UINT8 Green,\r
768 UINT8 Blue\r
eaf4f336 769 )\r
770{\r
ac0a286f
MK
771 VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8)Index);\r
772 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Red >> 2));\r
773 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Green >> 2));\r
774 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Blue >> 2));\r
eaf4f336 775}\r
776\r
777/**\r
778 TODO: Add function description\r
779\r
780 @param Private TODO: add argument description\r
781\r
782 TODO: add return values\r
783\r
784**/\r
785VOID\r
786SetDefaultPalette (\r
787 QEMU_VIDEO_PRIVATE_DATA *Private\r
788 )\r
789{\r
ac0a286f
MK
790 UINTN Index;\r
791 UINTN RedIndex;\r
792 UINTN GreenIndex;\r
793 UINTN BlueIndex;\r
eaf4f336 794\r
795 Index = 0;\r
796 for (RedIndex = 0; RedIndex < 8; RedIndex++) {\r
797 for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {\r
798 for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {\r
ac0a286f 799 SetPaletteColor (Private, Index, (UINT8)(RedIndex << 5), (UINT8)(GreenIndex << 5), (UINT8)(BlueIndex << 6));\r
eaf4f336 800 Index++;\r
801 }\r
802 }\r
803 }\r
804}\r
805\r
806/**\r
807 TODO: Add function description\r
808\r
809 @param Private TODO: add argument description\r
810\r
811 TODO: add return values\r
812\r
813**/\r
814VOID\r
815ClearScreen (\r
816 QEMU_VIDEO_PRIVATE_DATA *Private\r
817 )\r
818{\r
819 UINT32 Color;\r
820\r
821 Color = 0;\r
822 Private->PciIo->Mem.Write (\r
823 Private->PciIo,\r
824 EfiPciIoWidthFillUint32,\r
d021868c 825 Private->FrameBufferVramBarIndex,\r
eaf4f336 826 0,\r
827 0x400000 >> 2,\r
828 &Color\r
829 );\r
830}\r
831\r
832/**\r
833 TODO: Add function description\r
834\r
835 @param Private TODO: add argument description\r
836\r
837 TODO: add return values\r
838\r
839**/\r
840VOID\r
841DrawLogo (\r
842 QEMU_VIDEO_PRIVATE_DATA *Private,\r
ac0a286f
MK
843 UINTN ScreenWidth,\r
844 UINTN ScreenHeight\r
eaf4f336 845 )\r
846{\r
847}\r
848\r
849/**\r
850 TODO: Add function description\r
851\r
852 @param Private TODO: add argument description\r
853 @param ModeData TODO: add argument description\r
854\r
855 TODO: add return values\r
856\r
857**/\r
858VOID\r
212aac55 859InitializeCirrusGraphicsMode (\r
eaf4f336 860 QEMU_VIDEO_PRIVATE_DATA *Private,\r
212aac55 861 QEMU_VIDEO_CIRRUS_MODES *ModeData\r
eaf4f336 862 )\r
863{\r
ac0a286f
MK
864 UINT8 Byte;\r
865 UINTN Index;\r
eaf4f336 866\r
867 outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);\r
868 outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);\r
869\r
870 for (Index = 0; Index < 15; Index++) {\r
871 outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);\r
872 }\r
873\r
212aac55 874 if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {\r
eaf4f336 875 outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);\r
ac0a286f 876 Byte = (UINT8)((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);\r
eaf4f336 877 outb (Private, SEQ_DATA_REGISTER, Byte);\r
878 }\r
879\r
880 outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);\r
881 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);\r
882 outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);\r
883 outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);\r
884\r
885 for (Index = 0; Index < 28; Index++) {\r
ac0a286f 886 outw (Private, CRTC_ADDRESS_REGISTER, (UINT16)((ModeData->CrtcSettings[Index] << 8) | Index));\r
eaf4f336 887 }\r
888\r
889 for (Index = 0; Index < 9; Index++) {\r
ac0a286f 890 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16)((GraphicsController[Index] << 8) | Index));\r
eaf4f336 891 }\r
892\r
893 inb (Private, INPUT_STATUS_1_REGISTER);\r
894\r
895 for (Index = 0; Index < 21; Index++) {\r
ac0a286f 896 outb (Private, ATT_ADDRESS_REGISTER, (UINT8)Index);\r
eaf4f336 897 outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);\r
898 }\r
899\r
900 outb (Private, ATT_ADDRESS_REGISTER, 0x20);\r
901\r
902 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);\r
903 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);\r
904 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);\r
905 outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);\r
906\r
54f9b9ac 907 SetDefaultPalette (Private);\r
908 ClearScreen (Private);\r
909}\r
910\r
911VOID\r
912BochsWrite (\r
913 QEMU_VIDEO_PRIVATE_DATA *Private,\r
914 UINT16 Reg,\r
915 UINT16 Data\r
916 )\r
917{\r
ac0a286f 918 EFI_STATUS Status;\r
cdb4f5dc 919\r
920 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
921 Status = Private->PciIo->Mem.Write (\r
ac0a286f
MK
922 Private->PciIo,\r
923 EfiPciIoWidthUint16,\r
924 PCI_BAR_IDX2,\r
925 0x500 + (Reg << 1),\r
926 1,\r
927 &Data\r
928 );\r
cdb4f5dc 929 ASSERT_EFI_ERROR (Status);\r
930 } else {\r
931 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
ac0a286f 932 outw (Private, VBE_DISPI_IOPORT_DATA, Data);\r
cdb4f5dc 933 }\r
54f9b9ac 934}\r
935\r
936UINT16\r
937BochsRead (\r
938 QEMU_VIDEO_PRIVATE_DATA *Private,\r
939 UINT16 Reg\r
940 )\r
941{\r
ac0a286f
MK
942 EFI_STATUS Status;\r
943 UINT16 Data;\r
cdb4f5dc 944\r
945 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
946 Status = Private->PciIo->Mem.Read (\r
ac0a286f
MK
947 Private->PciIo,\r
948 EfiPciIoWidthUint16,\r
949 PCI_BAR_IDX2,\r
950 0x500 + (Reg << 1),\r
951 1,\r
952 &Data\r
953 );\r
cdb4f5dc 954 ASSERT_EFI_ERROR (Status);\r
955 } else {\r
956 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
957 Data = inw (Private, VBE_DISPI_IOPORT_DATA);\r
958 }\r
ac0a286f 959\r
54f9b9ac 960 return Data;\r
961}\r
962\r
cdb4f5dc 963VOID\r
964VgaOutb (\r
965 QEMU_VIDEO_PRIVATE_DATA *Private,\r
966 UINTN Reg,\r
967 UINT8 Data\r
968 )\r
969{\r
ac0a286f 970 EFI_STATUS Status;\r
cdb4f5dc 971\r
972 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
973 Status = Private->PciIo->Mem.Write (\r
ac0a286f
MK
974 Private->PciIo,\r
975 EfiPciIoWidthUint8,\r
976 PCI_BAR_IDX2,\r
977 0x400 - 0x3c0 + Reg,\r
978 1,\r
979 &Data\r
980 );\r
cdb4f5dc 981 ASSERT_EFI_ERROR (Status);\r
982 } else {\r
983 outb (Private, Reg, Data);\r
984 }\r
985}\r
986\r
512042eb
GH
987STATIC\r
988UINT8\r
989VgaInb (\r
990 QEMU_VIDEO_PRIVATE_DATA *Private,\r
991 UINTN Reg\r
992 )\r
993{\r
994 EFI_STATUS Status;\r
995 UINT8 Data;\r
996\r
997 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
998 Data = 0;\r
999 Status = Private->PciIo->Mem.Read (\r
1000 Private->PciIo,\r
1001 EfiPciIoWidthUint8,\r
1002 PCI_BAR_IDX2,\r
1003 0x400 - 0x3c0 + Reg,\r
1004 1,\r
1005 &Data\r
1006 );\r
1007 ASSERT_EFI_ERROR (Status);\r
1008 } else {\r
1009 Data = inb (Private, Reg);\r
1010 }\r
1011\r
1012 return Data;\r
1013}\r
1014\r
54f9b9ac 1015VOID\r
1016InitializeBochsGraphicsMode (\r
1017 QEMU_VIDEO_PRIVATE_DATA *Private,\r
7f25ddbc 1018 QEMU_VIDEO_MODE_DATA *ModeData\r
54f9b9ac 1019 )\r
1020{\r
ac0a286f
MK
1021 DEBUG ((\r
1022 DEBUG_INFO,\r
1023 "InitializeBochsGraphicsMode: %dx%d @ %d\n",\r
7f25ddbc
GH
1024 ModeData->HorizontalResolution,\r
1025 ModeData->VerticalResolution,\r
ac0a286f
MK
1026 ModeData->ColorDepth\r
1027 ));\r
54f9b9ac 1028\r
512042eb
GH
1029 /* set color mode */\r
1030 VgaOutb (Private, MISC_OUTPUT_REGISTER, 0x01);\r
1031\r
1032 /* reset flip flop + unblank */\r
1033 VgaInb (Private, INPUT_STATUS_1_REGISTER);\r
cdb4f5dc 1034 VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);\r
54f9b9ac 1035\r
ac0a286f
MK
1036 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);\r
1037 BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);\r
1038 BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);\r
1039 BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);\r
54f9b9ac 1040\r
ac0a286f 1041 BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16)ModeData->ColorDepth);\r
7f25ddbc
GH
1042 BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16)ModeData->HorizontalResolution);\r
1043 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16)ModeData->HorizontalResolution);\r
1044 BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16)ModeData->VerticalResolution);\r
1045 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16)ModeData->VerticalResolution);\r
54f9b9ac 1046\r
ac0a286f
MK
1047 BochsWrite (\r
1048 Private,\r
1049 VBE_DISPI_INDEX_ENABLE,\r
1050 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED\r
1051 );\r
54f9b9ac 1052\r
eaf4f336 1053 SetDefaultPalette (Private);\r
1054 ClearScreen (Private);\r
1055}\r
1056\r
1057EFI_STATUS\r
1058EFIAPI\r
1059InitializeQemuVideo (\r
ac0a286f
MK
1060 IN EFI_HANDLE ImageHandle,\r
1061 IN EFI_SYSTEM_TABLE *SystemTable\r
eaf4f336 1062 )\r
1063{\r
ac0a286f 1064 EFI_STATUS Status;\r
eaf4f336 1065\r
1066 Status = EfiLibInstallDriverBindingComponentName2 (\r
1067 ImageHandle,\r
1068 SystemTable,\r
1069 &gQemuVideoDriverBinding,\r
1070 ImageHandle,\r
1071 &gQemuVideoComponentName,\r
1072 &gQemuVideoComponentName2\r
1073 );\r
1074 ASSERT_EFI_ERROR (Status);\r
1075\r
eaf4f336 1076 return Status;\r
1077}\r