]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg/QemuVideoDxe: don't leak descriptors returned by GetBarAttributes
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
1 /** @file
2 This driver is a sample implementation of the Graphics Output Protocol for
3 the QEMU (Cirrus Logic 5446) video controller.
4
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Qemu.h"
18 #include <IndustryStandard/Acpi.h>
19
20 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
21 QemuVideoControllerDriverSupported,
22 QemuVideoControllerDriverStart,
23 QemuVideoControllerDriverStop,
24 0x10,
25 NULL,
26 NULL
27 };
28
29 QEMU_VIDEO_CARD gQemuVideoCardList[] = {
30 {
31 CIRRUS_LOGIC_VENDOR_ID,
32 CIRRUS_LOGIC_5430_DEVICE_ID,
33 QEMU_VIDEO_CIRRUS_5430,
34 L"Cirrus 5430"
35 },{
36 CIRRUS_LOGIC_VENDOR_ID,
37 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
38 QEMU_VIDEO_CIRRUS_5430,
39 L"Cirrus 5430"
40 },{
41 CIRRUS_LOGIC_VENDOR_ID,
42 CIRRUS_LOGIC_5446_DEVICE_ID,
43 QEMU_VIDEO_CIRRUS_5446,
44 L"Cirrus 5446"
45 },{
46 0x1234,
47 0x1111,
48 QEMU_VIDEO_BOCHS_MMIO,
49 L"QEMU Standard VGA"
50 },{
51 0x1b36,
52 0x0100,
53 QEMU_VIDEO_BOCHS,
54 L"QEMU QXL VGA"
55 },{
56 0 /* end of list */
57 }
58 };
59
60 static QEMU_VIDEO_CARD*
61 QemuVideoDetect(
62 IN UINT16 VendorId,
63 IN UINT16 DeviceId
64 )
65 {
66 UINTN Index = 0;
67
68 while (gQemuVideoCardList[Index].VendorId != 0) {
69 if (gQemuVideoCardList[Index].VendorId == VendorId &&
70 gQemuVideoCardList[Index].DeviceId == DeviceId) {
71 return gQemuVideoCardList + Index;
72 }
73 Index++;
74 }
75 return NULL;
76 }
77
78 /**
79 Check if this device is supported.
80
81 @param This The driver binding protocol.
82 @param Controller The controller handle to check.
83 @param RemainingDevicePath The remaining device path.
84
85 @retval EFI_SUCCESS The bus supports this controller.
86 @retval EFI_UNSUPPORTED This device isn't supported.
87
88 **/
89 EFI_STATUS
90 EFIAPI
91 QemuVideoControllerDriverSupported (
92 IN EFI_DRIVER_BINDING_PROTOCOL *This,
93 IN EFI_HANDLE Controller,
94 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
95 )
96 {
97 EFI_STATUS Status;
98 EFI_PCI_IO_PROTOCOL *PciIo;
99 PCI_TYPE00 Pci;
100 EFI_DEV_PATH *Node;
101 QEMU_VIDEO_CARD *Card;
102
103 //
104 // Open the PCI I/O Protocol
105 //
106 Status = gBS->OpenProtocol (
107 Controller,
108 &gEfiPciIoProtocolGuid,
109 (VOID **) &PciIo,
110 This->DriverBindingHandle,
111 Controller,
112 EFI_OPEN_PROTOCOL_BY_DRIVER
113 );
114 if (EFI_ERROR (Status)) {
115 return Status;
116 }
117
118 //
119 // Read the PCI Configuration Header from the PCI Device
120 //
121 Status = PciIo->Pci.Read (
122 PciIo,
123 EfiPciIoWidthUint32,
124 0,
125 sizeof (Pci) / sizeof (UINT32),
126 &Pci
127 );
128 if (EFI_ERROR (Status)) {
129 goto Done;
130 }
131
132 Status = EFI_UNSUPPORTED;
133 //
134 // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
135 // at a time, so see if this is one that is turned on.
136 //
137 // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
138 //
139 // See if this is a Cirrus Logic PCI controller
140 //
141 Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
142 if (Card != NULL) {
143 DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));
144 Status = EFI_SUCCESS;
145 //
146 // If this is an Intel 945 graphics controller,
147 // go further check RemainingDevicePath validation
148 //
149 if (RemainingDevicePath != NULL) {
150 Node = (EFI_DEV_PATH *) RemainingDevicePath;
151 //
152 // Check if RemainingDevicePath is the End of Device Path Node,
153 // if yes, return EFI_SUCCESS
154 //
155 if (!IsDevicePathEnd (Node)) {
156 //
157 // If RemainingDevicePath isn't the End of Device Path Node,
158 // check its validation
159 //
160 if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
161 Node->DevPath.SubType != ACPI_ADR_DP ||
162 DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {
163 Status = EFI_UNSUPPORTED;
164 }
165 }
166 }
167 }
168
169 Done:
170 //
171 // Close the PCI I/O Protocol
172 //
173 gBS->CloseProtocol (
174 Controller,
175 &gEfiPciIoProtocolGuid,
176 This->DriverBindingHandle,
177 Controller
178 );
179
180 return Status;
181 }
182
183 /**
184 Start to process the controller.
185
186 @param This The USB bus driver binding instance.
187 @param Controller The controller to check.
188 @param RemainingDevicePath The remaining device patch.
189
190 @retval EFI_SUCCESS The controller is controlled by the usb bus.
191 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
192 bus.
193 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
194
195 **/
196 EFI_STATUS
197 EFIAPI
198 QemuVideoControllerDriverStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL *This,
200 IN EFI_HANDLE Controller,
201 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
202 )
203 {
204 EFI_STATUS Status;
205 QEMU_VIDEO_PRIVATE_DATA *Private;
206 BOOLEAN PciAttributesSaved;
207 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
208 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
209 PCI_TYPE00 Pci;
210 QEMU_VIDEO_CARD *Card;
211 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
212
213 PciAttributesSaved = FALSE;
214 //
215 // Allocate Private context data for GOP inteface.
216 //
217 Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
218 if (Private == NULL) {
219 Status = EFI_OUT_OF_RESOURCES;
220 goto Error;
221 }
222
223 //
224 // Set up context record
225 //
226 Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
227 Private->Handle = NULL;
228
229 //
230 // Open PCI I/O Protocol
231 //
232 Status = gBS->OpenProtocol (
233 Controller,
234 &gEfiPciIoProtocolGuid,
235 (VOID **) &Private->PciIo,
236 This->DriverBindingHandle,
237 Controller,
238 EFI_OPEN_PROTOCOL_BY_DRIVER
239 );
240 if (EFI_ERROR (Status)) {
241 goto Error;
242 }
243
244 //
245 // Read the PCI Configuration Header from the PCI Device
246 //
247 Status = Private->PciIo->Pci.Read (
248 Private->PciIo,
249 EfiPciIoWidthUint32,
250 0,
251 sizeof (Pci) / sizeof (UINT32),
252 &Pci
253 );
254 if (EFI_ERROR (Status)) {
255 goto Error;
256 }
257
258 Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
259 if (Card == NULL) {
260 Status = EFI_DEVICE_ERROR;
261 goto Error;
262 }
263 Private->Variant = Card->Variant;
264
265 //
266 // Save original PCI attributes
267 //
268 Status = Private->PciIo->Attributes (
269 Private->PciIo,
270 EfiPciIoAttributeOperationGet,
271 0,
272 &Private->OriginalPciAttributes
273 );
274
275 if (EFI_ERROR (Status)) {
276 goto Error;
277 }
278 PciAttributesSaved = TRUE;
279
280 Status = Private->PciIo->Attributes (
281 Private->PciIo,
282 EfiPciIoAttributeOperationEnable,
283 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
284 NULL
285 );
286 if (EFI_ERROR (Status)) {
287 goto Error;
288 }
289
290 //
291 // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
292 //
293 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
294 Status = Private->PciIo->GetBarAttributes (
295 Private->PciIo,
296 PCI_BAR_IDX2,
297 NULL,
298 (VOID**) &MmioDesc
299 );
300 if (EFI_ERROR (Status) ||
301 MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
302 DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
303 Private->Variant = QEMU_VIDEO_BOCHS;
304 } else {
305 DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
306 MmioDesc->AddrRangeMin));
307 }
308
309 if (!EFI_ERROR (Status)) {
310 FreePool (MmioDesc);
311 }
312 }
313
314 //
315 // Check if accessing the bochs interface works.
316 //
317 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
318 Private->Variant == QEMU_VIDEO_BOCHS) {
319 UINT16 BochsId;
320 BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);
321 if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
322 DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
323 Status = EFI_DEVICE_ERROR;
324 goto Error;
325 }
326 }
327
328 //
329 // Get ParentDevicePath
330 //
331 Status = gBS->HandleProtocol (
332 Controller,
333 &gEfiDevicePathProtocolGuid,
334 (VOID **) &ParentDevicePath
335 );
336 if (EFI_ERROR (Status)) {
337 goto Error;
338 }
339
340 //
341 // Set Gop Device Path
342 //
343 if (RemainingDevicePath == NULL) {
344 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
345 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
346 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
347 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
348 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
349
350 Private->GopDevicePath = AppendDevicePathNode (
351 ParentDevicePath,
352 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
353 );
354 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
355 //
356 // If RemainingDevicePath isn't the End of Device Path Node,
357 // only scan the specified device by RemainingDevicePath
358 //
359 Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
360 } else {
361 //
362 // If RemainingDevicePath is the End of Device Path Node,
363 // don't create child device and return EFI_SUCCESS
364 //
365 Private->GopDevicePath = NULL;
366 }
367
368 if (Private->GopDevicePath != NULL) {
369 //
370 // Creat child handle and device path protocol firstly
371 //
372 Private->Handle = NULL;
373 Status = gBS->InstallMultipleProtocolInterfaces (
374 &Private->Handle,
375 &gEfiDevicePathProtocolGuid,
376 Private->GopDevicePath,
377 NULL
378 );
379 }
380
381 //
382 // Construct video mode buffer
383 //
384 switch (Private->Variant) {
385 case QEMU_VIDEO_CIRRUS_5430:
386 case QEMU_VIDEO_CIRRUS_5446:
387 Status = QemuVideoCirrusModeSetup (Private);
388 break;
389 case QEMU_VIDEO_BOCHS_MMIO:
390 case QEMU_VIDEO_BOCHS:
391 Status = QemuVideoBochsModeSetup (Private);
392 break;
393 default:
394 ASSERT (FALSE);
395 Status = EFI_DEVICE_ERROR;
396 break;
397 }
398 if (EFI_ERROR (Status)) {
399 goto Error;
400 }
401
402 if (Private->GopDevicePath == NULL) {
403 //
404 // If RemainingDevicePath is the End of Device Path Node,
405 // don't create child device and return EFI_SUCCESS
406 //
407 Status = EFI_SUCCESS;
408 } else {
409
410 //
411 // Start the GOP software stack.
412 //
413 Status = QemuVideoGraphicsOutputConstructor (Private);
414 ASSERT_EFI_ERROR (Status);
415
416 Status = gBS->InstallMultipleProtocolInterfaces (
417 &Private->Handle,
418 &gEfiGraphicsOutputProtocolGuid,
419 &Private->GraphicsOutput,
420 NULL
421 );
422 }
423
424 Error:
425 if (EFI_ERROR (Status)) {
426 if (Private) {
427 if (Private->PciIo) {
428 if (PciAttributesSaved == TRUE) {
429 //
430 // Restore original PCI attributes
431 //
432 Private->PciIo->Attributes (
433 Private->PciIo,
434 EfiPciIoAttributeOperationSet,
435 Private->OriginalPciAttributes,
436 NULL
437 );
438 }
439 //
440 // Close the PCI I/O Protocol
441 //
442 gBS->CloseProtocol (
443 Private->Handle,
444 &gEfiPciIoProtocolGuid,
445 This->DriverBindingHandle,
446 Private->Handle
447 );
448 }
449
450 gBS->FreePool (Private);
451 }
452 }
453
454 return Status;
455 }
456
457 /**
458 Stop this device
459
460 @param This The USB bus driver binding protocol.
461 @param Controller The controller to release.
462 @param NumberOfChildren The number of children of this device that
463 opened the controller BY_CHILD.
464 @param ChildHandleBuffer The array of child handle.
465
466 @retval EFI_SUCCESS The controller or children are stopped.
467 @retval EFI_DEVICE_ERROR Failed to stop the driver.
468
469 **/
470 EFI_STATUS
471 EFIAPI
472 QemuVideoControllerDriverStop (
473 IN EFI_DRIVER_BINDING_PROTOCOL *This,
474 IN EFI_HANDLE Controller,
475 IN UINTN NumberOfChildren,
476 IN EFI_HANDLE *ChildHandleBuffer
477 )
478 {
479 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
480
481 EFI_STATUS Status;
482 QEMU_VIDEO_PRIVATE_DATA *Private;
483
484 Status = gBS->OpenProtocol (
485 Controller,
486 &gEfiGraphicsOutputProtocolGuid,
487 (VOID **) &GraphicsOutput,
488 This->DriverBindingHandle,
489 Controller,
490 EFI_OPEN_PROTOCOL_GET_PROTOCOL
491 );
492 if (EFI_ERROR (Status)) {
493 return Status;
494 }
495
496 //
497 // Get our private context information
498 //
499 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
500
501 QemuVideoGraphicsOutputDestructor (Private);
502 //
503 // Remove the GOP protocol interface from the system
504 //
505 Status = gBS->UninstallMultipleProtocolInterfaces (
506 Private->Handle,
507 &gEfiGraphicsOutputProtocolGuid,
508 &Private->GraphicsOutput,
509 NULL
510 );
511
512 if (EFI_ERROR (Status)) {
513 return Status;
514 }
515
516 //
517 // Restore original PCI attributes
518 //
519 Private->PciIo->Attributes (
520 Private->PciIo,
521 EfiPciIoAttributeOperationSet,
522 Private->OriginalPciAttributes,
523 NULL
524 );
525
526 //
527 // Close the PCI I/O Protocol
528 //
529 gBS->CloseProtocol (
530 Controller,
531 &gEfiPciIoProtocolGuid,
532 This->DriverBindingHandle,
533 Controller
534 );
535
536 //
537 // Free our instance data
538 //
539 gBS->FreePool (Private);
540
541 return EFI_SUCCESS;
542 }
543
544 /**
545 TODO: Add function description
546
547 @param Private TODO: add argument description
548 @param Address TODO: add argument description
549 @param Data TODO: add argument description
550
551 TODO: add return values
552
553 **/
554 VOID
555 outb (
556 QEMU_VIDEO_PRIVATE_DATA *Private,
557 UINTN Address,
558 UINT8 Data
559 )
560 {
561 Private->PciIo->Io.Write (
562 Private->PciIo,
563 EfiPciIoWidthUint8,
564 EFI_PCI_IO_PASS_THROUGH_BAR,
565 Address,
566 1,
567 &Data
568 );
569 }
570
571 /**
572 TODO: Add function description
573
574 @param Private TODO: add argument description
575 @param Address TODO: add argument description
576 @param Data TODO: add argument description
577
578 TODO: add return values
579
580 **/
581 VOID
582 outw (
583 QEMU_VIDEO_PRIVATE_DATA *Private,
584 UINTN Address,
585 UINT16 Data
586 )
587 {
588 Private->PciIo->Io.Write (
589 Private->PciIo,
590 EfiPciIoWidthUint16,
591 EFI_PCI_IO_PASS_THROUGH_BAR,
592 Address,
593 1,
594 &Data
595 );
596 }
597
598 /**
599 TODO: Add function description
600
601 @param Private TODO: add argument description
602 @param Address TODO: add argument description
603
604 TODO: add return values
605
606 **/
607 UINT8
608 inb (
609 QEMU_VIDEO_PRIVATE_DATA *Private,
610 UINTN Address
611 )
612 {
613 UINT8 Data;
614
615 Private->PciIo->Io.Read (
616 Private->PciIo,
617 EfiPciIoWidthUint8,
618 EFI_PCI_IO_PASS_THROUGH_BAR,
619 Address,
620 1,
621 &Data
622 );
623 return Data;
624 }
625
626 /**
627 TODO: Add function description
628
629 @param Private TODO: add argument description
630 @param Address TODO: add argument description
631
632 TODO: add return values
633
634 **/
635 UINT16
636 inw (
637 QEMU_VIDEO_PRIVATE_DATA *Private,
638 UINTN Address
639 )
640 {
641 UINT16 Data;
642
643 Private->PciIo->Io.Read (
644 Private->PciIo,
645 EfiPciIoWidthUint16,
646 EFI_PCI_IO_PASS_THROUGH_BAR,
647 Address,
648 1,
649 &Data
650 );
651 return Data;
652 }
653
654 /**
655 TODO: Add function description
656
657 @param Private TODO: add argument description
658 @param Index TODO: add argument description
659 @param Red TODO: add argument description
660 @param Green TODO: add argument description
661 @param Blue TODO: add argument description
662
663 TODO: add return values
664
665 **/
666 VOID
667 SetPaletteColor (
668 QEMU_VIDEO_PRIVATE_DATA *Private,
669 UINTN Index,
670 UINT8 Red,
671 UINT8 Green,
672 UINT8 Blue
673 )
674 {
675 VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
676 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
677 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
678 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
679 }
680
681 /**
682 TODO: Add function description
683
684 @param Private TODO: add argument description
685
686 TODO: add return values
687
688 **/
689 VOID
690 SetDefaultPalette (
691 QEMU_VIDEO_PRIVATE_DATA *Private
692 )
693 {
694 UINTN Index;
695 UINTN RedIndex;
696 UINTN GreenIndex;
697 UINTN BlueIndex;
698
699 Index = 0;
700 for (RedIndex = 0; RedIndex < 8; RedIndex++) {
701 for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
702 for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
703 SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
704 Index++;
705 }
706 }
707 }
708 }
709
710 /**
711 TODO: Add function description
712
713 @param Private TODO: add argument description
714
715 TODO: add return values
716
717 **/
718 VOID
719 ClearScreen (
720 QEMU_VIDEO_PRIVATE_DATA *Private
721 )
722 {
723 UINT32 Color;
724
725 Color = 0;
726 Private->PciIo->Mem.Write (
727 Private->PciIo,
728 EfiPciIoWidthFillUint32,
729 0,
730 0,
731 0x400000 >> 2,
732 &Color
733 );
734 }
735
736 /**
737 TODO: Add function description
738
739 @param Private TODO: add argument description
740
741 TODO: add return values
742
743 **/
744 VOID
745 DrawLogo (
746 QEMU_VIDEO_PRIVATE_DATA *Private,
747 UINTN ScreenWidth,
748 UINTN ScreenHeight
749 )
750 {
751 }
752
753 /**
754 TODO: Add function description
755
756 @param Private TODO: add argument description
757 @param ModeData TODO: add argument description
758
759 TODO: add return values
760
761 **/
762 VOID
763 InitializeCirrusGraphicsMode (
764 QEMU_VIDEO_PRIVATE_DATA *Private,
765 QEMU_VIDEO_CIRRUS_MODES *ModeData
766 )
767 {
768 UINT8 Byte;
769 UINTN Index;
770
771 outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
772 outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
773
774 for (Index = 0; Index < 15; Index++) {
775 outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
776 }
777
778 if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
779 outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
780 Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
781 outb (Private, SEQ_DATA_REGISTER, Byte);
782 }
783
784 outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
785 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
786 outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
787 outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
788
789 for (Index = 0; Index < 28; Index++) {
790 outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));
791 }
792
793 for (Index = 0; Index < 9; Index++) {
794 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));
795 }
796
797 inb (Private, INPUT_STATUS_1_REGISTER);
798
799 for (Index = 0; Index < 21; Index++) {
800 outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);
801 outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
802 }
803
804 outb (Private, ATT_ADDRESS_REGISTER, 0x20);
805
806 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
807 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
808 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
809 outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
810
811 SetDefaultPalette (Private);
812 ClearScreen (Private);
813 }
814
815 VOID
816 BochsWrite (
817 QEMU_VIDEO_PRIVATE_DATA *Private,
818 UINT16 Reg,
819 UINT16 Data
820 )
821 {
822 EFI_STATUS Status;
823
824 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
825 Status = Private->PciIo->Mem.Write (
826 Private->PciIo,
827 EfiPciIoWidthUint16,
828 PCI_BAR_IDX2,
829 0x500 + (Reg << 1),
830 1,
831 &Data
832 );
833 ASSERT_EFI_ERROR (Status);
834 } else {
835 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
836 outw (Private, VBE_DISPI_IOPORT_DATA, Data);
837 }
838 }
839
840 UINT16
841 BochsRead (
842 QEMU_VIDEO_PRIVATE_DATA *Private,
843 UINT16 Reg
844 )
845 {
846 EFI_STATUS Status;
847 UINT16 Data;
848
849 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
850 Status = Private->PciIo->Mem.Read (
851 Private->PciIo,
852 EfiPciIoWidthUint16,
853 PCI_BAR_IDX2,
854 0x500 + (Reg << 1),
855 1,
856 &Data
857 );
858 ASSERT_EFI_ERROR (Status);
859 } else {
860 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
861 Data = inw (Private, VBE_DISPI_IOPORT_DATA);
862 }
863 return Data;
864 }
865
866 VOID
867 VgaOutb (
868 QEMU_VIDEO_PRIVATE_DATA *Private,
869 UINTN Reg,
870 UINT8 Data
871 )
872 {
873 EFI_STATUS Status;
874
875 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
876 Status = Private->PciIo->Mem.Write (
877 Private->PciIo,
878 EfiPciIoWidthUint8,
879 PCI_BAR_IDX2,
880 0x400 - 0x3c0 + Reg,
881 1,
882 &Data
883 );
884 ASSERT_EFI_ERROR (Status);
885 } else {
886 outb (Private, Reg, Data);
887 }
888 }
889
890 VOID
891 InitializeBochsGraphicsMode (
892 QEMU_VIDEO_PRIVATE_DATA *Private,
893 QEMU_VIDEO_BOCHS_MODES *ModeData
894 )
895 {
896 DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
897 ModeData->Width, ModeData->Height, ModeData->ColorDepth));
898
899 /* unblank */
900 VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
901
902 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);
903 BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);
904 BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);
905 BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);
906
907 BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16) ModeData->ColorDepth);
908 BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16) ModeData->Width);
909 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16) ModeData->Width);
910 BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16) ModeData->Height);
911 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);
912
913 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,
914 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
915
916 SetDefaultPalette (Private);
917 ClearScreen (Private);
918 }
919
920 EFI_STATUS
921 EFIAPI
922 InitializeQemuVideo (
923 IN EFI_HANDLE ImageHandle,
924 IN EFI_SYSTEM_TABLE *SystemTable
925 )
926 {
927 EFI_STATUS Status;
928
929 Status = EfiLibInstallDriverBindingComponentName2 (
930 ImageHandle,
931 SystemTable,
932 &gQemuVideoDriverBinding,
933 ImageHandle,
934 &gQemuVideoComponentName,
935 &gQemuVideoComponentName2
936 );
937 ASSERT_EFI_ERROR (Status);
938
939 //
940 // Install EFI Driver Supported EFI Version Protocol required for
941 // EFI drivers that are on PCI and other plug in cards.
942 //
943 gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
944 Status = gBS->InstallMultipleProtocolInterfaces (
945 &ImageHandle,
946 &gEfiDriverSupportedEfiVersionProtocolGuid,
947 &gQemuVideoDriverSupportedEfiVersion,
948 NULL
949 );
950 ASSERT_EFI_ERROR (Status);
951
952 return Status;
953 }