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