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