• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   ConsoleOut Routines that speak VGA.
3 
4 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5 
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution.  The
9 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 "BiosVideo.h"
18 
19 //
20 // EFI Driver Binding Protocol Instance
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {
23   BiosVideoDriverBindingSupported,
24   BiosVideoDriverBindingStart,
25   BiosVideoDriverBindingStop,
26   0x3,
27   NULL,
28   NULL
29 };
30 
31 //
32 // Global lookup tables for VGA graphics modes
33 //
34 UINT8                          mVgaLeftMaskTable[]   = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
35 
36 UINT8                          mVgaRightMaskTable[]  = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
37 
38 UINT8                          mVgaBitMaskTable[]    = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
39 
40 //
41 // Save controller attributes during first start
42 //
43 UINT64                         mOriginalPciAttributes;
44 BOOLEAN                        mPciAttributesSaved = FALSE;
45 
46 EFI_GRAPHICS_OUTPUT_BLT_PIXEL  mVgaColorToGraphicsOutputColor[] = {
47   { 0x00, 0x00, 0x00, 0x00 },
48   { 0x98, 0x00, 0x00, 0x00 },
49   { 0x00, 0x98, 0x00, 0x00 },
50   { 0x98, 0x98, 0x00, 0x00 },
51   { 0x00, 0x00, 0x98, 0x00 },
52   { 0x98, 0x00, 0x98, 0x00 },
53   { 0x00, 0x98, 0x98, 0x00 },
54   { 0x98, 0x98, 0x98, 0x00 },
55   { 0x10, 0x10, 0x10, 0x00 },
56   { 0xff, 0x10, 0x10, 0x00 },
57   { 0x10, 0xff, 0x10, 0x00 },
58   { 0xff, 0xff, 0x10, 0x00 },
59   { 0x10, 0x10, 0xff, 0x00 },
60   { 0xf0, 0x10, 0xff, 0x00 },
61   { 0x10, 0xff, 0xff, 0x00 },
62   { 0xff, 0xff, 0xff, 0x00 }
63 };
64 
65 //
66 // Standard timing defined by VESA EDID
67 //
68 VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = {
69   //
70   // Established Timing I
71   //
72   {800, 600, 60},
73   {800, 600, 56},
74   {640, 480, 75},
75   {640, 480, 72},
76   {640, 480, 67},
77   {640, 480, 60},
78   {720, 400, 88},
79   {720, 400, 70},
80   //
81   // Established Timing II
82   //
83   {1280, 1024, 75},
84   {1024,  768, 75},
85   {1024,  768, 70},
86   {1024,  768, 60},
87   {1024,  768, 87},
88   {832,   624, 75},
89   {800,   600, 75},
90   {800,   600, 72},
91   //
92   // Established Timing III
93   //
94   {1152, 870, 75}
95 };
96 
97 /**
98   Supported.
99 
100   @param  This                   Pointer to driver binding protocol
101   @param  Controller             Controller handle to connect
102   @param  RemainingDevicePath    A pointer to the remaining portion of a device
103                                  path
104 
105   @retval EFI_STATUS             EFI_SUCCESS:This controller can be managed by this
106                                  driver, Otherwise, this controller cannot be
107                                  managed by this driver
108 
109 **/
110 EFI_STATUS
111 EFIAPI
BiosVideoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)112 BiosVideoDriverBindingSupported (
113   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
114   IN EFI_HANDLE                   Controller,
115   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
116   )
117 {
118   EFI_STATUS                Status;
119   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
120   EFI_PCI_IO_PROTOCOL       *PciIo;
121   PCI_TYPE00                Pci;
122   EFI_DEV_PATH              *Node;
123 
124   //
125   // See if the Legacy BIOS Protocol is available
126   //
127   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
128   if (EFI_ERROR (Status)) {
129     return Status;
130   }
131 
132   //
133   // Open the IO Abstraction(s) needed to perform the supported test
134   //
135   Status = gBS->OpenProtocol (
136                   Controller,
137                   &gEfiPciIoProtocolGuid,
138                   (VOID **) &PciIo,
139                   This->DriverBindingHandle,
140                   Controller,
141                   EFI_OPEN_PROTOCOL_BY_DRIVER
142                   );
143   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
144     return Status;
145   }
146 
147   if (Status == EFI_ALREADY_STARTED) {
148     //
149     // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,
150     // because VgaMiniPort protocol is installed on controller handle directly.
151     //
152     Status = gBS->OpenProtocol (
153                     Controller,
154                     &gEfiVgaMiniPortProtocolGuid,
155                     NULL,
156                     NULL,
157                     NULL,
158                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
159                     );
160     if (!EFI_ERROR (Status)) {
161       return EFI_ALREADY_STARTED;
162     }
163   }
164   //
165   // See if this is a PCI Graphics Controller by looking at the Command register and
166   // Class Code Register
167   //
168   Status = PciIo->Pci.Read (
169                         PciIo,
170                         EfiPciIoWidthUint32,
171                         0,
172                         sizeof (Pci) / sizeof (UINT32),
173                         &Pci
174                         );
175   if (EFI_ERROR (Status)) {
176     Status = EFI_UNSUPPORTED;
177     goto Done;
178   }
179 
180   Status = EFI_UNSUPPORTED;
181   if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {
182 
183     Status = EFI_SUCCESS;
184     //
185     // If this is a graphics controller,
186     // go further check RemainingDevicePath validation
187     //
188     if (RemainingDevicePath != NULL) {
189       Node = (EFI_DEV_PATH *) RemainingDevicePath;
190       //
191       // Check if RemainingDevicePath is the End of Device Path Node,
192       // if yes, return EFI_SUCCESS
193       //
194       if (!IsDevicePathEnd (Node)) {
195         //
196         // If RemainingDevicePath isn't the End of Device Path Node,
197         // check its validation
198         //
199         if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
200             Node->DevPath.SubType != ACPI_ADR_DP ||
201             DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {
202           Status = EFI_UNSUPPORTED;
203         }
204       }
205     }
206   }
207 
208 Done:
209   gBS->CloseProtocol (
210          Controller,
211          &gEfiPciIoProtocolGuid,
212          This->DriverBindingHandle,
213          Controller
214          );
215 
216   return Status;
217 }
218 
219 
220 /**
221   Install Graphics Output Protocol onto VGA device handles.
222 
223   @param  This                   Pointer to driver binding protocol
224   @param  Controller             Controller handle to connect
225   @param  RemainingDevicePath    A pointer to the remaining portion of a device
226                                  path
227 
228   @return EFI_STATUS
229 
230 **/
231 EFI_STATUS
232 EFIAPI
BiosVideoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)233 BiosVideoDriverBindingStart (
234   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
235   IN EFI_HANDLE                   Controller,
236   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
237   )
238 {
239   EFI_STATUS                Status;
240   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
241   EFI_PCI_IO_PROTOCOL       *PciIo;
242   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
243   UINTN                     Flags;
244   UINT64                    Supports;
245 
246   //
247   // Initialize local variables
248   //
249   PciIo            = NULL;
250   ParentDevicePath = NULL;
251 
252   //
253   //
254   // See if the Legacy BIOS Protocol is available
255   //
256   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
257   if (EFI_ERROR (Status)) {
258     return Status;
259   }
260 
261   //
262   // Prepare for status code
263   //
264   Status = gBS->HandleProtocol (
265                   Controller,
266                   &gEfiDevicePathProtocolGuid,
267                   (VOID **) &ParentDevicePath
268                   );
269   if (EFI_ERROR (Status)) {
270     return Status;
271   }
272 
273   //
274   // Open the IO Abstraction(s) needed
275   //
276   Status = gBS->OpenProtocol (
277                   Controller,
278                   &gEfiPciIoProtocolGuid,
279                   (VOID **) &PciIo,
280                   This->DriverBindingHandle,
281                   Controller,
282                   EFI_OPEN_PROTOCOL_BY_DRIVER
283                   );
284   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
285     return Status;
286   }
287 
288   //
289   // Save original PCI attributes
290   //
291   if (!mPciAttributesSaved) {
292     Status = PciIo->Attributes (
293                       PciIo,
294                       EfiPciIoAttributeOperationGet,
295                       0,
296                       &mOriginalPciAttributes
297                       );
298 
299     if (EFI_ERROR (Status)) {
300       goto Done;
301     }
302     mPciAttributesSaved = TRUE;
303   }
304 
305   //
306   // Get supported PCI attributes
307   //
308   Status = PciIo->Attributes (
309                     PciIo,
310                     EfiPciIoAttributeOperationSupported,
311                     0,
312                     &Supports
313                     );
314   if (EFI_ERROR (Status)) {
315     goto Done;
316   }
317 
318   Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
319   if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
320     Status = EFI_UNSUPPORTED;
321     goto Done;
322   }
323 
324   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
325     EFI_PROGRESS_CODE,
326     EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
327     ParentDevicePath
328     );
329   //
330   // Enable the device and make sure VGA cycles are being forwarded to this VGA device
331   //
332   Status = PciIo->Attributes (
333              PciIo,
334              EfiPciIoAttributeOperationEnable,
335              EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,
336              NULL
337              );
338   if (EFI_ERROR (Status)) {
339     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
340       EFI_ERROR_CODE | EFI_ERROR_MINOR,
341       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
342       ParentDevicePath
343       );
344     goto Done;
345   }
346   //
347   // Check to see if there is a legacy option ROM image associated with this PCI device
348   //
349   Status = LegacyBios->CheckPciRom (
350                          LegacyBios,
351                          Controller,
352                          NULL,
353                          NULL,
354                          &Flags
355                          );
356   if (EFI_ERROR (Status)) {
357     goto Done;
358   }
359   //
360   // Post the legacy option ROM if it is available.
361   //
362   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
363     EFI_PROGRESS_CODE,
364     EFI_P_PC_RESET,
365     ParentDevicePath
366     );
367   Status = LegacyBios->InstallPciRom (
368                          LegacyBios,
369                          Controller,
370                          NULL,
371                          &Flags,
372                          NULL,
373                          NULL,
374                          NULL,
375                          NULL
376                          );
377   if (EFI_ERROR (Status)) {
378     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
379       EFI_ERROR_CODE | EFI_ERROR_MINOR,
380       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
381       ParentDevicePath
382       );
383     goto Done;
384   }
385 
386   if (RemainingDevicePath != NULL) {
387     if (IsDevicePathEnd (RemainingDevicePath) &&
388         (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) {
389       //
390       // If RemainingDevicePath is the End of Device Path Node,
391       // don't create any child device and return EFI_SUCESS
392       Status = EFI_SUCCESS;
393       goto Done;
394     }
395   }
396 
397   //
398   // Create child handle and install GraphicsOutputProtocol on it
399   //
400   Status = BiosVideoChildHandleInstall (
401              This,
402              Controller,
403              PciIo,
404              LegacyBios,
405              ParentDevicePath,
406              RemainingDevicePath
407              );
408 
409 Done:
410   if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
411     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
412       EFI_PROGRESS_CODE,
413       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
414       ParentDevicePath
415       );
416 
417     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
418       EFI_PROGRESS_CODE,
419       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
420       ParentDevicePath
421       );
422     if (!HasChildHandle (Controller)) {
423       if (mPciAttributesSaved) {
424         //
425         // Restore original PCI attributes
426         //
427         PciIo->Attributes (
428                         PciIo,
429                         EfiPciIoAttributeOperationSet,
430                         mOriginalPciAttributes,
431                         NULL
432                         );
433       }
434     }
435     //
436     // Release PCI I/O Protocols on the controller handle.
437     //
438     gBS->CloseProtocol (
439            Controller,
440            &gEfiPciIoProtocolGuid,
441            This->DriverBindingHandle,
442            Controller
443            );
444   }
445 
446   return Status;
447 }
448 
449 
450 /**
451   Stop.
452 
453   @param  This                   Pointer to driver binding protocol
454   @param  Controller             Controller handle to connect
455   @param  NumberOfChildren       Number of children handle created by this driver
456   @param  ChildHandleBuffer      Buffer containing child handle created
457 
458   @retval EFI_SUCCESS            Driver disconnected successfully from controller
459   @retval EFI_UNSUPPORTED        Cannot find BIOS_VIDEO_DEV structure
460 
461 **/
462 EFI_STATUS
463 EFIAPI
BiosVideoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)464 BiosVideoDriverBindingStop (
465   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
466   IN  EFI_HANDLE                      Controller,
467   IN  UINTN                           NumberOfChildren,
468   IN  EFI_HANDLE                      *ChildHandleBuffer
469   )
470 {
471   EFI_STATUS                   Status;
472   BOOLEAN                      AllChildrenStopped;
473   UINTN                        Index;
474   EFI_PCI_IO_PROTOCOL          *PciIo;
475 
476   AllChildrenStopped = TRUE;
477 
478   if (NumberOfChildren == 0) {
479     //
480     // Close PCI I/O protocol on the controller handle
481     //
482     gBS->CloseProtocol (
483            Controller,
484            &gEfiPciIoProtocolGuid,
485            This->DriverBindingHandle,
486            Controller
487            );
488 
489     return EFI_SUCCESS;
490   }
491 
492   for (Index = 0; Index < NumberOfChildren; Index++) {
493     Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
494 
495     if (EFI_ERROR (Status)) {
496       AllChildrenStopped = FALSE;
497     }
498   }
499 
500   if (!AllChildrenStopped) {
501     return EFI_DEVICE_ERROR;
502   }
503 
504   if (!HasChildHandle (Controller)) {
505     if (mPciAttributesSaved) {
506       Status = gBS->HandleProtocol (
507                       Controller,
508                       &gEfiPciIoProtocolGuid,
509                       (VOID **) &PciIo
510                       );
511       ASSERT_EFI_ERROR (Status);
512 
513       //
514       // Restore original PCI attributes
515       //
516       Status = PciIo->Attributes (
517                         PciIo,
518                         EfiPciIoAttributeOperationSet,
519                         mOriginalPciAttributes,
520                         NULL
521                         );
522       ASSERT_EFI_ERROR (Status);
523     }
524   }
525 
526 
527   return EFI_SUCCESS;
528 }
529 
530 
531 /**
532   Install child handles if the Handle supports MBR format.
533 
534   @param  This                   Calling context.
535   @param  ParentHandle           Parent Handle
536   @param  ParentPciIo            Parent PciIo interface
537   @param  ParentLegacyBios       Parent LegacyBios interface
538   @param  ParentDevicePath       Parent Device Path
539   @param  RemainingDevicePath    Remaining Device Path
540 
541   @retval EFI_SUCCESS            If a child handle was added
542   @retval other                  A child handle was not added
543 
544 **/
545 EFI_STATUS
BiosVideoChildHandleInstall(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ParentHandle,IN EFI_PCI_IO_PROTOCOL * ParentPciIo,IN EFI_LEGACY_BIOS_PROTOCOL * ParentLegacyBios,IN EFI_DEVICE_PATH_PROTOCOL * ParentDevicePath,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)546 BiosVideoChildHandleInstall (
547   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
548   IN  EFI_HANDLE                   ParentHandle,
549   IN  EFI_PCI_IO_PROTOCOL          *ParentPciIo,
550   IN  EFI_LEGACY_BIOS_PROTOCOL     *ParentLegacyBios,
551   IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,
552   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
553   )
554 {
555   EFI_STATUS               Status;
556   BIOS_VIDEO_DEV           *BiosVideoPrivate;
557   PCI_TYPE00               Pci;
558   ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;
559   BOOLEAN                  ProtocolInstalled;
560 
561   //
562   // Allocate the private device structure for video device
563   //
564   BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool (
565 																					sizeof (BIOS_VIDEO_DEV)
566 																					);
567   if (NULL == BiosVideoPrivate) {
568 		Status = EFI_OUT_OF_RESOURCES;
569     goto Done;
570   }
571 
572   //
573   // See if this is a VGA compatible controller or not
574   //
575   Status = ParentPciIo->Pci.Read (
576                           ParentPciIo,
577                           EfiPciIoWidthUint32,
578                           0,
579                           sizeof (Pci) / sizeof (UINT32),
580                           &Pci
581                           );
582   if (EFI_ERROR (Status)) {
583     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
584       EFI_ERROR_CODE | EFI_ERROR_MINOR,
585       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
586       ParentDevicePath
587       );
588     goto Done;
589   }
590   BiosVideoPrivate->VgaCompatible = FALSE;
591   if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) {
592     BiosVideoPrivate->VgaCompatible = TRUE;
593   }
594 
595   if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) {
596     BiosVideoPrivate->VgaCompatible = TRUE;
597   }
598 
599  if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
600     //
601     // Create EXIT_BOOT_SERIVES Event
602     //
603     Status = gBS->CreateEventEx (
604                     EVT_NOTIFY_SIGNAL,
605                     TPL_NOTIFY,
606                     BiosVideoNotifyExitBootServices,
607                     BiosVideoPrivate,
608                     &gEfiEventExitBootServicesGuid,
609                     &BiosVideoPrivate->ExitBootServicesEvent
610                     );
611     if (EFI_ERROR (Status)) {
612       goto Done;
613     }
614   }
615 
616   //
617   // Initialize the child private structure
618   //
619   BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;
620 
621   //
622   // Fill in Graphics Output specific mode structures
623   //
624   BiosVideoPrivate->HardwareNeedsStarting = TRUE;
625   BiosVideoPrivate->ModeData              = NULL;
626   BiosVideoPrivate->LineBuffer            = NULL;
627   BiosVideoPrivate->VgaFrameBuffer        = NULL;
628   BiosVideoPrivate->VbeFrameBuffer        = NULL;
629 
630   //
631   // Fill in the Graphics Output Protocol
632   //
633   BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;
634   BiosVideoPrivate->GraphicsOutput.SetMode   = BiosVideoGraphicsOutputSetMode;
635 
636 
637   //
638   // Allocate buffer for Graphics Output Protocol mode information
639   //
640   BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
641                                              sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
642                                              );
643   if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) {
644     Status = EFI_OUT_OF_RESOURCES;
645     goto Done;
646   }
647 
648   BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
649                                              sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
650                                              );
651   if (NULL ==  BiosVideoPrivate->GraphicsOutput.Mode->Info) {
652     Status = EFI_OUT_OF_RESOURCES;
653     goto Done;
654   }
655 
656   //
657   // Assume that Graphics Output Protocol will be produced until proven otherwise
658   //
659   BiosVideoPrivate->ProduceGraphicsOutput = TRUE;
660 
661   //
662   // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
663   //
664   if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
665     if (RemainingDevicePath == NULL) {
666       ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
667       AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
668       AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
669       AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
670       SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
671 
672       BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (
673                                           ParentDevicePath,
674                                           (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
675                                           );
676     } else {
677       BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
678     }
679 
680     //
681     // Creat child handle and device path protocol firstly
682     //
683     BiosVideoPrivate->Handle = NULL;
684     Status = gBS->InstallMultipleProtocolInterfaces (
685                     &BiosVideoPrivate->Handle,
686                     &gEfiDevicePathProtocolGuid,
687                     BiosVideoPrivate->GopDevicePath,
688                     NULL
689                     );
690     if (EFI_ERROR (Status)) {
691       goto Done;
692     }
693   }
694 
695   //
696   // Fill in the VGA Mini Port Protocol fields
697   //
698   BiosVideoPrivate->VgaMiniPort.SetMode                   = BiosVideoVgaMiniPortSetMode;
699   BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset           = 0xb8000;
700   BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
701   BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset    = 0x3d5;
702   BiosVideoPrivate->VgaMiniPort.VgaMemoryBar              = EFI_PCI_IO_PASS_THROUGH_BAR;
703   BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar    = EFI_PCI_IO_PASS_THROUGH_BAR;
704   BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar       = EFI_PCI_IO_PASS_THROUGH_BAR;
705 
706   //
707   // Child handle need to consume the Legacy Bios protocol
708   //
709   BiosVideoPrivate->LegacyBios = ParentLegacyBios;
710 
711   //
712   // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
713   //
714   BiosVideoPrivate->PciIo                 = ParentPciIo;
715 
716   //
717   // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
718   //
719   if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) {
720     Status = BiosVideoCheckForVbe (BiosVideoPrivate);
721     DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status));
722   } else {
723     Status = EFI_UNSUPPORTED;
724   }
725   if (EFI_ERROR (Status)) {
726     //
727     // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
728     // for the standard 640x480 16 color VGA mode
729     //
730     DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible));
731     if (BiosVideoPrivate->VgaCompatible) {
732       if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) {
733         Status = BiosVideoCheckForVga (BiosVideoPrivate);
734         DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status));
735       } else {
736         Status = EFI_UNSUPPORTED;
737       }
738     }
739 
740     if (EFI_ERROR (Status)) {
741       //
742       // Free GOP mode structure if it is not freed before
743       // VgaMiniPort does not need this structure any more
744       //
745       if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
746         if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
747           FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
748           BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
749         }
750         FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
751         BiosVideoPrivate->GraphicsOutput.Mode = NULL;
752       }
753 
754       //
755       // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
756       // not produce the Graphics Output protocol.  Instead, produce the VGA MiniPort Protocol.
757       //
758       BiosVideoPrivate->ProduceGraphicsOutput = FALSE;
759 
760       //
761       // INT services are available, so on the 80x25 and 80x50 text mode are supported
762       //
763       BiosVideoPrivate->VgaMiniPort.MaxMode = 2;
764     }
765   }
766 
767   ProtocolInstalled = FALSE;
768 
769   if (BiosVideoPrivate->ProduceGraphicsOutput) {
770     //
771     // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
772     //
773     Status = gBS->InstallMultipleProtocolInterfaces (
774                     &BiosVideoPrivate->Handle,
775                     &gEfiGraphicsOutputProtocolGuid,
776                     &BiosVideoPrivate->GraphicsOutput,
777                     &gEfiEdidDiscoveredProtocolGuid,
778                     &BiosVideoPrivate->EdidDiscovered,
779                     &gEfiEdidActiveProtocolGuid,
780                     &BiosVideoPrivate->EdidActive,
781                     NULL
782                     );
783 
784     if (!EFI_ERROR (Status)) {
785       //
786       // Open the Parent Handle for the child
787       //
788       Status = gBS->OpenProtocol (
789                       ParentHandle,
790                       &gEfiPciIoProtocolGuid,
791                       (VOID **) &BiosVideoPrivate->PciIo,
792                       This->DriverBindingHandle,
793                       BiosVideoPrivate->Handle,
794                       EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
795                       );
796       if (EFI_ERROR (Status)) {
797         goto Done;
798       }
799       ProtocolInstalled = TRUE;
800     }
801   }
802 
803   if (!ProtocolInstalled) {
804     //
805     // Install VGA Mini Port Protocol
806     //
807     Status = gBS->InstallMultipleProtocolInterfaces (
808                     &ParentHandle,
809                     &gEfiVgaMiniPortProtocolGuid,
810                     &BiosVideoPrivate->VgaMiniPort,
811                     NULL
812                     );
813   }
814 
815 Done:
816   if (EFI_ERROR (Status)) {
817     if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) {
818       gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
819     }
820     //
821     // Free private data structure
822     //
823     BiosVideoDeviceReleaseResource (BiosVideoPrivate);
824   }
825 
826   return Status;
827 }
828 
829 
830 /**
831   Deregister an video child handle and free resources.
832 
833   @param  This                   Protocol instance pointer.
834   @param  Controller             Video controller handle
835   @param  Handle                 Video child handle
836 
837   @return EFI_STATUS
838 
839 **/
840 EFI_STATUS
BiosVideoChildHandleUninstall(EFI_DRIVER_BINDING_PROTOCOL * This,EFI_HANDLE Controller,EFI_HANDLE Handle)841 BiosVideoChildHandleUninstall (
842   EFI_DRIVER_BINDING_PROTOCOL    *This,
843   EFI_HANDLE                     Controller,
844   EFI_HANDLE                     Handle
845   )
846 {
847   EFI_STATUS                   Status;
848   EFI_IA32_REGISTER_SET        Regs;
849   EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
850   EFI_VGA_MINI_PORT_PROTOCOL   *VgaMiniPort;
851   BIOS_VIDEO_DEV               *BiosVideoPrivate;
852   EFI_PCI_IO_PROTOCOL          *PciIo;
853 
854   BiosVideoPrivate = NULL;
855   GraphicsOutput   = NULL;
856   PciIo            = NULL;
857   Status           = EFI_UNSUPPORTED;
858 
859   Status = gBS->OpenProtocol (
860                   Handle,
861                   &gEfiGraphicsOutputProtocolGuid,
862                   (VOID **) &GraphicsOutput,
863                   This->DriverBindingHandle,
864                   Handle,
865                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
866                   );
867   if (!EFI_ERROR (Status)) {
868       BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
869   }
870 
871   if (EFI_ERROR (Status)) {
872     Status = gBS->OpenProtocol (
873                    Handle,
874                    &gEfiVgaMiniPortProtocolGuid,
875                    (VOID **) &VgaMiniPort,
876                    This->DriverBindingHandle,
877                    Handle,
878                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
879                    );
880     if (!EFI_ERROR (Status)) {
881       BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);
882     }
883   }
884 
885   if (BiosVideoPrivate == NULL) {
886     return EFI_UNSUPPORTED;
887   }
888 
889   //
890   // Set the 80x25 Text VGA Mode
891   //
892   Regs.H.AH = 0x00;
893   Regs.H.AL = 0x03;
894   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
895 
896   Regs.H.AH = 0x11;
897   Regs.H.AL = 0x14;
898   Regs.H.BL = 0;
899   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
900 
901   //
902   // Close PCI I/O protocol that opened by child handle
903   //
904   Status = gBS->CloseProtocol (
905                   Controller,
906                   &gEfiPciIoProtocolGuid,
907                   This->DriverBindingHandle,
908                   Handle
909                   );
910 
911   //
912   // Uninstall protocols on child handle
913   //
914   if (BiosVideoPrivate->ProduceGraphicsOutput) {
915     Status = gBS->UninstallMultipleProtocolInterfaces (
916                     BiosVideoPrivate->Handle,
917                     &gEfiDevicePathProtocolGuid,
918                     BiosVideoPrivate->GopDevicePath,
919                     &gEfiGraphicsOutputProtocolGuid,
920                     &BiosVideoPrivate->GraphicsOutput,
921                     &gEfiEdidDiscoveredProtocolGuid,
922                     &BiosVideoPrivate->EdidDiscovered,
923                     &gEfiEdidActiveProtocolGuid,
924                     &BiosVideoPrivate->EdidActive,
925                     NULL
926                     );
927   }
928   if (!BiosVideoPrivate->ProduceGraphicsOutput) {
929     Status = gBS->UninstallMultipleProtocolInterfaces (
930                     Controller,
931                     &gEfiVgaMiniPortProtocolGuid,
932                     &BiosVideoPrivate->VgaMiniPort,
933                     NULL
934                     );
935   }
936 
937   if (EFI_ERROR (Status)) {
938     gBS->OpenProtocol (
939            Controller,
940            &gEfiPciIoProtocolGuid,
941            (VOID **) &PciIo,
942            This->DriverBindingHandle,
943            Handle,
944            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
945            );
946     return Status;
947   }
948 
949   if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
950     //
951     // Close EXIT_BOOT_SERIVES Event
952     //
953     gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
954   }
955 
956   //
957   // Release all allocated resources
958   //
959   BiosVideoDeviceReleaseResource (BiosVideoPrivate);
960 
961   return EFI_SUCCESS;
962 }
963 
964 
965 /**
966   Release resource for biso video instance.
967 
968   @param  BiosVideoPrivate       Video child device private data structure
969 
970 **/
971 VOID
BiosVideoDeviceReleaseResource(BIOS_VIDEO_DEV * BiosVideoPrivate)972 BiosVideoDeviceReleaseResource (
973   BIOS_VIDEO_DEV  *BiosVideoPrivate
974   )
975 {
976   if (BiosVideoPrivate == NULL) {
977     return ;
978   }
979 
980   //
981   // Release all the resourses occupied by the BIOS_VIDEO_DEV
982   //
983 
984   //
985   // Free VGA Frame Buffer
986   //
987   if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
988     FreePool (BiosVideoPrivate->VgaFrameBuffer);
989   }
990   //
991   // Free VBE Frame Buffer
992   //
993   if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
994     FreePool (BiosVideoPrivate->VbeFrameBuffer);
995   }
996   //
997   // Free line buffer
998   //
999   if (BiosVideoPrivate->LineBuffer != NULL) {
1000     FreePool (BiosVideoPrivate->LineBuffer);
1001   }
1002   //
1003   // Free mode data
1004   //
1005   if (BiosVideoPrivate->ModeData != NULL) {
1006     FreePool (BiosVideoPrivate->ModeData);
1007   }
1008   //
1009   // Free memory allocated below 1MB
1010   //
1011   if (BiosVideoPrivate->PagesBelow1MB != 0) {
1012     gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
1013   }
1014 
1015   if (BiosVideoPrivate->VbeSaveRestorePages != 0) {
1016     gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);
1017   }
1018 
1019   //
1020   // Free graphics output protocol occupied resource
1021   //
1022   if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1023     if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1024         FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1025         BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
1026     }
1027     FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1028     BiosVideoPrivate->GraphicsOutput.Mode = NULL;
1029   }
1030   //
1031   // Free EDID discovered protocol occupied resource
1032   //
1033   if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {
1034     FreePool (BiosVideoPrivate->EdidDiscovered.Edid);
1035   }
1036   //
1037   // Free EDID active protocol occupied resource
1038   //
1039   if (BiosVideoPrivate->EdidActive.Edid != NULL) {
1040     FreePool (BiosVideoPrivate->EdidActive.Edid);
1041   }
1042 
1043   if (BiosVideoPrivate->GopDevicePath!= NULL) {
1044     FreePool (BiosVideoPrivate->GopDevicePath);
1045   }
1046 
1047   FreePool (BiosVideoPrivate);
1048 
1049   return ;
1050 }
1051 
1052 
1053 /**
1054   Generate a search key for a specified timing data.
1055 
1056   @param  EdidTiming             Pointer to EDID timing
1057 
1058   @return The 32 bit unique key for search.
1059 
1060 **/
1061 UINT32
CalculateEdidKey(VESA_BIOS_EXTENSIONS_EDID_TIMING * EdidTiming)1062 CalculateEdidKey (
1063   VESA_BIOS_EXTENSIONS_EDID_TIMING       *EdidTiming
1064   )
1065 {
1066   UINT32 Key;
1067 
1068   //
1069   // Be sure no conflicts for all standard timing defined by VESA.
1070   //
1071   Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
1072   return Key;
1073 }
1074 
1075 
1076 /**
1077   Parse the Established Timing and Standard Timing in EDID data block.
1078 
1079   @param  EdidBuffer             Pointer to EDID data block
1080   @param  ValidEdidTiming        Valid EDID timing information
1081 
1082   @retval TRUE                   The EDID data is valid.
1083   @retval FALSE                  The EDID data is invalid.
1084 
1085 **/
1086 BOOLEAN
ParseEdidData(UINT8 * EdidBuffer,VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING * ValidEdidTiming)1087 ParseEdidData (
1088   UINT8                                      *EdidBuffer,
1089   VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING     *ValidEdidTiming
1090   )
1091 {
1092   UINT8  CheckSum;
1093   UINT32 Index;
1094   UINT32 ValidNumber;
1095   UINT32 TimingBits;
1096   UINT8  *BufferIndex;
1097   UINT16 HorizontalResolution;
1098   UINT16 VerticalResolution;
1099   UINT8  AspectRatio;
1100   UINT8  RefreshRate;
1101   VESA_BIOS_EXTENSIONS_EDID_TIMING     TempTiming;
1102   VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;
1103 
1104   EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;
1105 
1106   //
1107   // Check the checksum of EDID data
1108   //
1109   CheckSum = 0;
1110   for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {
1111     CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
1112   }
1113   if (CheckSum != 0) {
1114     return FALSE;
1115   }
1116 
1117   ValidNumber = 0;
1118   gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);
1119 
1120   if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
1121       (EdidDataBlock->EstablishedTimings[1] != 0) ||
1122       (EdidDataBlock->EstablishedTimings[2] != 0)
1123       ) {
1124     //
1125     // Established timing data
1126     //
1127     TimingBits = EdidDataBlock->EstablishedTimings[0] |
1128                  (EdidDataBlock->EstablishedTimings[1] << 8) |
1129                  ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
1130     for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
1131       if ((TimingBits & 0x1) != 0) {
1132         DEBUG ((EFI_D_INFO, "Established Timing: %d x %d\n",
1133         mEstablishedEdidTiming[Index].HorizontalResolution, mEstablishedEdidTiming[Index].VerticalResolution));
1134         ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);
1135         ValidNumber ++;
1136       }
1137       TimingBits = TimingBits >> 1;
1138     }
1139   }
1140 
1141   //
1142   // Parse the standard timing data
1143   //
1144   BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
1145   for (Index = 0; Index < 8; Index ++) {
1146     //
1147     // Check if this is a valid Standard Timing entry
1148     // VESA documents unused fields should be set to 01h
1149     //
1150     if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
1151       //
1152       // A valid Standard Timing
1153       //
1154       HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
1155       AspectRatio = (UINT8) (BufferIndex[1] >> 6);
1156       switch (AspectRatio) {
1157         case 0:
1158           VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
1159           break;
1160         case 1:
1161           VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
1162           break;
1163         case 2:
1164           VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
1165           break;
1166         case 3:
1167           VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
1168           break;
1169         default:
1170           VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
1171           break;
1172       }
1173       RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
1174       DEBUG ((EFI_D_INFO, "Standard Timing: %d x %d\n", HorizontalResolution, VerticalResolution));
1175       TempTiming.HorizontalResolution = HorizontalResolution;
1176       TempTiming.VerticalResolution = VerticalResolution;
1177       TempTiming.RefreshRate = RefreshRate;
1178       ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
1179       ValidNumber ++;
1180     }
1181     BufferIndex += 2;
1182   }
1183 
1184   //
1185   // Parse the Detailed Timing data
1186   //
1187   BufferIndex = &EdidDataBlock->DetailedTimingDescriptions[0];
1188   for (Index = 0; Index < 4; Index ++, BufferIndex += VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE) {
1189     if ((BufferIndex[0] == 0x0) && (BufferIndex[1] == 0x0)) {
1190       //
1191       // Check if this is a valid Detailed Timing Descriptor
1192       // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor
1193       //
1194       continue;
1195     }
1196     //
1197     // Calculate Horizontal and Vertical resolution
1198     //
1199     TempTiming.HorizontalResolution = ((UINT16)(BufferIndex[4] & 0xF0) << 4) | (BufferIndex[2]);
1200     TempTiming.VerticalResolution = ((UINT16)(BufferIndex[7] & 0xF0) << 4) | (BufferIndex[5]);
1201     DEBUG ((EFI_D_INFO, "Detailed Timing %d: %d x %d\n",
1202             Index, TempTiming.HorizontalResolution, TempTiming.VerticalResolution));
1203     ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
1204     ValidNumber ++;
1205   }
1206 
1207   ValidEdidTiming->ValidNumber = ValidNumber;
1208   return TRUE;
1209 }
1210 
1211 
1212 /**
1213   Search a specified Timing in all the valid EDID timings.
1214 
1215   @param  ValidEdidTiming        All valid EDID timing information.
1216   @param  EdidTiming             The Timing to search for.
1217 
1218   @retval TRUE                   Found.
1219   @retval FALSE                  Not found.
1220 
1221 **/
1222 BOOLEAN
SearchEdidTiming(VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING * ValidEdidTiming,VESA_BIOS_EXTENSIONS_EDID_TIMING * EdidTiming)1223 SearchEdidTiming (
1224   VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,
1225   VESA_BIOS_EXTENSIONS_EDID_TIMING       *EdidTiming
1226   )
1227 {
1228   UINT32 Index;
1229   UINT32 Key;
1230 
1231   Key = CalculateEdidKey (EdidTiming);
1232 
1233   for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
1234     if (Key == ValidEdidTiming->Key[Index]) {
1235       return TRUE;
1236     }
1237   }
1238 
1239   return FALSE;
1240 }
1241 
1242 /**
1243   Check if all video child handles have been uninstalled.
1244 
1245   @param  Controller             Video controller handle
1246 
1247   @return TRUE                   Child handles exist.
1248   @return FALSE                  All video child handles have been uninstalled.
1249 
1250 **/
1251 BOOLEAN
HasChildHandle(IN EFI_HANDLE Controller)1252 HasChildHandle (
1253   IN EFI_HANDLE  Controller
1254   )
1255 {
1256   UINTN                                Index;
1257   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
1258   UINTN                                EntryCount;
1259   BOOLEAN                              HasChild;
1260 
1261   EntryCount = 0;
1262   HasChild   = FALSE;
1263   gBS->OpenProtocolInformation (
1264          Controller,
1265          &gEfiPciIoProtocolGuid,
1266          &OpenInfoBuffer,
1267          &EntryCount
1268          );
1269   for (Index = 0; Index < EntryCount; Index++) {
1270     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1271       HasChild = TRUE;
1272     }
1273   }
1274 
1275   return HasChild;
1276 }
1277 
1278 /**
1279   Check for VBE device.
1280 
1281   @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure
1282 
1283   @retval EFI_SUCCESS            VBE device found
1284 
1285 **/
1286 EFI_STATUS
BiosVideoCheckForVbe(IN OUT BIOS_VIDEO_DEV * BiosVideoPrivate)1287 BiosVideoCheckForVbe (
1288   IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate
1289   )
1290 {
1291   EFI_STATUS                             Status;
1292   EFI_IA32_REGISTER_SET                  Regs;
1293   UINT16                                 *ModeNumberPtr;
1294   UINT16                                 VbeModeNumber;
1295   BOOLEAN                                ModeFound;
1296   BOOLEAN                                EdidFound;
1297   BIOS_VIDEO_MODE_DATA                   *ModeBuffer;
1298   BIOS_VIDEO_MODE_DATA                   *CurrentModeData;
1299   UINTN                                  PreferMode;
1300   UINTN                                  ModeNumber;
1301   VESA_BIOS_EXTENSIONS_EDID_TIMING       Timing;
1302   VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
1303   EFI_EDID_OVERRIDE_PROTOCOL             *EdidOverride;
1304   UINT32                                 EdidAttributes;
1305   BOOLEAN                                EdidOverrideFound;
1306   UINTN                                  EdidOverrideDataSize;
1307   UINT8                                  *EdidOverrideDataBlock;
1308   UINTN                                  EdidActiveDataSize;
1309   UINT8                                  *EdidActiveDataBlock;
1310   UINT32                                 HighestHorizontalResolution;
1311   UINT32                                 HighestVerticalResolution;
1312   UINTN                                  HighestResolutionMode;
1313 
1314   EdidFound             = TRUE;
1315   EdidOverrideFound     = FALSE;
1316   EdidOverrideDataBlock = NULL;
1317   EdidActiveDataSize    = 0;
1318   EdidActiveDataBlock   = NULL;
1319   HighestHorizontalResolution = 0;
1320   HighestVerticalResolution   = 0;
1321   HighestResolutionMode       = 0;
1322 
1323   //
1324   // Allocate buffer under 1MB for VBE data structures
1325   //
1326   BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
1327                                               sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +
1328                                               sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
1329                                               sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +
1330                                               sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
1331                                               );
1332 
1333   BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
1334 
1335   Status = gBS->AllocatePages (
1336                   AllocateMaxAddress,
1337                   EfiBootServicesData,
1338                   BiosVideoPrivate->NumberOfPagesBelow1MB,
1339                   &BiosVideoPrivate->PagesBelow1MB
1340                   );
1341   if (EFI_ERROR (Status)) {
1342     return Status;
1343   }
1344 
1345   ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));
1346 
1347   //
1348   // Fill in the VBE related data structures
1349   //
1350   BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
1351   BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
1352   BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
1353   BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);
1354   BiosVideoPrivate->VbeSaveRestorePages   = 0;
1355   BiosVideoPrivate->VbeSaveRestoreBuffer  = 0;
1356 
1357   //
1358   // Test to see if the Video Adapter is compliant with VBE 3.0
1359   //
1360   gBS->SetMem (&Regs, sizeof (Regs), 0);
1361   Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
1362   gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
1363   BiosVideoPrivate->VbeInformationBlock->VESASignature  = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
1364   Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1365   Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1366 
1367   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1368 
1369   Status = EFI_DEVICE_ERROR;
1370 
1371   //
1372   // See if the VESA call succeeded
1373   //
1374   if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1375     return Status;
1376   }
1377   //
1378   // Check for 'VESA' signature
1379   //
1380   if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
1381     return Status;
1382   }
1383   //
1384   // Check to see if this is VBE 2.0 or higher
1385   //
1386   if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
1387     return Status;
1388   }
1389 
1390   EdidFound            = FALSE;
1391   EdidAttributes       = 0xff;
1392   EdidOverrideDataSize = 0;
1393 
1394   //
1395   // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
1396   //
1397   Status = gBS->LocateProtocol (
1398                    &gEfiEdidOverrideProtocolGuid,
1399                    NULL,
1400                    (VOID **) &EdidOverride
1401                    );
1402   if (!EFI_ERROR (Status)) {
1403     //
1404     // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
1405     //
1406     EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);
1407     if (NULL == EdidOverrideDataBlock) {
1408   		Status = EFI_OUT_OF_RESOURCES;
1409       goto Done;
1410     }
1411 
1412     Status = EdidOverride->GetEdid (
1413                              EdidOverride,
1414                              BiosVideoPrivate->Handle,
1415                              &EdidAttributes,
1416                              &EdidOverrideDataSize,
1417                              (UINT8 **) &EdidOverrideDataBlock
1418                              );
1419     if (!EFI_ERROR (Status)  &&
1420          EdidAttributes == 0 &&
1421          EdidOverrideDataSize != 0) {
1422       //
1423       // Succeeded to get EDID Override Data
1424       //
1425       EdidOverrideFound = TRUE;
1426     }
1427   }
1428 
1429   if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
1430     //
1431     // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
1432     // read EDID information through INT10 call
1433     //
1434 
1435     gBS->SetMem (&Regs, sizeof (Regs), 0);
1436     Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
1437     Regs.X.BX = 1;
1438     Regs.X.CX = 0;
1439     Regs.X.DX = 0;
1440     Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1441     Regs.X.DI = EFI_OFFSET  ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1442 
1443     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1444     //
1445     // See if the VESA call succeeded
1446     //
1447     if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1448       //
1449       // Set EDID Discovered Data
1450       //
1451       BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1452  		  BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
1453                                                           VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
1454                                                           BiosVideoPrivate->VbeEdidDataBlock
1455  																												  );
1456 
1457       if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {
1458  			  Status = EFI_OUT_OF_RESOURCES;
1459         goto Done;
1460       }
1461 
1462       EdidFound = TRUE;
1463     }
1464   }
1465 
1466   if (EdidFound) {
1467     EdidActiveDataSize  = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1468     EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;
1469   } else if (EdidOverrideFound) {
1470     EdidActiveDataSize  = EdidOverrideDataSize;
1471     EdidActiveDataBlock = EdidOverrideDataBlock;
1472     EdidFound = TRUE;
1473  	}
1474 
1475  	if (EdidFound) {
1476     //
1477     // Parse EDID data structure to retrieve modes supported by monitor
1478     //
1479     if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {
1480       //
1481       // Copy EDID Override Data to EDID Active Data
1482       //
1483       BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
1484       BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
1485                                                       EdidActiveDataSize,
1486                                                       EdidActiveDataBlock
1487                                                       );
1488       if (NULL ==  BiosVideoPrivate->EdidActive.Edid) {
1489    		  Status = EFI_OUT_OF_RESOURCES;
1490         goto Done;
1491       }
1492     }
1493   } else {
1494     BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
1495     BiosVideoPrivate->EdidActive.Edid = NULL;
1496     EdidFound = FALSE;
1497   }
1498 
1499   //
1500   // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1501   //
1502   ModeNumberPtr = (UINT16 *)
1503     (
1504       (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
1505         ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
1506     );
1507 
1508   PreferMode = 0;
1509   ModeNumber = 0;
1510 
1511   //
1512   // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
1513   //
1514   for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);
1515        VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;
1516        VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {
1517     //
1518     // Make sure this is a mode number defined by the VESA VBE specification.  If it isn'tm then skip this mode number.
1519     //
1520     if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
1521       continue;
1522     }
1523     //
1524     // Get the information about the mode
1525     //
1526     gBS->SetMem (&Regs, sizeof (Regs), 0);
1527     Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
1528     Regs.X.CX = VbeModeNumber;
1529     gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
1530     Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1531     Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1532 
1533     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1534 
1535     //
1536     // See if the call succeeded.  If it didn't, then try the next mode.
1537     //
1538     if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1539       continue;
1540     }
1541     //
1542     // See if the mode supports color.  If it doesn't then try the next mode.
1543     //
1544     if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
1545       continue;
1546     }
1547     //
1548     // See if the mode supports graphics.  If it doesn't then try the next mode.
1549     //
1550     if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
1551       continue;
1552     }
1553     //
1554     // See if the mode supports a linear frame buffer.  If it doesn't then try the next mode.
1555     //
1556     if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
1557       continue;
1558     }
1559     //
1560     // See if the mode supports 32 bit color.  If it doesn't then try the next mode.
1561     // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1562     // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1563     //
1564     if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
1565       continue;
1566     }
1567 
1568     if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
1569       continue;
1570     }
1571 
1572     if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
1573       continue;
1574     }
1575     //
1576     // See if the physical base pointer for the linear mode is valid.  If it isn't then try the next mode.
1577     //
1578     if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
1579       continue;
1580     }
1581 
1582     DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",
1583             VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));
1584 
1585     if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
1586       //
1587       // EDID exist, check whether this mode match with any mode in EDID
1588       //
1589       Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1590       Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1591       if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {
1592         //
1593         // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
1594         // but INT10 can support these modes, we add them into GOP mode.
1595         //
1596         if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&
1597             !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&
1598             !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&
1599             !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {
1600         continue;
1601         }
1602       }
1603     }
1604 
1605     //
1606     // Select a reasonable mode to be set for current display mode
1607     //
1608     ModeFound = FALSE;
1609 
1610     if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
1611         BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
1612         ) {
1613       ModeFound = TRUE;
1614     }
1615     if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
1616         BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
1617         ) {
1618       ModeFound = TRUE;
1619       PreferMode = ModeNumber;
1620     }
1621     if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
1622         BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
1623         ) {
1624       ModeFound = TRUE;
1625     }
1626 
1627     if ((!EdidFound) && (!ModeFound)) {
1628       //
1629       // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1630       //
1631       continue;
1632     }
1633 
1634     //
1635     // Record the highest resolution mode to set later
1636     //
1637     if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||
1638         ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) &&
1639          (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {
1640       HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1641       HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1642       HighestResolutionMode = ModeNumber;
1643     }
1644 
1645     //
1646     // Add mode to the list of available modes
1647     //
1648     ModeNumber ++;
1649     ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1650 																						ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)
1651 																						);
1652     if (NULL == ModeBuffer) {
1653 			Status = EFI_OUT_OF_RESOURCES;
1654       goto Done;
1655     }
1656 
1657     if (ModeNumber > 1) {
1658       CopyMem (
1659         ModeBuffer,
1660         BiosVideoPrivate->ModeData,
1661         (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
1662         );
1663     }
1664 
1665     if (BiosVideoPrivate->ModeData != NULL) {
1666       FreePool (BiosVideoPrivate->ModeData);
1667     }
1668 
1669     CurrentModeData = &ModeBuffer[ModeNumber - 1];
1670     CurrentModeData->VbeModeNumber = VbeModeNumber;
1671     if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
1672       CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
1673       CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
1674       CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
1675       CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
1676       CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
1677       CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
1678       CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
1679       CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
1680       CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
1681     } else {
1682       CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
1683       CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
1684       CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
1685       CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
1686       CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
1687       CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
1688       CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
1689       CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
1690       CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
1691     }
1692 
1693     CurrentModeData->PixelFormat = PixelBitMask;
1694     if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
1695         (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
1696       if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
1697         CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
1698       } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
1699         CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
1700       }
1701     }
1702 
1703     CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
1704     CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
1705     CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
1706     CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
1707 
1708     CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
1709     CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1710     CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1711 
1712     CurrentModeData->BitsPerPixel  = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1713     CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
1714     //
1715     // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
1716     //
1717     ASSERT (CurrentModeData->FrameBufferSize <= (UINTN)(BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));
1718 
1719     BiosVideoPrivate->ModeData = ModeBuffer;
1720   }
1721   //
1722   // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1723   //
1724   if (ModeNumber == 0) {
1725     Status = EFI_DEVICE_ERROR;
1726     goto Done;
1727   }
1728 
1729   //
1730   // Assign Gop's Blt function
1731   //
1732   BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVbeBlt;
1733 
1734   BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;
1735   //
1736   // Current mode is unknow till now, set it to an invalid mode.
1737   //
1738   BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1739 
1740   //
1741   // Find the best mode to initialize
1742   //
1743   if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {
1744     DEBUG_CODE (
1745       BIOS_VIDEO_MODE_DATA    *ModeData;
1746       ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];
1747       DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",
1748               ModeData->HorizontalResolution, ModeData->VerticalResolution));
1749     );
1750     PreferMode = HighestResolutionMode;
1751   }
1752   Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
1753   if (EFI_ERROR (Status)) {
1754     for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
1755       Status = BiosVideoGraphicsOutputSetMode (
1756                 &BiosVideoPrivate->GraphicsOutput,
1757                 (UINT32) PreferMode
1758                 );
1759       if (!EFI_ERROR (Status)) {
1760         break;
1761       }
1762     }
1763     if (PreferMode == ModeNumber) {
1764       //
1765       // None mode is set successfully.
1766       //
1767       goto Done;
1768     }
1769   }
1770 
1771 Done:
1772   //
1773   // If there was an error, then free the mode structure
1774   //
1775   if (EFI_ERROR (Status)) {
1776     if (BiosVideoPrivate->ModeData != NULL) {
1777       FreePool (BiosVideoPrivate->ModeData);
1778       BiosVideoPrivate->ModeData  = NULL;
1779       BiosVideoPrivate->MaxMode   = 0;
1780     }
1781     if (EdidOverrideDataBlock != NULL) {
1782       FreePool (EdidOverrideDataBlock);
1783     }
1784   }
1785 
1786   return Status;
1787 }
1788 
1789 
1790 /**
1791   Check for VGA device.
1792 
1793   @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure
1794 
1795   @retval EFI_SUCCESS            Standard VGA device found
1796 
1797 **/
1798 EFI_STATUS
BiosVideoCheckForVga(IN OUT BIOS_VIDEO_DEV * BiosVideoPrivate)1799 BiosVideoCheckForVga (
1800   IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate
1801   )
1802 {
1803   EFI_STATUS            Status;
1804   BIOS_VIDEO_MODE_DATA  *ModeBuffer;
1805 
1806   Status = EFI_UNSUPPORTED;
1807 
1808   //
1809   // Assign Gop's Blt function
1810   //
1811   BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVgaBlt;
1812 
1813   //
1814   // Add mode to the list of available modes
1815   // caller should guarantee that Mode has been allocated.
1816   //
1817   ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);
1818   BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
1819 
1820   ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1821                                           sizeof (BIOS_VIDEO_MODE_DATA)
1822                                           );
1823   if (NULL == ModeBuffer) {
1824 		Status = EFI_OUT_OF_RESOURCES;
1825     goto Done;
1826   }
1827 
1828   ModeBuffer->VbeModeNumber         = 0x0012;
1829   ModeBuffer->BytesPerScanLine      = 640;
1830   ModeBuffer->LinearFrameBuffer     = (VOID *) (UINTN) (0xa0000);
1831   ModeBuffer->HorizontalResolution  = 640;
1832   ModeBuffer->VerticalResolution    = 480;
1833   ModeBuffer->PixelFormat           = PixelBltOnly;
1834   ModeBuffer->BitsPerPixel          = 8;
1835   ModeBuffer->ColorDepth            = 32;
1836   ModeBuffer->RefreshRate           = 60;
1837 
1838   BiosVideoPrivate->ModeData = ModeBuffer;
1839 
1840   //
1841   // Test to see if the Video Adapter support the 640x480 16 color mode
1842   //
1843   BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1844   Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
1845 
1846 Done:
1847   //
1848   // If there was an error, then free the mode structure
1849   //
1850   if (EFI_ERROR (Status)) {
1851     if (BiosVideoPrivate->ModeData != NULL) {
1852       FreePool (BiosVideoPrivate->ModeData);
1853       BiosVideoPrivate->ModeData = NULL;
1854     }
1855     if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1856       if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1857         FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1858         BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
1859       }
1860       FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1861       BiosVideoPrivate->GraphicsOutput.Mode = NULL;
1862     }
1863   }
1864   return Status;
1865 }
1866 
1867 //
1868 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1869 //
1870 
1871 /**
1872   Graphics Output protocol interface to get video mode.
1873 
1874   @param  This                   Protocol instance pointer.
1875   @param  ModeNumber             The mode number to return information on.
1876   @param  SizeOfInfo             A pointer to the size, in bytes, of the Info
1877                                  buffer.
1878   @param  Info                   Caller allocated buffer that returns information
1879                                  about ModeNumber.
1880 
1881   @retval EFI_SUCCESS            Mode information returned.
1882   @retval EFI_DEVICE_ERROR       A hardware error occurred trying to retrieve the
1883                                  video mode.
1884   @retval EFI_NOT_STARTED        Video display is not initialized. Call SetMode ()
1885   @retval EFI_INVALID_PARAMETER  One of the input args was NULL.
1886 
1887 **/
1888 EFI_STATUS
1889 EFIAPI
BiosVideoGraphicsOutputQueryMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)1890 BiosVideoGraphicsOutputQueryMode (
1891   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
1892   IN  UINT32                                ModeNumber,
1893   OUT UINTN                                 *SizeOfInfo,
1894   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
1895   )
1896 {
1897   BIOS_VIDEO_DEV        *BiosVideoPrivate;
1898   BIOS_VIDEO_MODE_DATA  *ModeData;
1899 
1900   BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1901 
1902   if (BiosVideoPrivate->HardwareNeedsStarting) {
1903     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1904       EFI_ERROR_CODE | EFI_ERROR_MINOR,
1905       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
1906       BiosVideoPrivate->GopDevicePath
1907       );
1908     return EFI_NOT_STARTED;
1909   }
1910 
1911   if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
1912     return EFI_INVALID_PARAMETER;
1913   }
1914 
1915   *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
1916 																										sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
1917 																										);
1918   if (NULL == *Info) {
1919     return EFI_OUT_OF_RESOURCES;
1920   }
1921 
1922   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1923 
1924   ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
1925   (*Info)->Version = 0;
1926   (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
1927   (*Info)->VerticalResolution   = ModeData->VerticalResolution;
1928   (*Info)->PixelFormat = ModeData->PixelFormat;
1929   CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
1930 
1931   (*Info)->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
1932 
1933   return EFI_SUCCESS;
1934 }
1935 
1936 /**
1937   Worker function to set video mode.
1938 
1939   @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV.
1940   @param  ModeData               The mode data to be set.
1941   @param  DevicePath             Pointer to Device Path Protocol.
1942 
1943   @retval EFI_SUCCESS            Graphics mode was changed.
1944   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the
1945                                  request.
1946   @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.
1947 
1948 **/
1949 EFI_STATUS
BiosVideoSetModeWorker(IN BIOS_VIDEO_DEV * BiosVideoPrivate,IN BIOS_VIDEO_MODE_DATA * ModeData,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)1950 BiosVideoSetModeWorker (
1951   IN  BIOS_VIDEO_DEV               *BiosVideoPrivate,
1952   IN  BIOS_VIDEO_MODE_DATA         *ModeData,
1953   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
1954   )
1955 {
1956   EFI_STATUS              Status;
1957   EFI_IA32_REGISTER_SET   Regs;
1958 
1959   if (BiosVideoPrivate->LineBuffer != NULL) {
1960     FreePool (BiosVideoPrivate->LineBuffer);
1961   }
1962 
1963   if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
1964     FreePool (BiosVideoPrivate->VgaFrameBuffer);
1965   }
1966 
1967   if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
1968     FreePool (BiosVideoPrivate->VbeFrameBuffer);
1969   }
1970 
1971   BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (
1972 																					   ModeData->BytesPerScanLine
1973 																					   );
1974   if (NULL == BiosVideoPrivate->LineBuffer) {
1975     return EFI_OUT_OF_RESOURCES;
1976   }
1977   //
1978   // Clear all registers
1979   //
1980   ZeroMem (&Regs, sizeof (Regs));
1981 
1982   if (ModeData->VbeModeNumber < 0x100) {
1983     //
1984     // Allocate a working buffer for BLT operations to the VGA frame buffer
1985     //
1986     BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);
1987     if (NULL == BiosVideoPrivate->VgaFrameBuffer) {
1988       return EFI_OUT_OF_RESOURCES;
1989     }
1990     //
1991     // Set VGA Mode
1992     //
1993     Regs.X.AX = ModeData->VbeModeNumber;
1994     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1995 
1996   } else {
1997     //
1998     // Allocate a working buffer for BLT operations to the VBE frame buffer
1999     //
2000     BiosVideoPrivate->VbeFrameBuffer =
2001 			(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
2002 																					ModeData->BytesPerScanLine * ModeData->VerticalResolution
2003 																				  );
2004     if (NULL == BiosVideoPrivate->VbeFrameBuffer) {
2005       return EFI_OUT_OF_RESOURCES;
2006     }
2007     //
2008     // Set VBE mode
2009     //
2010     Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
2011     Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
2012     ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));
2013     Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2014     Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2015     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
2016 
2017     //
2018     // Check to see if the call succeeded
2019     //
2020     if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
2021       REPORT_STATUS_CODE_WITH_DEVICE_PATH (
2022         EFI_ERROR_CODE | EFI_ERROR_MINOR,
2023         EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
2024         DevicePath
2025         );
2026       return EFI_DEVICE_ERROR;
2027     }
2028     //
2029     // Initialize the state of the VbeFrameBuffer
2030     //
2031     Status = BiosVideoPrivate->PciIo->Mem.Read (
2032                                             BiosVideoPrivate->PciIo,
2033                                             EfiPciIoWidthUint32,
2034                                             EFI_PCI_IO_PASS_THROUGH_BAR,
2035                                             (UINT64) (UINTN) ModeData->LinearFrameBuffer,
2036                                             (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
2037                                             BiosVideoPrivate->VbeFrameBuffer
2038                                             );
2039     if (EFI_ERROR (Status)) {
2040       return Status;
2041     }
2042   }
2043 
2044   return EFI_SUCCESS;
2045 }
2046 
2047 /**
2048   Graphics Output protocol interface to set video mode.
2049 
2050   @param  This                   Protocol instance pointer.
2051   @param  ModeNumber             The mode number to be set.
2052 
2053   @retval EFI_SUCCESS            Graphics mode was changed.
2054   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the
2055                                  request.
2056   @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.
2057 
2058 **/
2059 EFI_STATUS
2060 EFIAPI
BiosVideoGraphicsOutputSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)2061 BiosVideoGraphicsOutputSetMode (
2062   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
2063   IN  UINT32                       ModeNumber
2064   )
2065 {
2066   EFI_STATUS              Status;
2067   BIOS_VIDEO_DEV          *BiosVideoPrivate;
2068   BIOS_VIDEO_MODE_DATA    *ModeData;
2069   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
2070 
2071   if (This == NULL) {
2072     return EFI_INVALID_PARAMETER;
2073   }
2074 
2075   BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2076 
2077   ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
2078 
2079   if (ModeNumber >= This->Mode->MaxMode) {
2080     return EFI_UNSUPPORTED;
2081   }
2082 
2083   if (ModeNumber == This->Mode->Mode) {
2084     //
2085     // Clear screen to black
2086     //
2087     ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2088     BiosVideoGraphicsOutputVbeBlt (
2089                         This,
2090                         &Background,
2091                         EfiBltVideoFill,
2092                         0,
2093                         0,
2094                         0,
2095                         0,
2096                         ModeData->HorizontalResolution,
2097                         ModeData->VerticalResolution,
2098                         0
2099     );
2100     return EFI_SUCCESS;
2101   }
2102 
2103   Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);
2104   if (EFI_ERROR (Status)) {
2105     return Status;
2106   }
2107 
2108   This->Mode->Mode = ModeNumber;
2109   This->Mode->Info->Version = 0;
2110   This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
2111   This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
2112   This->Mode->Info->PixelFormat = ModeData->PixelFormat;
2113   CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));
2114   This->Mode->Info->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
2115   This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
2116   This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
2117   This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;
2118 
2119   BiosVideoPrivate->HardwareNeedsStarting = FALSE;
2120 
2121   return EFI_SUCCESS;
2122 }
2123 
2124 /**
2125   Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
2126 
2127   @param   PciIo              The pointer of EFI_PCI_IO_PROTOCOL
2128   @param   VbeBuffer          The data to transfer to screen
2129   @param   MemAddress         Physical frame buffer base address
2130   @param   DestinationX       The X coordinate of the destination for BltOperation
2131   @param   DestinationY       The Y coordinate of the destination for BltOperation
2132   @param   TotalBytes         The total bytes of copy
2133   @param   VbePixelWidth      Bytes per pixel
2134   @param   BytesPerScanLine   Bytes per scan line
2135 
2136 **/
2137 VOID
CopyVideoBuffer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 * VbeBuffer,IN VOID * MemAddress,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN TotalBytes,IN UINT32 VbePixelWidth,IN UINTN BytesPerScanLine)2138 CopyVideoBuffer (
2139   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
2140   IN  UINT8                 *VbeBuffer,
2141   IN  VOID                  *MemAddress,
2142   IN  UINTN                 DestinationX,
2143   IN  UINTN                 DestinationY,
2144   IN  UINTN                 TotalBytes,
2145   IN  UINT32                VbePixelWidth,
2146   IN  UINTN                 BytesPerScanLine
2147   )
2148 {
2149   UINTN                 FrameBufferAddr;
2150   UINTN                 CopyBlockNum;
2151   UINTN                 RemainingBytes;
2152   UINTN                 UnalignedBytes;
2153   EFI_STATUS            Status;
2154 
2155   FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
2156 
2157   //
2158   // If TotalBytes is less than 4 bytes, only start byte copy.
2159   //
2160   if (TotalBytes < 4) {
2161     Status = PciIo->Mem.Write (
2162                      PciIo,
2163                      EfiPciIoWidthUint8,
2164                      EFI_PCI_IO_PASS_THROUGH_BAR,
2165                      (UINT64) FrameBufferAddr,
2166                      TotalBytes,
2167                      VbeBuffer
2168                      );
2169     ASSERT_EFI_ERROR (Status);
2170     return;
2171   }
2172 
2173   //
2174   // If VbeBuffer is not 4-byte aligned, start byte copy.
2175   //
2176   UnalignedBytes  = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
2177 
2178   if (UnalignedBytes != 0) {
2179     Status = PciIo->Mem.Write (
2180                      PciIo,
2181                      EfiPciIoWidthUint8,
2182                      EFI_PCI_IO_PASS_THROUGH_BAR,
2183                      (UINT64) FrameBufferAddr,
2184                      UnalignedBytes,
2185                      VbeBuffer
2186                      );
2187     ASSERT_EFI_ERROR (Status);
2188     FrameBufferAddr += UnalignedBytes;
2189     VbeBuffer       += UnalignedBytes;
2190   }
2191 
2192   //
2193   // Calculate 4-byte block count and remaining bytes.
2194   //
2195   CopyBlockNum   = (TotalBytes - UnalignedBytes) >> 2;
2196   RemainingBytes = (TotalBytes - UnalignedBytes) &  3;
2197 
2198   //
2199   // Copy 4-byte block and remaining bytes to physical frame buffer.
2200   //
2201   if (CopyBlockNum != 0) {
2202     Status = PciIo->Mem.Write (
2203                     PciIo,
2204                     EfiPciIoWidthUint32,
2205                     EFI_PCI_IO_PASS_THROUGH_BAR,
2206                     (UINT64) FrameBufferAddr,
2207                     CopyBlockNum,
2208                     VbeBuffer
2209                     );
2210     ASSERT_EFI_ERROR (Status);
2211   }
2212 
2213   if (RemainingBytes != 0) {
2214     FrameBufferAddr += (CopyBlockNum << 2);
2215     VbeBuffer       += (CopyBlockNum << 2);
2216     Status = PciIo->Mem.Write (
2217                     PciIo,
2218                     EfiPciIoWidthUint8,
2219                     EFI_PCI_IO_PASS_THROUGH_BAR,
2220                     (UINT64) FrameBufferAddr,
2221                     RemainingBytes,
2222                     VbeBuffer
2223                     );
2224     ASSERT_EFI_ERROR (Status);
2225   }
2226 }
2227 
2228 /**
2229   Worker function to block transfer for VBE device.
2230 
2231   @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV
2232   @param  BltBuffer              The data to transfer to screen
2233   @param  BltOperation           The operation to perform
2234   @param  SourceX                The X coordinate of the source for BltOperation
2235   @param  SourceY                The Y coordinate of the source for BltOperation
2236   @param  DestinationX           The X coordinate of the destination for
2237                                  BltOperation
2238   @param  DestinationY           The Y coordinate of the destination for
2239                                  BltOperation
2240   @param  Width                  The width of a rectangle in the blt rectangle in
2241                                  pixels
2242   @param  Height                 The height of a rectangle in the blt rectangle in
2243                                  pixels
2244   @param  Delta                  Not used for EfiBltVideoFill and
2245                                  EfiBltVideoToVideo operation. If a Delta of 0 is
2246                                  used, the entire BltBuffer will be operated on. If
2247                                  a subrectangle of the BltBuffer is used, then
2248                                  Delta represents the number of bytes in a row of
2249                                  the BltBuffer.
2250   @param  Mode                   Mode data.
2251 
2252   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
2253   @retval EFI_SUCCESS            Blt operation success
2254 
2255 **/
2256 EFI_STATUS
BiosVideoVbeBltWorker(IN BIOS_VIDEO_DEV * BiosVideoPrivate,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta,IN BIOS_VIDEO_MODE_DATA * Mode)2257 BiosVideoVbeBltWorker (
2258   IN  BIOS_VIDEO_DEV                     *BiosVideoPrivate,
2259   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
2260   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
2261   IN  UINTN                              SourceX,
2262   IN  UINTN                              SourceY,
2263   IN  UINTN                              DestinationX,
2264   IN  UINTN                              DestinationY,
2265   IN  UINTN                              Width,
2266   IN  UINTN                              Height,
2267   IN  UINTN                              Delta,
2268   IN  BIOS_VIDEO_MODE_DATA               *Mode
2269   )
2270 {
2271   EFI_PCI_IO_PROTOCOL            *PciIo;
2272   EFI_TPL                        OriginalTPL;
2273   UINTN                          DstY;
2274   UINTN                          SrcY;
2275   UINTN                          DstX;
2276   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *Blt;
2277   VOID                           *MemAddress;
2278   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *VbeFrameBuffer;
2279   UINTN                          BytesPerScanLine;
2280   UINTN                          Index;
2281   UINT8                          *VbeBuffer;
2282   UINT8                          *VbeBuffer1;
2283   UINT8                          *BltUint8;
2284   UINT32                         VbePixelWidth;
2285   UINT32                         Pixel;
2286   UINTN                          TotalBytes;
2287 
2288   PciIo             = BiosVideoPrivate->PciIo;
2289 
2290   VbeFrameBuffer    = BiosVideoPrivate->VbeFrameBuffer;
2291   MemAddress        = Mode->LinearFrameBuffer;
2292   BytesPerScanLine  = Mode->BytesPerScanLine;
2293   VbePixelWidth     = Mode->BitsPerPixel / 8;
2294   BltUint8          = (UINT8 *) BltBuffer;
2295   TotalBytes        = Width * VbePixelWidth;
2296 
2297   if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2298     return EFI_INVALID_PARAMETER;
2299   }
2300 
2301   if (Width == 0 || Height == 0) {
2302     return EFI_INVALID_PARAMETER;
2303   }
2304   //
2305   // We need to fill the Virtual Screen buffer with the blt data.
2306   // The virtual screen is upside down, as the first row is the bootom row of
2307   // the image.
2308   //
2309   if (BltOperation == EfiBltVideoToBltBuffer) {
2310     //
2311     // Video to BltBuffer: Source is Video, destination is BltBuffer
2312     //
2313     if (SourceY + Height > Mode->VerticalResolution) {
2314       return EFI_INVALID_PARAMETER;
2315     }
2316 
2317     if (SourceX + Width > Mode->HorizontalResolution) {
2318       return EFI_INVALID_PARAMETER;
2319     }
2320   } else {
2321     //
2322     // BltBuffer to Video: Source is BltBuffer, destination is Video
2323     //
2324     if (DestinationY + Height > Mode->VerticalResolution) {
2325       return EFI_INVALID_PARAMETER;
2326     }
2327 
2328     if (DestinationX + Width > Mode->HorizontalResolution) {
2329       return EFI_INVALID_PARAMETER;
2330     }
2331   }
2332   //
2333   // If Delta is zero, then the entire BltBuffer is being used, so Delta
2334   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
2335   // the number of bytes in each row can be computed.
2336   //
2337   if (Delta == 0) {
2338     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2339   }
2340   //
2341   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2342   // We would not want a timer based event (Cursor, ...) to come in while we are
2343   // doing this operation.
2344   //
2345   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2346 
2347   switch (BltOperation) {
2348   case EfiBltVideoToBltBuffer:
2349     for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
2350       Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2351       //
2352       // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2353       //
2354       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
2355       for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2356         Pixel         = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
2357         Blt->Red      = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
2358         Blt->Blue     = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
2359         Blt->Green    = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
2360         Blt->Reserved = 0;
2361         Blt++;
2362         VbeBuffer += VbePixelWidth;
2363       }
2364 
2365     }
2366     break;
2367 
2368   case EfiBltVideoToVideo:
2369     for (Index = 0; Index < Height; Index++) {
2370       if (DestinationY <= SourceY) {
2371         SrcY  = SourceY + Index;
2372         DstY  = DestinationY + Index;
2373       } else {
2374         SrcY  = SourceY + Height - Index - 1;
2375         DstY  = DestinationY + Height - Index - 1;
2376       }
2377 
2378       VbeBuffer   = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
2379       VbeBuffer1  = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
2380 
2381       gBS->CopyMem (
2382             VbeBuffer,
2383             VbeBuffer1,
2384             TotalBytes
2385             );
2386 
2387       //
2388       // Update physical frame buffer.
2389       //
2390       CopyVideoBuffer (
2391         PciIo,
2392         VbeBuffer,
2393         MemAddress,
2394         DestinationX,
2395         DstY,
2396         TotalBytes,
2397         VbePixelWidth,
2398         BytesPerScanLine
2399         );
2400     }
2401     break;
2402 
2403   case EfiBltVideoFill:
2404     VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2405     Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
2406     //
2407     // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2408     //
2409     Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2410       (
2411         (Blt->Green & Mode->Green.Mask) <<
2412         Mode->Green.Position
2413       ) |
2414           ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2415 
2416     for (Index = 0; Index < Width; Index++) {
2417       gBS->CopyMem (
2418             VbeBuffer,
2419             &Pixel,
2420             VbePixelWidth
2421             );
2422       VbeBuffer += VbePixelWidth;
2423     }
2424 
2425     VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2426     for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
2427       gBS->CopyMem (
2428             (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
2429             VbeBuffer,
2430             TotalBytes
2431             );
2432     }
2433 
2434     for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
2435       //
2436       // Update physical frame buffer.
2437       //
2438       CopyVideoBuffer (
2439         PciIo,
2440         VbeBuffer,
2441         MemAddress,
2442         DestinationX,
2443         DstY,
2444         TotalBytes,
2445         VbePixelWidth,
2446         BytesPerScanLine
2447         );
2448     }
2449     break;
2450 
2451   case EfiBltBufferToVideo:
2452     for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
2453       Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2454       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2455       for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2456         //
2457         // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2458         //
2459         Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2460           ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
2461             ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2462         gBS->CopyMem (
2463               VbeBuffer,
2464               &Pixel,
2465               VbePixelWidth
2466               );
2467         Blt++;
2468         VbeBuffer += VbePixelWidth;
2469       }
2470 
2471       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2472 
2473       //
2474       // Update physical frame buffer.
2475       //
2476       CopyVideoBuffer (
2477         PciIo,
2478         VbeBuffer,
2479         MemAddress,
2480         DestinationX,
2481         DstY,
2482         TotalBytes,
2483         VbePixelWidth,
2484         BytesPerScanLine
2485         );
2486     }
2487     break;
2488 
2489     default: ;
2490   }
2491 
2492   gBS->RestoreTPL (OriginalTPL);
2493 
2494   return EFI_SUCCESS;
2495 }
2496 
2497 /**
2498   Graphics Output protocol instance to block transfer for VBE device.
2499 
2500   @param  This                   Pointer to Graphics Output protocol instance
2501   @param  BltBuffer              The data to transfer to screen
2502   @param  BltOperation           The operation to perform
2503   @param  SourceX                The X coordinate of the source for BltOperation
2504   @param  SourceY                The Y coordinate of the source for BltOperation
2505   @param  DestinationX           The X coordinate of the destination for
2506                                  BltOperation
2507   @param  DestinationY           The Y coordinate of the destination for
2508                                  BltOperation
2509   @param  Width                  The width of a rectangle in the blt rectangle in
2510                                  pixels
2511   @param  Height                 The height of a rectangle in the blt rectangle in
2512                                  pixels
2513   @param  Delta                  Not used for EfiBltVideoFill and
2514                                  EfiBltVideoToVideo operation. If a Delta of 0 is
2515                                  used, the entire BltBuffer will be operated on. If
2516                                  a subrectangle of the BltBuffer is used, then
2517                                  Delta represents the number of bytes in a row of
2518                                  the BltBuffer.
2519 
2520   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
2521   @retval EFI_SUCCESS            Blt operation success
2522 
2523 **/
2524 EFI_STATUS
2525 EFIAPI
BiosVideoGraphicsOutputVbeBlt(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta)2526 BiosVideoGraphicsOutputVbeBlt (
2527   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,
2528   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
2529   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
2530   IN  UINTN                              SourceX,
2531   IN  UINTN                              SourceY,
2532   IN  UINTN                              DestinationX,
2533   IN  UINTN                              DestinationY,
2534   IN  UINTN                              Width,
2535   IN  UINTN                              Height,
2536   IN  UINTN                              Delta
2537   )
2538 {
2539   BIOS_VIDEO_DEV                 *BiosVideoPrivate;
2540   BIOS_VIDEO_MODE_DATA           *Mode;
2541 
2542   if (This == NULL) {
2543     return EFI_INVALID_PARAMETER;
2544   }
2545 
2546   BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2547   Mode              = &BiosVideoPrivate->ModeData[This->Mode->Mode];
2548 
2549   return BiosVideoVbeBltWorker (
2550            BiosVideoPrivate,
2551            BltBuffer,
2552            BltOperation,
2553            SourceX,
2554            SourceY,
2555            DestinationX,
2556            DestinationY,
2557            Width,
2558            Height,
2559            Delta,
2560            Mode
2561            );
2562 }
2563 
2564 /**
2565   Write graphics controller registers.
2566 
2567   @param  PciIo                  Pointer to PciIo protocol instance of the
2568                                  controller
2569   @param  Address                Register address
2570   @param  Data                   Data to be written to register
2571 
2572   @return None
2573 
2574 **/
2575 VOID
WriteGraphicsController(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINTN Address,IN UINTN Data)2576 WriteGraphicsController (
2577   IN  EFI_PCI_IO_PROTOCOL  *PciIo,
2578   IN  UINTN                Address,
2579   IN  UINTN                Data
2580   )
2581 {
2582   Address = Address | (Data << 8);
2583   PciIo->Io.Write (
2584               PciIo,
2585               EfiPciIoWidthUint16,
2586               EFI_PCI_IO_PASS_THROUGH_BAR,
2587               VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
2588               1,
2589               &Address
2590               );
2591 }
2592 
2593 
2594 /**
2595   Read the four bit plane of VGA frame buffer.
2596 
2597   @param  PciIo                  Pointer to PciIo protocol instance of the
2598                                  controller
2599   @param  HardwareBuffer         Hardware VGA frame buffer address
2600   @param  MemoryBuffer           Memory buffer address
2601   @param  WidthInBytes           Number of bytes in a line to read
2602   @param  Height                 Height of the area to read
2603 
2604   @return None
2605 
2606 **/
2607 VOID
VgaReadBitPlanes(EFI_PCI_IO_PROTOCOL * PciIo,UINT8 * HardwareBuffer,UINT8 * MemoryBuffer,UINTN WidthInBytes,UINTN Height)2608 VgaReadBitPlanes (
2609   EFI_PCI_IO_PROTOCOL  *PciIo,
2610   UINT8                *HardwareBuffer,
2611   UINT8                *MemoryBuffer,
2612   UINTN                WidthInBytes,
2613   UINTN                Height
2614   )
2615 {
2616   UINTN BitPlane;
2617   UINTN Rows;
2618   UINTN FrameBufferOffset;
2619   UINT8 *Source;
2620   UINT8 *Destination;
2621 
2622   //
2623   // Program the Mode Register Write mode 0, Read mode 0
2624   //
2625   WriteGraphicsController (
2626     PciIo,
2627     VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2628     VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2629     );
2630 
2631   for (BitPlane = 0, FrameBufferOffset = 0;
2632        BitPlane < VGA_NUMBER_OF_BIT_PLANES;
2633        BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
2634       ) {
2635     //
2636     // Program the Read Map Select Register to select the correct bit plane
2637     //
2638     WriteGraphicsController (
2639       PciIo,
2640       VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
2641       BitPlane
2642       );
2643 
2644     Source      = HardwareBuffer;
2645     Destination = MemoryBuffer + FrameBufferOffset;
2646 
2647     for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
2648       PciIo->Mem.Read (
2649                   PciIo,
2650                   EfiPciIoWidthUint8,
2651                   EFI_PCI_IO_PASS_THROUGH_BAR,
2652                   (UINT64) (UINTN) Source,
2653                   WidthInBytes,
2654                   (VOID *) Destination
2655                   );
2656     }
2657   }
2658 }
2659 
2660 
2661 /**
2662   Internal routine to convert VGA color to Grahpics Output color.
2663 
2664   @param  MemoryBuffer           Buffer containing VGA color
2665   @param  CoordinateX            The X coordinate of pixel on screen
2666   @param  CoordinateY            The Y coordinate of pixel on screen
2667   @param  BltBuffer              Buffer to contain converted Grahpics Output color
2668 
2669   @return None
2670 
2671 **/
2672 VOID
VgaConvertToGraphicsOutputColor(UINT8 * MemoryBuffer,UINTN CoordinateX,UINTN CoordinateY,EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer)2673 VgaConvertToGraphicsOutputColor (
2674   UINT8                          *MemoryBuffer,
2675   UINTN                          CoordinateX,
2676   UINTN                          CoordinateY,
2677   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *BltBuffer
2678   )
2679 {
2680   UINTN Mask;
2681   UINTN Bit;
2682   UINTN Color;
2683 
2684   MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));
2685   Mask = mVgaBitMaskTable[CoordinateX & 0x07];
2686   for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
2687     if ((*MemoryBuffer & Mask) != 0) {
2688       Color |= Bit;
2689     }
2690   }
2691 
2692   *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
2693 }
2694 
2695 /**
2696   Internal routine to convert Grahpics Output color to VGA color.
2697 
2698   @param  BltBuffer              buffer containing Grahpics Output color
2699 
2700   @return Converted VGA color
2701 
2702 **/
2703 UINT8
VgaConvertColor(IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer)2704 VgaConvertColor (
2705   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL          *BltBuffer
2706   )
2707 {
2708   UINT8 Color;
2709 
2710   Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
2711   if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
2712     Color |= 0x08;
2713   }
2714 
2715   return Color;
2716 }
2717 
2718 
2719 /**
2720   Grahpics Output protocol instance to block transfer for VGA device.
2721 
2722   @param  This                   Pointer to Grahpics Output protocol instance
2723   @param  BltBuffer              The data to transfer to screen
2724   @param  BltOperation           The operation to perform
2725   @param  SourceX                The X coordinate of the source for BltOperation
2726   @param  SourceY                The Y coordinate of the source for BltOperation
2727   @param  DestinationX           The X coordinate of the destination for
2728                                  BltOperation
2729   @param  DestinationY           The Y coordinate of the destination for
2730                                  BltOperation
2731   @param  Width                  The width of a rectangle in the blt rectangle in
2732                                  pixels
2733   @param  Height                 The height of a rectangle in the blt rectangle in
2734                                  pixels
2735   @param  Delta                  Not used for EfiBltVideoFill and
2736                                  EfiBltVideoToVideo operation. If a Delta of 0 is
2737                                  used, the entire BltBuffer will be operated on. If
2738                                  a subrectangle of the BltBuffer is used, then
2739                                  Delta represents the number of bytes in a row of
2740                                  the BltBuffer.
2741 
2742   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
2743   @retval EFI_SUCCESS            Blt operation success
2744 
2745 **/
2746 EFI_STATUS
2747 EFIAPI
BiosVideoGraphicsOutputVgaBlt(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta)2748 BiosVideoGraphicsOutputVgaBlt (
2749   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,
2750   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
2751   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
2752   IN  UINTN                              SourceX,
2753   IN  UINTN                              SourceY,
2754   IN  UINTN                              DestinationX,
2755   IN  UINTN                              DestinationY,
2756   IN  UINTN                              Width,
2757   IN  UINTN                              Height,
2758   IN  UINTN                              Delta
2759   )
2760 {
2761   BIOS_VIDEO_DEV      *BiosVideoPrivate;
2762   EFI_TPL             OriginalTPL;
2763   UINT8               *MemAddress;
2764   UINTN               BytesPerScanLine;
2765   UINTN               Bit;
2766   UINTN               Index;
2767   UINTN               Index1;
2768   UINTN               StartAddress;
2769   UINTN               Bytes;
2770   UINTN               Offset;
2771   UINT8               LeftMask;
2772   UINT8               RightMask;
2773   UINTN               Address;
2774   UINTN               AddressFix;
2775   UINT8               *Address1;
2776   UINT8               *SourceAddress;
2777   UINT8               *DestinationAddress;
2778   EFI_PCI_IO_PROTOCOL *PciIo;
2779   UINT8               Data;
2780   UINT8               PixelColor;
2781   UINT8               *VgaFrameBuffer;
2782   UINTN               SourceOffset;
2783   UINTN               SourceWidth;
2784   UINTN               Rows;
2785   UINTN               Columns;
2786   UINTN               CoordinateX;
2787   UINTN               CoordinateY;
2788   UINTN               CurrentMode;
2789 
2790   if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2791     return EFI_INVALID_PARAMETER;
2792   }
2793 
2794   BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2795 
2796   CurrentMode = This->Mode->Mode;
2797   PciIo             = BiosVideoPrivate->PciIo;
2798   MemAddress        = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
2799   BytesPerScanLine  = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
2800   VgaFrameBuffer    = BiosVideoPrivate->VgaFrameBuffer;
2801 
2802 
2803   if (Width == 0 || Height == 0) {
2804     return EFI_INVALID_PARAMETER;
2805   }
2806   //
2807   // We need to fill the Virtual Screen buffer with the blt data.
2808   // The virtual screen is upside down, as the first row is the bootom row of
2809   // the image.
2810   //
2811   if (BltOperation == EfiBltVideoToBltBuffer) {
2812     //
2813     // Video to BltBuffer: Source is Video, destination is BltBuffer
2814     //
2815     if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2816       return EFI_INVALID_PARAMETER;
2817     }
2818 
2819     if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2820       return EFI_INVALID_PARAMETER;
2821     }
2822   } else {
2823     //
2824     // BltBuffer to Video: Source is BltBuffer, destination is Video
2825     //
2826     if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2827       return EFI_INVALID_PARAMETER;
2828     }
2829 
2830     if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2831       return EFI_INVALID_PARAMETER;
2832     }
2833   }
2834   //
2835   // If Delta is zero, then the entire BltBuffer is being used, so Delta
2836   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
2837   // the number of bytes in each row can be computed.
2838   //
2839   if (Delta == 0) {
2840     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2841   }
2842   //
2843   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2844   // We would not want a timer based event (Cursor, ...) to come in while we are
2845   // doing this operation.
2846   //
2847   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2848 
2849   //
2850   // Compute some values we need for VGA
2851   //
2852   switch (BltOperation) {
2853   case EfiBltVideoToBltBuffer:
2854 
2855     SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2856     SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2857 
2858     //
2859     // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2860     //
2861     VgaReadBitPlanes (
2862       PciIo,
2863       MemAddress + SourceOffset,
2864       VgaFrameBuffer + SourceOffset,
2865       SourceWidth,
2866       Height
2867       );
2868 
2869     //
2870     // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2871     //
2872     BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2873     for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {
2874       for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {
2875         VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);
2876       }
2877 
2878       BltBuffer -= Width;
2879     }
2880 
2881     break;
2882 
2883   case EfiBltVideoToVideo:
2884     //
2885     // Check for an aligned Video to Video operation
2886     //
2887     if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2888       //
2889       // Program the Mode Register Write mode 1, Read mode 0
2890       //
2891       WriteGraphicsController (
2892         PciIo,
2893         VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2894         VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2895         );
2896 
2897       SourceAddress       = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2898       DestinationAddress  = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2899       Bytes               = Width >> 3;
2900       for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2901         PciIo->CopyMem (
2902                 PciIo,
2903                 EfiPciIoWidthUint8,
2904                 EFI_PCI_IO_PASS_THROUGH_BAR,
2905                 (UINT64) (UINTN) (DestinationAddress + Offset),
2906                 EFI_PCI_IO_PASS_THROUGH_BAR,
2907                 (UINT64) (UINTN) (SourceAddress + Offset),
2908                 Bytes
2909                 );
2910       }
2911     } else {
2912       SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2913       SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2914 
2915       //
2916       // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2917       //
2918       VgaReadBitPlanes (
2919         PciIo,
2920         MemAddress + SourceOffset,
2921         VgaFrameBuffer + SourceOffset,
2922         SourceWidth,
2923         Height
2924         );
2925     }
2926 
2927     break;
2928 
2929   case EfiBltVideoFill:
2930     StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2931     Bytes         = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2932     LeftMask      = mVgaLeftMaskTable[DestinationX & 0x07];
2933     RightMask     = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2934     if (Bytes == 0) {
2935       LeftMask = (UINT8) (LeftMask & RightMask);
2936       RightMask = 0;
2937     }
2938 
2939     if (LeftMask == 0xff) {
2940       StartAddress--;
2941       Bytes++;
2942       LeftMask = 0;
2943     }
2944 
2945     if (RightMask == 0xff) {
2946       Bytes++;
2947       RightMask = 0;
2948     }
2949 
2950     PixelColor = VgaConvertColor (BltBuffer);
2951 
2952     //
2953     // Program the Mode Register Write mode 2, Read mode 0
2954     //
2955     WriteGraphicsController (
2956       PciIo,
2957       VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2958       VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2959       );
2960 
2961     //
2962     // Program the Data Rotate/Function Select Register to replace
2963     //
2964     WriteGraphicsController (
2965       PciIo,
2966       VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2967       VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2968       );
2969 
2970     if (LeftMask != 0) {
2971       //
2972       // Program the BitMask register with the Left column mask
2973       //
2974       WriteGraphicsController (
2975         PciIo,
2976         VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2977         LeftMask
2978         );
2979 
2980       for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2981         //
2982         // Read data from the bit planes into the latches
2983         //
2984         PciIo->Mem.Read (
2985                     PciIo,
2986                     EfiPciIoWidthUint8,
2987                     EFI_PCI_IO_PASS_THROUGH_BAR,
2988                     (UINT64) (UINTN) Address,
2989                     1,
2990                     &Data
2991                     );
2992         //
2993         // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2994         //
2995         PciIo->Mem.Write (
2996                     PciIo,
2997                     EfiPciIoWidthUint8,
2998                     EFI_PCI_IO_PASS_THROUGH_BAR,
2999                     (UINT64) (UINTN) Address,
3000                     1,
3001                     &PixelColor
3002                     );
3003       }
3004     }
3005 
3006     if (Bytes > 1) {
3007       //
3008       // Program the BitMask register with the middle column mask of 0xff
3009       //
3010       WriteGraphicsController (
3011         PciIo,
3012         VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3013         0xff
3014         );
3015 
3016       for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
3017         PciIo->Mem.Write (
3018                     PciIo,
3019                     EfiPciIoWidthFillUint8,
3020                     EFI_PCI_IO_PASS_THROUGH_BAR,
3021                     (UINT64) (UINTN) Address,
3022                     Bytes - 1,
3023                     &PixelColor
3024                     );
3025       }
3026     }
3027 
3028     if (RightMask != 0) {
3029       //
3030       // Program the BitMask register with the Right column mask
3031       //
3032       WriteGraphicsController (
3033         PciIo,
3034         VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3035         RightMask
3036         );
3037 
3038       for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
3039         //
3040         // Read data from the bit planes into the latches
3041         //
3042         PciIo->Mem.Read (
3043                     PciIo,
3044                     EfiPciIoWidthUint8,
3045                     EFI_PCI_IO_PASS_THROUGH_BAR,
3046                     (UINT64) (UINTN) Address,
3047                     1,
3048                     &Data
3049                     );
3050         //
3051         // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3052         //
3053         PciIo->Mem.Write (
3054                     PciIo,
3055                     EfiPciIoWidthUint8,
3056                     EFI_PCI_IO_PASS_THROUGH_BAR,
3057                     (UINT64) (UINTN) Address,
3058                     1,
3059                     &PixelColor
3060                     );
3061       }
3062     }
3063     break;
3064 
3065   case EfiBltBufferToVideo:
3066     StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
3067     LeftMask      = mVgaBitMaskTable[DestinationX & 0x07];
3068 
3069     //
3070     // Program the Mode Register Write mode 2, Read mode 0
3071     //
3072     WriteGraphicsController (
3073       PciIo,
3074       VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
3075       VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3076       );
3077 
3078     //
3079     // Program the Data Rotate/Function Select Register to replace
3080     //
3081     WriteGraphicsController (
3082       PciIo,
3083       VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
3084       VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3085       );
3086 
3087     for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
3088       for (Index1 = 0; Index1 < Width; Index1++) {
3089         BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
3090       }
3091       AddressFix = Address;
3092 
3093       for (Bit = 0; Bit < 8; Bit++) {
3094         //
3095         // Program the BitMask register with the Left column mask
3096         //
3097         WriteGraphicsController (
3098           PciIo,
3099           VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3100           LeftMask
3101           );
3102 
3103         for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
3104           //
3105           // Read data from the bit planes into the latches
3106           //
3107           PciIo->Mem.Read (
3108                       PciIo,
3109                       EfiPciIoWidthUint8,
3110                       EFI_PCI_IO_PASS_THROUGH_BAR,
3111                       (UINT64) (UINTN) Address1,
3112                       1,
3113                       &Data
3114                       );
3115 
3116           PciIo->Mem.Write (
3117                       PciIo,
3118                       EfiPciIoWidthUint8,
3119                       EFI_PCI_IO_PASS_THROUGH_BAR,
3120                       (UINT64) (UINTN) Address1,
3121                       1,
3122                       &BiosVideoPrivate->LineBuffer[Index1]
3123                       );
3124         }
3125 
3126         LeftMask = (UINT8) (LeftMask >> 1);
3127         if (LeftMask == 0) {
3128           LeftMask = 0x80;
3129           AddressFix++;
3130         }
3131       }
3132     }
3133 
3134     break;
3135 
3136     default: ;
3137   }
3138 
3139   gBS->RestoreTPL (OriginalTPL);
3140 
3141   return EFI_SUCCESS;
3142 }
3143 
3144 //
3145 // VGA Mini Port Protocol Functions
3146 //
3147 
3148 /**
3149   VgaMiniPort protocol interface to set mode.
3150 
3151   @param  This                   Pointer to VgaMiniPort protocol instance
3152   @param  ModeNumber             The index of the mode
3153 
3154   @retval EFI_UNSUPPORTED        The requested mode is not supported
3155   @retval EFI_SUCCESS            The requested mode is set successfully
3156 
3157 **/
3158 EFI_STATUS
3159 EFIAPI
BiosVideoVgaMiniPortSetMode(IN EFI_VGA_MINI_PORT_PROTOCOL * This,IN UINTN ModeNumber)3160 BiosVideoVgaMiniPortSetMode (
3161   IN  EFI_VGA_MINI_PORT_PROTOCOL  *This,
3162   IN  UINTN                       ModeNumber
3163   )
3164 {
3165   BIOS_VIDEO_DEV        *BiosVideoPrivate;
3166   EFI_IA32_REGISTER_SET Regs;
3167 
3168   if (This == NULL) {
3169     return EFI_INVALID_PARAMETER;
3170   }
3171 
3172   //
3173   // Make sure the ModeNumber is a valid value
3174   //
3175   if (ModeNumber >= This->MaxMode) {
3176     return EFI_UNSUPPORTED;
3177   }
3178   //
3179   // Get the device structure for this device
3180   //
3181   BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
3182 
3183   switch (ModeNumber) {
3184   case 0:
3185     //
3186     // Set the 80x25 Text VGA Mode
3187     //
3188     Regs.H.AH = 0x00;
3189     Regs.H.AL = 0x83;
3190     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3191 
3192     Regs.H.AH = 0x11;
3193     Regs.H.AL = 0x14;
3194     Regs.H.BL = 0;
3195     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3196     break;
3197 
3198   case 1:
3199     //
3200     // Set the 80x50 Text VGA Mode
3201     //
3202     Regs.H.AH = 0x00;
3203     Regs.H.AL = 0x83;
3204     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3205     Regs.H.AH = 0x11;
3206     Regs.H.AL = 0x12;
3207     Regs.H.BL = 0;
3208     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3209     break;
3210 
3211   default:
3212     return EFI_UNSUPPORTED;
3213   }
3214 
3215   return EFI_SUCCESS;
3216 }
3217 
3218 /**
3219   Event handler for Exit Boot Service.
3220 
3221   @param  Event       The event that be siganlled when exiting boot service.
3222   @param  Context     Pointer to instance of BIOS_VIDEO_DEV.
3223 
3224 **/
3225 VOID
3226 EFIAPI
BiosVideoNotifyExitBootServices(IN EFI_EVENT Event,IN VOID * Context)3227 BiosVideoNotifyExitBootServices (
3228   IN  EFI_EVENT Event,
3229   IN  VOID      *Context
3230   )
3231 {
3232   BIOS_VIDEO_DEV         *BiosVideoPrivate;
3233   EFI_IA32_REGISTER_SET  Regs;
3234 
3235   BiosVideoPrivate  = (BIOS_VIDEO_DEV *)Context;
3236 
3237   //
3238   // Set the 80x25 Text VGA Mode
3239   //
3240   Regs.H.AH = 0x00;
3241   Regs.H.AL = 0x03;
3242   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3243 
3244   Regs.H.AH = 0x00;
3245   Regs.H.AL = 0x83;
3246   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3247 
3248   Regs.H.AH = 0x11;
3249   Regs.H.AL = 0x04;
3250   Regs.H.BL = 0;
3251   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3252 }
3253 
3254 /**
3255   The user Entry Point for module UefiBiosVideo. The user code starts with this function.
3256 
3257   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
3258   @param[in] SystemTable    A pointer to the EFI System Table.
3259 
3260   @retval EFI_SUCCESS       The entry point is executed successfully.
3261   @retval other             Some error occurs when executing this entry point.
3262 
3263 **/
3264 EFI_STATUS
3265 EFIAPI
BiosVideoEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)3266 BiosVideoEntryPoint(
3267   IN EFI_HANDLE           ImageHandle,
3268   IN EFI_SYSTEM_TABLE     *SystemTable
3269   )
3270 {
3271   EFI_STATUS  Status;
3272 
3273   //
3274   // Install driver model protocol(s).
3275   //
3276   Status = EfiLibInstallDriverBindingComponentName2 (
3277              ImageHandle,
3278              SystemTable,
3279              &gBiosVideoDriverBinding,
3280              ImageHandle,
3281              &gBiosVideoComponentName,
3282              &gBiosVideoComponentName2
3283              );
3284   ASSERT_EFI_ERROR (Status);
3285 
3286   //
3287   // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
3288   //
3289   return gBS->InstallMultipleProtocolInterfaces (
3290                 &ImageHandle,
3291                 &gEfiLegacyBiosGuid,
3292                 NULL,
3293                 NULL
3294                 );
3295 }
3296 
3297