• 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   EFI_STATUS                           Status;
1261 
1262   EntryCount = 0;
1263   HasChild   = FALSE;
1264   Status = gBS->OpenProtocolInformation (
1265                   Controller,
1266                   &gEfiPciIoProtocolGuid,
1267                   &OpenInfoBuffer,
1268                   &EntryCount
1269                   );
1270   for (Index = 0; Index < EntryCount; Index++) {
1271     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1272       HasChild = TRUE;
1273     }
1274   }
1275 
1276   return HasChild;
1277 }
1278 
1279 /**
1280   Check for VBE device.
1281 
1282   @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure
1283 
1284   @retval EFI_SUCCESS            VBE device found
1285 
1286 **/
1287 EFI_STATUS
BiosVideoCheckForVbe(IN OUT BIOS_VIDEO_DEV * BiosVideoPrivate)1288 BiosVideoCheckForVbe (
1289   IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate
1290   )
1291 {
1292   EFI_STATUS                             Status;
1293   EFI_IA32_REGISTER_SET                  Regs;
1294   UINT16                                 *ModeNumberPtr;
1295   UINT16                                 VbeModeNumber;
1296   BOOLEAN                                ModeFound;
1297   BOOLEAN                                EdidFound;
1298   BIOS_VIDEO_MODE_DATA                   *ModeBuffer;
1299   BIOS_VIDEO_MODE_DATA                   *CurrentModeData;
1300   UINTN                                  PreferMode;
1301   UINTN                                  ModeNumber;
1302   VESA_BIOS_EXTENSIONS_EDID_TIMING       Timing;
1303   VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
1304   EFI_EDID_OVERRIDE_PROTOCOL             *EdidOverride;
1305   UINT32                                 EdidAttributes;
1306   BOOLEAN                                EdidOverrideFound;
1307   UINTN                                  EdidOverrideDataSize;
1308   UINT8                                  *EdidOverrideDataBlock;
1309   UINTN                                  EdidActiveDataSize;
1310   UINT8                                  *EdidActiveDataBlock;
1311   UINT32                                 HighestHorizontalResolution;
1312   UINT32                                 HighestVerticalResolution;
1313   UINTN                                  HighestResolutionMode;
1314 
1315   EdidFound             = TRUE;
1316   EdidOverrideFound     = FALSE;
1317   EdidOverrideDataBlock = NULL;
1318   EdidActiveDataSize    = 0;
1319   EdidActiveDataBlock   = NULL;
1320   HighestHorizontalResolution = 0;
1321   HighestVerticalResolution   = 0;
1322   HighestResolutionMode       = 0;
1323 
1324   //
1325   // Allocate buffer under 1MB for VBE data structures
1326   //
1327   BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
1328                                               sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +
1329                                               sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
1330                                               sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +
1331                                               sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
1332                                               );
1333 
1334   BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
1335 
1336   Status = gBS->AllocatePages (
1337                   AllocateMaxAddress,
1338                   EfiBootServicesData,
1339                   BiosVideoPrivate->NumberOfPagesBelow1MB,
1340                   &BiosVideoPrivate->PagesBelow1MB
1341                   );
1342   if (EFI_ERROR (Status)) {
1343     return Status;
1344   }
1345 
1346   ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));
1347 
1348   //
1349   // Fill in the VBE related data structures
1350   //
1351   BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
1352   BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
1353   BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
1354   BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);
1355   BiosVideoPrivate->VbeSaveRestorePages   = 0;
1356   BiosVideoPrivate->VbeSaveRestoreBuffer  = 0;
1357 
1358   //
1359   // Test to see if the Video Adapter is compliant with VBE 3.0
1360   //
1361   gBS->SetMem (&Regs, sizeof (Regs), 0);
1362   Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
1363   gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
1364   BiosVideoPrivate->VbeInformationBlock->VESASignature  = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
1365   Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1366   Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1367 
1368   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1369 
1370   Status = EFI_DEVICE_ERROR;
1371 
1372   //
1373   // See if the VESA call succeeded
1374   //
1375   if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1376     return Status;
1377   }
1378   //
1379   // Check for 'VESA' signature
1380   //
1381   if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
1382     return Status;
1383   }
1384   //
1385   // Check to see if this is VBE 2.0 or higher
1386   //
1387   if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
1388     return Status;
1389   }
1390 
1391   EdidFound            = FALSE;
1392   EdidAttributes       = 0xff;
1393   EdidOverrideDataSize = 0;
1394 
1395   //
1396   // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
1397   //
1398   Status = gBS->LocateProtocol (
1399                    &gEfiEdidOverrideProtocolGuid,
1400                    NULL,
1401                    (VOID **) &EdidOverride
1402                    );
1403   if (!EFI_ERROR (Status)) {
1404     //
1405     // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
1406     //
1407     EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);
1408     if (NULL == EdidOverrideDataBlock) {
1409   		Status = EFI_OUT_OF_RESOURCES;
1410       goto Done;
1411     }
1412 
1413     Status = EdidOverride->GetEdid (
1414                              EdidOverride,
1415                              BiosVideoPrivate->Handle,
1416                              &EdidAttributes,
1417                              &EdidOverrideDataSize,
1418                              (UINT8 **) &EdidOverrideDataBlock
1419                              );
1420     if (!EFI_ERROR (Status)  &&
1421          EdidAttributes == 0 &&
1422          EdidOverrideDataSize != 0) {
1423       //
1424       // Succeeded to get EDID Override Data
1425       //
1426       EdidOverrideFound = TRUE;
1427     }
1428   }
1429 
1430   if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
1431     //
1432     // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
1433     // read EDID information through INT10 call
1434     //
1435 
1436     gBS->SetMem (&Regs, sizeof (Regs), 0);
1437     Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
1438     Regs.X.BX = 1;
1439     Regs.X.CX = 0;
1440     Regs.X.DX = 0;
1441     Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1442     Regs.X.DI = EFI_OFFSET  ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1443 
1444     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1445     //
1446     // See if the VESA call succeeded
1447     //
1448     if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1449       //
1450       // Set EDID Discovered Data
1451       //
1452       BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1453  		  BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
1454                                                           VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
1455                                                           BiosVideoPrivate->VbeEdidDataBlock
1456  																												  );
1457 
1458       if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {
1459  			  Status = EFI_OUT_OF_RESOURCES;
1460         goto Done;
1461       }
1462 
1463       EdidFound = TRUE;
1464     }
1465   }
1466 
1467   if (EdidFound) {
1468     EdidActiveDataSize  = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1469     EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;
1470   } else if (EdidOverrideFound) {
1471     EdidActiveDataSize  = EdidOverrideDataSize;
1472     EdidActiveDataBlock = EdidOverrideDataBlock;
1473     EdidFound = TRUE;
1474  	}
1475 
1476  	if (EdidFound) {
1477     //
1478     // Parse EDID data structure to retrieve modes supported by monitor
1479     //
1480     if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {
1481       //
1482       // Copy EDID Override Data to EDID Active Data
1483       //
1484       BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
1485       BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
1486                                                       EdidActiveDataSize,
1487                                                       EdidActiveDataBlock
1488                                                       );
1489       if (NULL ==  BiosVideoPrivate->EdidActive.Edid) {
1490    		  Status = EFI_OUT_OF_RESOURCES;
1491         goto Done;
1492       }
1493     }
1494   } else {
1495     BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
1496     BiosVideoPrivate->EdidActive.Edid = NULL;
1497     EdidFound = FALSE;
1498   }
1499 
1500   //
1501   // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1502   //
1503   ModeNumberPtr = (UINT16 *)
1504     (
1505       (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
1506         ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
1507     );
1508 
1509   PreferMode = 0;
1510   ModeNumber = 0;
1511 
1512   //
1513   // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
1514   //
1515   for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);
1516        VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;
1517        VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {
1518     //
1519     // Make sure this is a mode number defined by the VESA VBE specification.  If it isn'tm then skip this mode number.
1520     //
1521     if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
1522       continue;
1523     }
1524     //
1525     // Get the information about the mode
1526     //
1527     gBS->SetMem (&Regs, sizeof (Regs), 0);
1528     Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
1529     Regs.X.CX = VbeModeNumber;
1530     gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
1531     Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1532     Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1533 
1534     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1535 
1536     //
1537     // See if the call succeeded.  If it didn't, then try the next mode.
1538     //
1539     if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1540       continue;
1541     }
1542     //
1543     // See if the mode supports color.  If it doesn't then try the next mode.
1544     //
1545     if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
1546       continue;
1547     }
1548     //
1549     // See if the mode supports graphics.  If it doesn't then try the next mode.
1550     //
1551     if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
1552       continue;
1553     }
1554     //
1555     // See if the mode supports a linear frame buffer.  If it doesn't then try the next mode.
1556     //
1557     if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
1558       continue;
1559     }
1560     //
1561     // See if the mode supports 32 bit color.  If it doesn't then try the next mode.
1562     // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1563     // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1564     //
1565     if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
1566       continue;
1567     }
1568 
1569     if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
1570       continue;
1571     }
1572 
1573     if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
1574       continue;
1575     }
1576     //
1577     // See if the physical base pointer for the linear mode is valid.  If it isn't then try the next mode.
1578     //
1579     if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
1580       continue;
1581     }
1582 
1583     DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",
1584             VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));
1585 
1586     if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
1587       //
1588       // EDID exist, check whether this mode match with any mode in EDID
1589       //
1590       Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1591       Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1592       if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {
1593         //
1594         // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
1595         // but INT10 can support these modes, we add them into GOP mode.
1596         //
1597         if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&
1598             !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&
1599             !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&
1600             !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {
1601         continue;
1602         }
1603       }
1604     }
1605 
1606     //
1607     // Select a reasonable mode to be set for current display mode
1608     //
1609     ModeFound = FALSE;
1610 
1611     if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
1612         BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
1613         ) {
1614       ModeFound = TRUE;
1615     }
1616     if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
1617         BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
1618         ) {
1619       ModeFound = TRUE;
1620       PreferMode = ModeNumber;
1621     }
1622     if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
1623         BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
1624         ) {
1625       ModeFound = TRUE;
1626     }
1627 
1628     if ((!EdidFound) && (!ModeFound)) {
1629       //
1630       // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1631       //
1632       continue;
1633     }
1634 
1635     //
1636     // Record the highest resolution mode to set later
1637     //
1638     if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||
1639         ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) &&
1640          (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {
1641       HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1642       HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1643       HighestResolutionMode = ModeNumber;
1644     }
1645 
1646     //
1647     // Add mode to the list of available modes
1648     //
1649     ModeNumber ++;
1650     ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1651 																						ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)
1652 																						);
1653     if (NULL == ModeBuffer) {
1654 			Status = EFI_OUT_OF_RESOURCES;
1655       goto Done;
1656     }
1657 
1658     if (ModeNumber > 1) {
1659       CopyMem (
1660         ModeBuffer,
1661         BiosVideoPrivate->ModeData,
1662         (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
1663         );
1664     }
1665 
1666     if (BiosVideoPrivate->ModeData != NULL) {
1667       FreePool (BiosVideoPrivate->ModeData);
1668     }
1669 
1670     CurrentModeData = &ModeBuffer[ModeNumber - 1];
1671     CurrentModeData->VbeModeNumber = VbeModeNumber;
1672     if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
1673       CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
1674       CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
1675       CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
1676       CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
1677       CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
1678       CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
1679       CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
1680       CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
1681       CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
1682     } else {
1683       CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
1684       CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
1685       CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
1686       CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
1687       CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
1688       CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
1689       CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
1690       CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
1691       CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
1692     }
1693 
1694     CurrentModeData->PixelFormat = PixelBitMask;
1695     if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
1696         (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
1697       if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
1698         CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
1699       } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
1700         CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
1701       }
1702     }
1703 
1704     CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
1705     CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
1706     CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
1707     CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
1708 
1709     CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
1710     CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1711     CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1712 
1713     CurrentModeData->BitsPerPixel  = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1714     CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
1715     //
1716     // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
1717     //
1718     ASSERT (CurrentModeData->FrameBufferSize <= (UINTN)(BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));
1719 
1720     BiosVideoPrivate->ModeData = ModeBuffer;
1721   }
1722   //
1723   // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1724   //
1725   if (ModeNumber == 0) {
1726     Status = EFI_DEVICE_ERROR;
1727     goto Done;
1728   }
1729 
1730   //
1731   // Assign Gop's Blt function
1732   //
1733   BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVbeBlt;
1734 
1735   BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;
1736   //
1737   // Current mode is unknow till now, set it to an invalid mode.
1738   //
1739   BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1740 
1741   //
1742   // Find the best mode to initialize
1743   //
1744   if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {
1745     DEBUG_CODE (
1746       BIOS_VIDEO_MODE_DATA    *ModeData;
1747       ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];
1748       DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",
1749               ModeData->HorizontalResolution, ModeData->VerticalResolution));
1750     );
1751     PreferMode = HighestResolutionMode;
1752   }
1753   Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
1754   if (EFI_ERROR (Status)) {
1755     for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
1756       Status = BiosVideoGraphicsOutputSetMode (
1757                 &BiosVideoPrivate->GraphicsOutput,
1758                 (UINT32) PreferMode
1759                 );
1760       if (!EFI_ERROR (Status)) {
1761         break;
1762       }
1763     }
1764     if (PreferMode == ModeNumber) {
1765       //
1766       // None mode is set successfully.
1767       //
1768       goto Done;
1769     }
1770   }
1771 
1772 Done:
1773   //
1774   // If there was an error, then free the mode structure
1775   //
1776   if (EFI_ERROR (Status)) {
1777     if (BiosVideoPrivate->ModeData != NULL) {
1778       FreePool (BiosVideoPrivate->ModeData);
1779       BiosVideoPrivate->ModeData  = NULL;
1780       BiosVideoPrivate->MaxMode   = 0;
1781     }
1782     if (EdidOverrideDataBlock != NULL) {
1783       FreePool (EdidOverrideDataBlock);
1784     }
1785   }
1786 
1787   return Status;
1788 }
1789 
1790 
1791 /**
1792   Check for VGA device.
1793 
1794   @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure
1795 
1796   @retval EFI_SUCCESS            Standard VGA device found
1797 
1798 **/
1799 EFI_STATUS
BiosVideoCheckForVga(IN OUT BIOS_VIDEO_DEV * BiosVideoPrivate)1800 BiosVideoCheckForVga (
1801   IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate
1802   )
1803 {
1804   EFI_STATUS            Status;
1805   BIOS_VIDEO_MODE_DATA  *ModeBuffer;
1806 
1807   Status = EFI_UNSUPPORTED;
1808 
1809   //
1810   // Assign Gop's Blt function
1811   //
1812   BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVgaBlt;
1813 
1814   //
1815   // Add mode to the list of available modes
1816   // caller should guarantee that Mode has been allocated.
1817   //
1818   ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);
1819   BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
1820 
1821   ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1822                                           sizeof (BIOS_VIDEO_MODE_DATA)
1823                                           );
1824   if (NULL == ModeBuffer) {
1825 		Status = EFI_OUT_OF_RESOURCES;
1826     goto Done;
1827   }
1828 
1829   ModeBuffer->VbeModeNumber         = 0x0012;
1830   ModeBuffer->BytesPerScanLine      = 640;
1831   ModeBuffer->LinearFrameBuffer     = (VOID *) (UINTN) (0xa0000);
1832   ModeBuffer->HorizontalResolution  = 640;
1833   ModeBuffer->VerticalResolution    = 480;
1834   ModeBuffer->PixelFormat           = PixelBltOnly;
1835   ModeBuffer->BitsPerPixel          = 8;
1836   ModeBuffer->ColorDepth            = 32;
1837   ModeBuffer->RefreshRate           = 60;
1838 
1839   BiosVideoPrivate->ModeData = ModeBuffer;
1840 
1841   //
1842   // Test to see if the Video Adapter support the 640x480 16 color mode
1843   //
1844   BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1845   Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
1846 
1847 Done:
1848   //
1849   // If there was an error, then free the mode structure
1850   //
1851   if (EFI_ERROR (Status)) {
1852     if (BiosVideoPrivate->ModeData != NULL) {
1853       FreePool (BiosVideoPrivate->ModeData);
1854       BiosVideoPrivate->ModeData = NULL;
1855     }
1856     if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1857       if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1858         FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1859         BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
1860       }
1861       FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1862       BiosVideoPrivate->GraphicsOutput.Mode = NULL;
1863     }
1864   }
1865   return Status;
1866 }
1867 
1868 //
1869 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1870 //
1871 
1872 /**
1873   Graphics Output protocol interface to get video mode.
1874 
1875   @param  This                   Protocol instance pointer.
1876   @param  ModeNumber             The mode number to return information on.
1877   @param  SizeOfInfo             A pointer to the size, in bytes, of the Info
1878                                  buffer.
1879   @param  Info                   Caller allocated buffer that returns information
1880                                  about ModeNumber.
1881 
1882   @retval EFI_SUCCESS            Mode information returned.
1883   @retval EFI_DEVICE_ERROR       A hardware error occurred trying to retrieve the
1884                                  video mode.
1885   @retval EFI_NOT_STARTED        Video display is not initialized. Call SetMode ()
1886   @retval EFI_INVALID_PARAMETER  One of the input args was NULL.
1887 
1888 **/
1889 EFI_STATUS
1890 EFIAPI
BiosVideoGraphicsOutputQueryMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)1891 BiosVideoGraphicsOutputQueryMode (
1892   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
1893   IN  UINT32                                ModeNumber,
1894   OUT UINTN                                 *SizeOfInfo,
1895   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
1896   )
1897 {
1898   BIOS_VIDEO_DEV        *BiosVideoPrivate;
1899   BIOS_VIDEO_MODE_DATA  *ModeData;
1900 
1901   BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1902 
1903   if (BiosVideoPrivate->HardwareNeedsStarting) {
1904     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1905       EFI_ERROR_CODE | EFI_ERROR_MINOR,
1906       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
1907       BiosVideoPrivate->GopDevicePath
1908       );
1909     return EFI_NOT_STARTED;
1910   }
1911 
1912   if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
1913     return EFI_INVALID_PARAMETER;
1914   }
1915 
1916   *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
1917 																										sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
1918 																										);
1919   if (NULL == *Info) {
1920     return EFI_OUT_OF_RESOURCES;
1921   }
1922 
1923   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1924 
1925   ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
1926   (*Info)->Version = 0;
1927   (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
1928   (*Info)->VerticalResolution   = ModeData->VerticalResolution;
1929   (*Info)->PixelFormat = ModeData->PixelFormat;
1930   CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
1931 
1932   (*Info)->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
1933 
1934   return EFI_SUCCESS;
1935 }
1936 
1937 /**
1938   Worker function to set video mode.
1939 
1940   @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV.
1941   @param  ModeData               The mode data to be set.
1942   @param  DevicePath             Pointer to Device Path Protocol.
1943 
1944   @retval EFI_SUCCESS            Graphics mode was changed.
1945   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the
1946                                  request.
1947   @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.
1948 
1949 **/
1950 EFI_STATUS
BiosVideoSetModeWorker(IN BIOS_VIDEO_DEV * BiosVideoPrivate,IN BIOS_VIDEO_MODE_DATA * ModeData,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)1951 BiosVideoSetModeWorker (
1952   IN  BIOS_VIDEO_DEV               *BiosVideoPrivate,
1953   IN  BIOS_VIDEO_MODE_DATA         *ModeData,
1954   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
1955   )
1956 {
1957   EFI_STATUS              Status;
1958   EFI_IA32_REGISTER_SET   Regs;
1959 
1960   if (BiosVideoPrivate->LineBuffer != NULL) {
1961     FreePool (BiosVideoPrivate->LineBuffer);
1962   }
1963 
1964   if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
1965     FreePool (BiosVideoPrivate->VgaFrameBuffer);
1966   }
1967 
1968   if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
1969     FreePool (BiosVideoPrivate->VbeFrameBuffer);
1970   }
1971 
1972   BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (
1973 																					   ModeData->BytesPerScanLine
1974 																					   );
1975   if (NULL == BiosVideoPrivate->LineBuffer) {
1976     return EFI_OUT_OF_RESOURCES;
1977   }
1978   //
1979   // Clear all registers
1980   //
1981   ZeroMem (&Regs, sizeof (Regs));
1982 
1983   if (ModeData->VbeModeNumber < 0x100) {
1984     //
1985     // Allocate a working buffer for BLT operations to the VGA frame buffer
1986     //
1987     BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);
1988     if (NULL == BiosVideoPrivate->VgaFrameBuffer) {
1989       return EFI_OUT_OF_RESOURCES;
1990     }
1991     //
1992     // Set VGA Mode
1993     //
1994     Regs.X.AX = ModeData->VbeModeNumber;
1995     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1996 
1997   } else {
1998     //
1999     // Allocate a working buffer for BLT operations to the VBE frame buffer
2000     //
2001     BiosVideoPrivate->VbeFrameBuffer =
2002 			(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
2003 																					ModeData->BytesPerScanLine * ModeData->VerticalResolution
2004 																				  );
2005     if (NULL == BiosVideoPrivate->VbeFrameBuffer) {
2006       return EFI_OUT_OF_RESOURCES;
2007     }
2008     //
2009     // Set VBE mode
2010     //
2011     Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
2012     Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
2013     ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));
2014     Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2015     Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2016     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
2017 
2018     //
2019     // Check to see if the call succeeded
2020     //
2021     if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
2022       REPORT_STATUS_CODE_WITH_DEVICE_PATH (
2023         EFI_ERROR_CODE | EFI_ERROR_MINOR,
2024         EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
2025         DevicePath
2026         );
2027       return EFI_DEVICE_ERROR;
2028     }
2029     //
2030     // Initialize the state of the VbeFrameBuffer
2031     //
2032     Status = BiosVideoPrivate->PciIo->Mem.Read (
2033                                             BiosVideoPrivate->PciIo,
2034                                             EfiPciIoWidthUint32,
2035                                             EFI_PCI_IO_PASS_THROUGH_BAR,
2036                                             (UINT64) (UINTN) ModeData->LinearFrameBuffer,
2037                                             (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
2038                                             BiosVideoPrivate->VbeFrameBuffer
2039                                             );
2040     if (EFI_ERROR (Status)) {
2041       return Status;
2042     }
2043   }
2044 
2045   return EFI_SUCCESS;
2046 }
2047 
2048 /**
2049   Graphics Output protocol interface to set video mode.
2050 
2051   @param  This                   Protocol instance pointer.
2052   @param  ModeNumber             The mode number to be set.
2053 
2054   @retval EFI_SUCCESS            Graphics mode was changed.
2055   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the
2056                                  request.
2057   @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.
2058 
2059 **/
2060 EFI_STATUS
2061 EFIAPI
BiosVideoGraphicsOutputSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)2062 BiosVideoGraphicsOutputSetMode (
2063   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
2064   IN  UINT32                       ModeNumber
2065   )
2066 {
2067   EFI_STATUS              Status;
2068   BIOS_VIDEO_DEV          *BiosVideoPrivate;
2069   BIOS_VIDEO_MODE_DATA    *ModeData;
2070   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
2071 
2072   if (This == NULL) {
2073     return EFI_INVALID_PARAMETER;
2074   }
2075 
2076   BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2077 
2078   ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
2079 
2080   if (ModeNumber >= This->Mode->MaxMode) {
2081     return EFI_UNSUPPORTED;
2082   }
2083 
2084   if (ModeNumber == This->Mode->Mode) {
2085     //
2086     // Clear screen to black
2087     //
2088     ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2089     BiosVideoGraphicsOutputVbeBlt (
2090                         This,
2091                         &Background,
2092                         EfiBltVideoFill,
2093                         0,
2094                         0,
2095                         0,
2096                         0,
2097                         ModeData->HorizontalResolution,
2098                         ModeData->VerticalResolution,
2099                         0
2100     );
2101     return EFI_SUCCESS;
2102   }
2103 
2104   Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);
2105   if (EFI_ERROR (Status)) {
2106     return Status;
2107   }
2108 
2109   This->Mode->Mode = ModeNumber;
2110   This->Mode->Info->Version = 0;
2111   This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
2112   This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
2113   This->Mode->Info->PixelFormat = ModeData->PixelFormat;
2114   CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));
2115   This->Mode->Info->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
2116   This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
2117   This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
2118   This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;
2119 
2120   BiosVideoPrivate->HardwareNeedsStarting = FALSE;
2121 
2122   return EFI_SUCCESS;
2123 }
2124 
2125 /**
2126   Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
2127 
2128   @param   PciIo              The pointer of EFI_PCI_IO_PROTOCOL
2129   @param   VbeBuffer          The data to transfer to screen
2130   @param   MemAddress         Physical frame buffer base address
2131   @param   DestinationX       The X coordinate of the destination for BltOperation
2132   @param   DestinationY       The Y coordinate of the destination for BltOperation
2133   @param   TotalBytes         The total bytes of copy
2134   @param   VbePixelWidth      Bytes per pixel
2135   @param   BytesPerScanLine   Bytes per scan line
2136 
2137 **/
2138 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)2139 CopyVideoBuffer (
2140   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
2141   IN  UINT8                 *VbeBuffer,
2142   IN  VOID                  *MemAddress,
2143   IN  UINTN                 DestinationX,
2144   IN  UINTN                 DestinationY,
2145   IN  UINTN                 TotalBytes,
2146   IN  UINT32                VbePixelWidth,
2147   IN  UINTN                 BytesPerScanLine
2148   )
2149 {
2150   UINTN                 FrameBufferAddr;
2151   UINTN                 CopyBlockNum;
2152   UINTN                 RemainingBytes;
2153   UINTN                 UnalignedBytes;
2154   EFI_STATUS            Status;
2155 
2156   FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
2157 
2158   //
2159   // If TotalBytes is less than 4 bytes, only start byte copy.
2160   //
2161   if (TotalBytes < 4) {
2162     Status = PciIo->Mem.Write (
2163                      PciIo,
2164                      EfiPciIoWidthUint8,
2165                      EFI_PCI_IO_PASS_THROUGH_BAR,
2166                      (UINT64) FrameBufferAddr,
2167                      TotalBytes,
2168                      VbeBuffer
2169                      );
2170     ASSERT_EFI_ERROR (Status);
2171     return;
2172   }
2173 
2174   //
2175   // If VbeBuffer is not 4-byte aligned, start byte copy.
2176   //
2177   UnalignedBytes  = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
2178 
2179   if (UnalignedBytes != 0) {
2180     Status = PciIo->Mem.Write (
2181                      PciIo,
2182                      EfiPciIoWidthUint8,
2183                      EFI_PCI_IO_PASS_THROUGH_BAR,
2184                      (UINT64) FrameBufferAddr,
2185                      UnalignedBytes,
2186                      VbeBuffer
2187                      );
2188     ASSERT_EFI_ERROR (Status);
2189     FrameBufferAddr += UnalignedBytes;
2190     VbeBuffer       += UnalignedBytes;
2191   }
2192 
2193   //
2194   // Calculate 4-byte block count and remaining bytes.
2195   //
2196   CopyBlockNum   = (TotalBytes - UnalignedBytes) >> 2;
2197   RemainingBytes = (TotalBytes - UnalignedBytes) &  3;
2198 
2199   //
2200   // Copy 4-byte block and remaining bytes to physical frame buffer.
2201   //
2202   if (CopyBlockNum != 0) {
2203     Status = PciIo->Mem.Write (
2204                     PciIo,
2205                     EfiPciIoWidthUint32,
2206                     EFI_PCI_IO_PASS_THROUGH_BAR,
2207                     (UINT64) FrameBufferAddr,
2208                     CopyBlockNum,
2209                     VbeBuffer
2210                     );
2211     ASSERT_EFI_ERROR (Status);
2212   }
2213 
2214   if (RemainingBytes != 0) {
2215     FrameBufferAddr += (CopyBlockNum << 2);
2216     VbeBuffer       += (CopyBlockNum << 2);
2217     Status = PciIo->Mem.Write (
2218                     PciIo,
2219                     EfiPciIoWidthUint8,
2220                     EFI_PCI_IO_PASS_THROUGH_BAR,
2221                     (UINT64) FrameBufferAddr,
2222                     RemainingBytes,
2223                     VbeBuffer
2224                     );
2225     ASSERT_EFI_ERROR (Status);
2226   }
2227 }
2228 
2229 /**
2230   Worker function to block transfer for VBE device.
2231 
2232   @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV
2233   @param  BltBuffer              The data to transfer to screen
2234   @param  BltOperation           The operation to perform
2235   @param  SourceX                The X coordinate of the source for BltOperation
2236   @param  SourceY                The Y coordinate of the source for BltOperation
2237   @param  DestinationX           The X coordinate of the destination for
2238                                  BltOperation
2239   @param  DestinationY           The Y coordinate of the destination for
2240                                  BltOperation
2241   @param  Width                  The width of a rectangle in the blt rectangle in
2242                                  pixels
2243   @param  Height                 The height of a rectangle in the blt rectangle in
2244                                  pixels
2245   @param  Delta                  Not used for EfiBltVideoFill and
2246                                  EfiBltVideoToVideo operation. If a Delta of 0 is
2247                                  used, the entire BltBuffer will be operated on. If
2248                                  a subrectangle of the BltBuffer is used, then
2249                                  Delta represents the number of bytes in a row of
2250                                  the BltBuffer.
2251   @param  Mode                   Mode data.
2252 
2253   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
2254   @retval EFI_SUCCESS            Blt operation success
2255 
2256 **/
2257 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)2258 BiosVideoVbeBltWorker (
2259   IN  BIOS_VIDEO_DEV                     *BiosVideoPrivate,
2260   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
2261   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
2262   IN  UINTN                              SourceX,
2263   IN  UINTN                              SourceY,
2264   IN  UINTN                              DestinationX,
2265   IN  UINTN                              DestinationY,
2266   IN  UINTN                              Width,
2267   IN  UINTN                              Height,
2268   IN  UINTN                              Delta,
2269   IN  BIOS_VIDEO_MODE_DATA               *Mode
2270   )
2271 {
2272   EFI_PCI_IO_PROTOCOL            *PciIo;
2273   EFI_TPL                        OriginalTPL;
2274   UINTN                          DstY;
2275   UINTN                          SrcY;
2276   UINTN                          DstX;
2277   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *Blt;
2278   VOID                           *MemAddress;
2279   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *VbeFrameBuffer;
2280   UINTN                          BytesPerScanLine;
2281   UINTN                          Index;
2282   UINT8                          *VbeBuffer;
2283   UINT8                          *VbeBuffer1;
2284   UINT8                          *BltUint8;
2285   UINT32                         VbePixelWidth;
2286   UINT32                         Pixel;
2287   UINTN                          TotalBytes;
2288 
2289   PciIo             = BiosVideoPrivate->PciIo;
2290 
2291   VbeFrameBuffer    = BiosVideoPrivate->VbeFrameBuffer;
2292   MemAddress        = Mode->LinearFrameBuffer;
2293   BytesPerScanLine  = Mode->BytesPerScanLine;
2294   VbePixelWidth     = Mode->BitsPerPixel / 8;
2295   BltUint8          = (UINT8 *) BltBuffer;
2296   TotalBytes        = Width * VbePixelWidth;
2297 
2298   if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2299     return EFI_INVALID_PARAMETER;
2300   }
2301 
2302   if (Width == 0 || Height == 0) {
2303     return EFI_INVALID_PARAMETER;
2304   }
2305   //
2306   // We need to fill the Virtual Screen buffer with the blt data.
2307   // The virtual screen is upside down, as the first row is the bootom row of
2308   // the image.
2309   //
2310   if (BltOperation == EfiBltVideoToBltBuffer) {
2311     //
2312     // Video to BltBuffer: Source is Video, destination is BltBuffer
2313     //
2314     if (SourceY + Height > Mode->VerticalResolution) {
2315       return EFI_INVALID_PARAMETER;
2316     }
2317 
2318     if (SourceX + Width > Mode->HorizontalResolution) {
2319       return EFI_INVALID_PARAMETER;
2320     }
2321   } else {
2322     //
2323     // BltBuffer to Video: Source is BltBuffer, destination is Video
2324     //
2325     if (DestinationY + Height > Mode->VerticalResolution) {
2326       return EFI_INVALID_PARAMETER;
2327     }
2328 
2329     if (DestinationX + Width > Mode->HorizontalResolution) {
2330       return EFI_INVALID_PARAMETER;
2331     }
2332   }
2333   //
2334   // If Delta is zero, then the entire BltBuffer is being used, so Delta
2335   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
2336   // the number of bytes in each row can be computed.
2337   //
2338   if (Delta == 0) {
2339     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2340   }
2341   //
2342   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2343   // We would not want a timer based event (Cursor, ...) to come in while we are
2344   // doing this operation.
2345   //
2346   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2347 
2348   switch (BltOperation) {
2349   case EfiBltVideoToBltBuffer:
2350     for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
2351       Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2352       //
2353       // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2354       //
2355       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
2356       for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2357         Pixel         = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
2358         Blt->Red      = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
2359         Blt->Blue     = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
2360         Blt->Green    = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
2361         Blt->Reserved = 0;
2362         Blt++;
2363         VbeBuffer += VbePixelWidth;
2364       }
2365 
2366     }
2367     break;
2368 
2369   case EfiBltVideoToVideo:
2370     for (Index = 0; Index < Height; Index++) {
2371       if (DestinationY <= SourceY) {
2372         SrcY  = SourceY + Index;
2373         DstY  = DestinationY + Index;
2374       } else {
2375         SrcY  = SourceY + Height - Index - 1;
2376         DstY  = DestinationY + Height - Index - 1;
2377       }
2378 
2379       VbeBuffer   = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
2380       VbeBuffer1  = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
2381 
2382       gBS->CopyMem (
2383             VbeBuffer,
2384             VbeBuffer1,
2385             TotalBytes
2386             );
2387 
2388       //
2389       // Update physical frame buffer.
2390       //
2391       CopyVideoBuffer (
2392         PciIo,
2393         VbeBuffer,
2394         MemAddress,
2395         DestinationX,
2396         DstY,
2397         TotalBytes,
2398         VbePixelWidth,
2399         BytesPerScanLine
2400         );
2401     }
2402     break;
2403 
2404   case EfiBltVideoFill:
2405     VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2406     Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
2407     //
2408     // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2409     //
2410     Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2411       (
2412         (Blt->Green & Mode->Green.Mask) <<
2413         Mode->Green.Position
2414       ) |
2415           ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2416 
2417     for (Index = 0; Index < Width; Index++) {
2418       gBS->CopyMem (
2419             VbeBuffer,
2420             &Pixel,
2421             VbePixelWidth
2422             );
2423       VbeBuffer += VbePixelWidth;
2424     }
2425 
2426     VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2427     for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
2428       gBS->CopyMem (
2429             (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
2430             VbeBuffer,
2431             TotalBytes
2432             );
2433     }
2434 
2435     for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
2436       //
2437       // Update physical frame buffer.
2438       //
2439       CopyVideoBuffer (
2440         PciIo,
2441         VbeBuffer,
2442         MemAddress,
2443         DestinationX,
2444         DstY,
2445         TotalBytes,
2446         VbePixelWidth,
2447         BytesPerScanLine
2448         );
2449     }
2450     break;
2451 
2452   case EfiBltBufferToVideo:
2453     for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
2454       Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2455       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2456       for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2457         //
2458         // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2459         //
2460         Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2461           ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
2462             ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2463         gBS->CopyMem (
2464               VbeBuffer,
2465               &Pixel,
2466               VbePixelWidth
2467               );
2468         Blt++;
2469         VbeBuffer += VbePixelWidth;
2470       }
2471 
2472       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2473 
2474       //
2475       // Update physical frame buffer.
2476       //
2477       CopyVideoBuffer (
2478         PciIo,
2479         VbeBuffer,
2480         MemAddress,
2481         DestinationX,
2482         DstY,
2483         TotalBytes,
2484         VbePixelWidth,
2485         BytesPerScanLine
2486         );
2487     }
2488     break;
2489 
2490     default: ;
2491   }
2492 
2493   gBS->RestoreTPL (OriginalTPL);
2494 
2495   return EFI_SUCCESS;
2496 }
2497 
2498 /**
2499   Graphics Output protocol instance to block transfer for VBE device.
2500 
2501   @param  This                   Pointer to Graphics Output protocol instance
2502   @param  BltBuffer              The data to transfer to screen
2503   @param  BltOperation           The operation to perform
2504   @param  SourceX                The X coordinate of the source for BltOperation
2505   @param  SourceY                The Y coordinate of the source for BltOperation
2506   @param  DestinationX           The X coordinate of the destination for
2507                                  BltOperation
2508   @param  DestinationY           The Y coordinate of the destination for
2509                                  BltOperation
2510   @param  Width                  The width of a rectangle in the blt rectangle in
2511                                  pixels
2512   @param  Height                 The height of a rectangle in the blt rectangle in
2513                                  pixels
2514   @param  Delta                  Not used for EfiBltVideoFill and
2515                                  EfiBltVideoToVideo operation. If a Delta of 0 is
2516                                  used, the entire BltBuffer will be operated on. If
2517                                  a subrectangle of the BltBuffer is used, then
2518                                  Delta represents the number of bytes in a row of
2519                                  the BltBuffer.
2520 
2521   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
2522   @retval EFI_SUCCESS            Blt operation success
2523 
2524 **/
2525 EFI_STATUS
2526 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)2527 BiosVideoGraphicsOutputVbeBlt (
2528   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,
2529   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
2530   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
2531   IN  UINTN                              SourceX,
2532   IN  UINTN                              SourceY,
2533   IN  UINTN                              DestinationX,
2534   IN  UINTN                              DestinationY,
2535   IN  UINTN                              Width,
2536   IN  UINTN                              Height,
2537   IN  UINTN                              Delta
2538   )
2539 {
2540   BIOS_VIDEO_DEV                 *BiosVideoPrivate;
2541   BIOS_VIDEO_MODE_DATA           *Mode;
2542 
2543   if (This == NULL) {
2544     return EFI_INVALID_PARAMETER;
2545   }
2546 
2547   BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2548   Mode              = &BiosVideoPrivate->ModeData[This->Mode->Mode];
2549 
2550   return BiosVideoVbeBltWorker (
2551            BiosVideoPrivate,
2552            BltBuffer,
2553            BltOperation,
2554            SourceX,
2555            SourceY,
2556            DestinationX,
2557            DestinationY,
2558            Width,
2559            Height,
2560            Delta,
2561            Mode
2562            );
2563 }
2564 
2565 /**
2566   Write graphics controller registers.
2567 
2568   @param  PciIo                  Pointer to PciIo protocol instance of the
2569                                  controller
2570   @param  Address                Register address
2571   @param  Data                   Data to be written to register
2572 
2573   @return None
2574 
2575 **/
2576 VOID
WriteGraphicsController(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINTN Address,IN UINTN Data)2577 WriteGraphicsController (
2578   IN  EFI_PCI_IO_PROTOCOL  *PciIo,
2579   IN  UINTN                Address,
2580   IN  UINTN                Data
2581   )
2582 {
2583   Address = Address | (Data << 8);
2584   PciIo->Io.Write (
2585               PciIo,
2586               EfiPciIoWidthUint16,
2587               EFI_PCI_IO_PASS_THROUGH_BAR,
2588               VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
2589               1,
2590               &Address
2591               );
2592 }
2593 
2594 
2595 /**
2596   Read the four bit plane of VGA frame buffer.
2597 
2598   @param  PciIo                  Pointer to PciIo protocol instance of the
2599                                  controller
2600   @param  HardwareBuffer         Hardware VGA frame buffer address
2601   @param  MemoryBuffer           Memory buffer address
2602   @param  WidthInBytes           Number of bytes in a line to read
2603   @param  Height                 Height of the area to read
2604 
2605   @return None
2606 
2607 **/
2608 VOID
VgaReadBitPlanes(EFI_PCI_IO_PROTOCOL * PciIo,UINT8 * HardwareBuffer,UINT8 * MemoryBuffer,UINTN WidthInBytes,UINTN Height)2609 VgaReadBitPlanes (
2610   EFI_PCI_IO_PROTOCOL  *PciIo,
2611   UINT8                *HardwareBuffer,
2612   UINT8                *MemoryBuffer,
2613   UINTN                WidthInBytes,
2614   UINTN                Height
2615   )
2616 {
2617   UINTN BitPlane;
2618   UINTN Rows;
2619   UINTN FrameBufferOffset;
2620   UINT8 *Source;
2621   UINT8 *Destination;
2622 
2623   //
2624   // Program the Mode Register Write mode 0, Read mode 0
2625   //
2626   WriteGraphicsController (
2627     PciIo,
2628     VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2629     VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2630     );
2631 
2632   for (BitPlane = 0, FrameBufferOffset = 0;
2633        BitPlane < VGA_NUMBER_OF_BIT_PLANES;
2634        BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
2635       ) {
2636     //
2637     // Program the Read Map Select Register to select the correct bit plane
2638     //
2639     WriteGraphicsController (
2640       PciIo,
2641       VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
2642       BitPlane
2643       );
2644 
2645     Source      = HardwareBuffer;
2646     Destination = MemoryBuffer + FrameBufferOffset;
2647 
2648     for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
2649       PciIo->Mem.Read (
2650                   PciIo,
2651                   EfiPciIoWidthUint8,
2652                   EFI_PCI_IO_PASS_THROUGH_BAR,
2653                   (UINT64) (UINTN) Source,
2654                   WidthInBytes,
2655                   (VOID *) Destination
2656                   );
2657     }
2658   }
2659 }
2660 
2661 
2662 /**
2663   Internal routine to convert VGA color to Grahpics Output color.
2664 
2665   @param  MemoryBuffer           Buffer containing VGA color
2666   @param  CoordinateX            The X coordinate of pixel on screen
2667   @param  CoordinateY            The Y coordinate of pixel on screen
2668   @param  BltBuffer              Buffer to contain converted Grahpics Output color
2669 
2670   @return None
2671 
2672 **/
2673 VOID
VgaConvertToGraphicsOutputColor(UINT8 * MemoryBuffer,UINTN CoordinateX,UINTN CoordinateY,EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer)2674 VgaConvertToGraphicsOutputColor (
2675   UINT8                          *MemoryBuffer,
2676   UINTN                          CoordinateX,
2677   UINTN                          CoordinateY,
2678   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *BltBuffer
2679   )
2680 {
2681   UINTN Mask;
2682   UINTN Bit;
2683   UINTN Color;
2684 
2685   MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));
2686   Mask = mVgaBitMaskTable[CoordinateX & 0x07];
2687   for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
2688     if ((*MemoryBuffer & Mask) != 0) {
2689       Color |= Bit;
2690     }
2691   }
2692 
2693   *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
2694 }
2695 
2696 /**
2697   Internal routine to convert Grahpics Output color to VGA color.
2698 
2699   @param  BltBuffer              buffer containing Grahpics Output color
2700 
2701   @return Converted VGA color
2702 
2703 **/
2704 UINT8
VgaConvertColor(IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer)2705 VgaConvertColor (
2706   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL          *BltBuffer
2707   )
2708 {
2709   UINT8 Color;
2710 
2711   Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
2712   if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
2713     Color |= 0x08;
2714   }
2715 
2716   return Color;
2717 }
2718 
2719 
2720 /**
2721   Grahpics Output protocol instance to block transfer for VGA device.
2722 
2723   @param  This                   Pointer to Grahpics Output protocol instance
2724   @param  BltBuffer              The data to transfer to screen
2725   @param  BltOperation           The operation to perform
2726   @param  SourceX                The X coordinate of the source for BltOperation
2727   @param  SourceY                The Y coordinate of the source for BltOperation
2728   @param  DestinationX           The X coordinate of the destination for
2729                                  BltOperation
2730   @param  DestinationY           The Y coordinate of the destination for
2731                                  BltOperation
2732   @param  Width                  The width of a rectangle in the blt rectangle in
2733                                  pixels
2734   @param  Height                 The height of a rectangle in the blt rectangle in
2735                                  pixels
2736   @param  Delta                  Not used for EfiBltVideoFill and
2737                                  EfiBltVideoToVideo operation. If a Delta of 0 is
2738                                  used, the entire BltBuffer will be operated on. If
2739                                  a subrectangle of the BltBuffer is used, then
2740                                  Delta represents the number of bytes in a row of
2741                                  the BltBuffer.
2742 
2743   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
2744   @retval EFI_SUCCESS            Blt operation success
2745 
2746 **/
2747 EFI_STATUS
2748 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)2749 BiosVideoGraphicsOutputVgaBlt (
2750   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,
2751   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
2752   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
2753   IN  UINTN                              SourceX,
2754   IN  UINTN                              SourceY,
2755   IN  UINTN                              DestinationX,
2756   IN  UINTN                              DestinationY,
2757   IN  UINTN                              Width,
2758   IN  UINTN                              Height,
2759   IN  UINTN                              Delta
2760   )
2761 {
2762   BIOS_VIDEO_DEV      *BiosVideoPrivate;
2763   EFI_TPL             OriginalTPL;
2764   UINT8               *MemAddress;
2765   UINTN               BytesPerScanLine;
2766   UINTN               Bit;
2767   UINTN               Index;
2768   UINTN               Index1;
2769   UINTN               StartAddress;
2770   UINTN               Bytes;
2771   UINTN               Offset;
2772   UINT8               LeftMask;
2773   UINT8               RightMask;
2774   UINTN               Address;
2775   UINTN               AddressFix;
2776   UINT8               *Address1;
2777   UINT8               *SourceAddress;
2778   UINT8               *DestinationAddress;
2779   EFI_PCI_IO_PROTOCOL *PciIo;
2780   UINT8               Data;
2781   UINT8               PixelColor;
2782   UINT8               *VgaFrameBuffer;
2783   UINTN               SourceOffset;
2784   UINTN               SourceWidth;
2785   UINTN               Rows;
2786   UINTN               Columns;
2787   UINTN               CoordinateX;
2788   UINTN               CoordinateY;
2789   UINTN               CurrentMode;
2790 
2791   if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2792     return EFI_INVALID_PARAMETER;
2793   }
2794 
2795   BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2796 
2797   CurrentMode = This->Mode->Mode;
2798   PciIo             = BiosVideoPrivate->PciIo;
2799   MemAddress        = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
2800   BytesPerScanLine  = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
2801   VgaFrameBuffer    = BiosVideoPrivate->VgaFrameBuffer;
2802 
2803 
2804   if (Width == 0 || Height == 0) {
2805     return EFI_INVALID_PARAMETER;
2806   }
2807   //
2808   // We need to fill the Virtual Screen buffer with the blt data.
2809   // The virtual screen is upside down, as the first row is the bootom row of
2810   // the image.
2811   //
2812   if (BltOperation == EfiBltVideoToBltBuffer) {
2813     //
2814     // Video to BltBuffer: Source is Video, destination is BltBuffer
2815     //
2816     if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2817       return EFI_INVALID_PARAMETER;
2818     }
2819 
2820     if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2821       return EFI_INVALID_PARAMETER;
2822     }
2823   } else {
2824     //
2825     // BltBuffer to Video: Source is BltBuffer, destination is Video
2826     //
2827     if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2828       return EFI_INVALID_PARAMETER;
2829     }
2830 
2831     if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2832       return EFI_INVALID_PARAMETER;
2833     }
2834   }
2835   //
2836   // If Delta is zero, then the entire BltBuffer is being used, so Delta
2837   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
2838   // the number of bytes in each row can be computed.
2839   //
2840   if (Delta == 0) {
2841     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2842   }
2843   //
2844   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2845   // We would not want a timer based event (Cursor, ...) to come in while we are
2846   // doing this operation.
2847   //
2848   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2849 
2850   //
2851   // Compute some values we need for VGA
2852   //
2853   switch (BltOperation) {
2854   case EfiBltVideoToBltBuffer:
2855 
2856     SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2857     SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2858 
2859     //
2860     // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2861     //
2862     VgaReadBitPlanes (
2863       PciIo,
2864       MemAddress + SourceOffset,
2865       VgaFrameBuffer + SourceOffset,
2866       SourceWidth,
2867       Height
2868       );
2869 
2870     //
2871     // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2872     //
2873     BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2874     for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {
2875       for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {
2876         VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);
2877       }
2878 
2879       BltBuffer -= Width;
2880     }
2881 
2882     break;
2883 
2884   case EfiBltVideoToVideo:
2885     //
2886     // Check for an aligned Video to Video operation
2887     //
2888     if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2889       //
2890       // Program the Mode Register Write mode 1, Read mode 0
2891       //
2892       WriteGraphicsController (
2893         PciIo,
2894         VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2895         VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2896         );
2897 
2898       SourceAddress       = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2899       DestinationAddress  = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2900       Bytes               = Width >> 3;
2901       for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2902         PciIo->CopyMem (
2903                 PciIo,
2904                 EfiPciIoWidthUint8,
2905                 EFI_PCI_IO_PASS_THROUGH_BAR,
2906                 (UINT64) (UINTN) (DestinationAddress + Offset),
2907                 EFI_PCI_IO_PASS_THROUGH_BAR,
2908                 (UINT64) (UINTN) (SourceAddress + Offset),
2909                 Bytes
2910                 );
2911       }
2912     } else {
2913       SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2914       SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2915 
2916       //
2917       // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2918       //
2919       VgaReadBitPlanes (
2920         PciIo,
2921         MemAddress + SourceOffset,
2922         VgaFrameBuffer + SourceOffset,
2923         SourceWidth,
2924         Height
2925         );
2926     }
2927 
2928     break;
2929 
2930   case EfiBltVideoFill:
2931     StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2932     Bytes         = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2933     LeftMask      = mVgaLeftMaskTable[DestinationX & 0x07];
2934     RightMask     = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2935     if (Bytes == 0) {
2936       LeftMask = (UINT8) (LeftMask & RightMask);
2937       RightMask = 0;
2938     }
2939 
2940     if (LeftMask == 0xff) {
2941       StartAddress--;
2942       Bytes++;
2943       LeftMask = 0;
2944     }
2945 
2946     if (RightMask == 0xff) {
2947       Bytes++;
2948       RightMask = 0;
2949     }
2950 
2951     PixelColor = VgaConvertColor (BltBuffer);
2952 
2953     //
2954     // Program the Mode Register Write mode 2, Read mode 0
2955     //
2956     WriteGraphicsController (
2957       PciIo,
2958       VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2959       VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2960       );
2961 
2962     //
2963     // Program the Data Rotate/Function Select Register to replace
2964     //
2965     WriteGraphicsController (
2966       PciIo,
2967       VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2968       VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2969       );
2970 
2971     if (LeftMask != 0) {
2972       //
2973       // Program the BitMask register with the Left column mask
2974       //
2975       WriteGraphicsController (
2976         PciIo,
2977         VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2978         LeftMask
2979         );
2980 
2981       for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2982         //
2983         // Read data from the bit planes into the latches
2984         //
2985         PciIo->Mem.Read (
2986                     PciIo,
2987                     EfiPciIoWidthUint8,
2988                     EFI_PCI_IO_PASS_THROUGH_BAR,
2989                     (UINT64) (UINTN) Address,
2990                     1,
2991                     &Data
2992                     );
2993         //
2994         // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2995         //
2996         PciIo->Mem.Write (
2997                     PciIo,
2998                     EfiPciIoWidthUint8,
2999                     EFI_PCI_IO_PASS_THROUGH_BAR,
3000                     (UINT64) (UINTN) Address,
3001                     1,
3002                     &PixelColor
3003                     );
3004       }
3005     }
3006 
3007     if (Bytes > 1) {
3008       //
3009       // Program the BitMask register with the middle column mask of 0xff
3010       //
3011       WriteGraphicsController (
3012         PciIo,
3013         VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3014         0xff
3015         );
3016 
3017       for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
3018         PciIo->Mem.Write (
3019                     PciIo,
3020                     EfiPciIoWidthFillUint8,
3021                     EFI_PCI_IO_PASS_THROUGH_BAR,
3022                     (UINT64) (UINTN) Address,
3023                     Bytes - 1,
3024                     &PixelColor
3025                     );
3026       }
3027     }
3028 
3029     if (RightMask != 0) {
3030       //
3031       // Program the BitMask register with the Right column mask
3032       //
3033       WriteGraphicsController (
3034         PciIo,
3035         VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3036         RightMask
3037         );
3038 
3039       for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
3040         //
3041         // Read data from the bit planes into the latches
3042         //
3043         PciIo->Mem.Read (
3044                     PciIo,
3045                     EfiPciIoWidthUint8,
3046                     EFI_PCI_IO_PASS_THROUGH_BAR,
3047                     (UINT64) (UINTN) Address,
3048                     1,
3049                     &Data
3050                     );
3051         //
3052         // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3053         //
3054         PciIo->Mem.Write (
3055                     PciIo,
3056                     EfiPciIoWidthUint8,
3057                     EFI_PCI_IO_PASS_THROUGH_BAR,
3058                     (UINT64) (UINTN) Address,
3059                     1,
3060                     &PixelColor
3061                     );
3062       }
3063     }
3064     break;
3065 
3066   case EfiBltBufferToVideo:
3067     StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
3068     LeftMask      = mVgaBitMaskTable[DestinationX & 0x07];
3069 
3070     //
3071     // Program the Mode Register Write mode 2, Read mode 0
3072     //
3073     WriteGraphicsController (
3074       PciIo,
3075       VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
3076       VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3077       );
3078 
3079     //
3080     // Program the Data Rotate/Function Select Register to replace
3081     //
3082     WriteGraphicsController (
3083       PciIo,
3084       VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
3085       VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3086       );
3087 
3088     for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
3089       for (Index1 = 0; Index1 < Width; Index1++) {
3090         BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
3091       }
3092       AddressFix = Address;
3093 
3094       for (Bit = 0; Bit < 8; Bit++) {
3095         //
3096         // Program the BitMask register with the Left column mask
3097         //
3098         WriteGraphicsController (
3099           PciIo,
3100           VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3101           LeftMask
3102           );
3103 
3104         for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
3105           //
3106           // Read data from the bit planes into the latches
3107           //
3108           PciIo->Mem.Read (
3109                       PciIo,
3110                       EfiPciIoWidthUint8,
3111                       EFI_PCI_IO_PASS_THROUGH_BAR,
3112                       (UINT64) (UINTN) Address1,
3113                       1,
3114                       &Data
3115                       );
3116 
3117           PciIo->Mem.Write (
3118                       PciIo,
3119                       EfiPciIoWidthUint8,
3120                       EFI_PCI_IO_PASS_THROUGH_BAR,
3121                       (UINT64) (UINTN) Address1,
3122                       1,
3123                       &BiosVideoPrivate->LineBuffer[Index1]
3124                       );
3125         }
3126 
3127         LeftMask = (UINT8) (LeftMask >> 1);
3128         if (LeftMask == 0) {
3129           LeftMask = 0x80;
3130           AddressFix++;
3131         }
3132       }
3133     }
3134 
3135     break;
3136 
3137     default: ;
3138   }
3139 
3140   gBS->RestoreTPL (OriginalTPL);
3141 
3142   return EFI_SUCCESS;
3143 }
3144 
3145 //
3146 // VGA Mini Port Protocol Functions
3147 //
3148 
3149 /**
3150   VgaMiniPort protocol interface to set mode.
3151 
3152   @param  This                   Pointer to VgaMiniPort protocol instance
3153   @param  ModeNumber             The index of the mode
3154 
3155   @retval EFI_UNSUPPORTED        The requested mode is not supported
3156   @retval EFI_SUCCESS            The requested mode is set successfully
3157 
3158 **/
3159 EFI_STATUS
3160 EFIAPI
BiosVideoVgaMiniPortSetMode(IN EFI_VGA_MINI_PORT_PROTOCOL * This,IN UINTN ModeNumber)3161 BiosVideoVgaMiniPortSetMode (
3162   IN  EFI_VGA_MINI_PORT_PROTOCOL  *This,
3163   IN  UINTN                       ModeNumber
3164   )
3165 {
3166   BIOS_VIDEO_DEV        *BiosVideoPrivate;
3167   EFI_IA32_REGISTER_SET Regs;
3168 
3169   if (This == NULL) {
3170     return EFI_INVALID_PARAMETER;
3171   }
3172 
3173   //
3174   // Make sure the ModeNumber is a valid value
3175   //
3176   if (ModeNumber >= This->MaxMode) {
3177     return EFI_UNSUPPORTED;
3178   }
3179   //
3180   // Get the device structure for this device
3181   //
3182   BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
3183 
3184   switch (ModeNumber) {
3185   case 0:
3186     //
3187     // Set the 80x25 Text VGA Mode
3188     //
3189     Regs.H.AH = 0x00;
3190     Regs.H.AL = 0x83;
3191     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3192 
3193     Regs.H.AH = 0x11;
3194     Regs.H.AL = 0x14;
3195     Regs.H.BL = 0;
3196     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3197     break;
3198 
3199   case 1:
3200     //
3201     // Set the 80x50 Text VGA Mode
3202     //
3203     Regs.H.AH = 0x00;
3204     Regs.H.AL = 0x83;
3205     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3206     Regs.H.AH = 0x11;
3207     Regs.H.AL = 0x12;
3208     Regs.H.BL = 0;
3209     BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3210     break;
3211 
3212   default:
3213     return EFI_UNSUPPORTED;
3214   }
3215 
3216   return EFI_SUCCESS;
3217 }
3218 
3219 /**
3220   Event handler for Exit Boot Service.
3221 
3222   @param  Event       The event that be siganlled when exiting boot service.
3223   @param  Context     Pointer to instance of BIOS_VIDEO_DEV.
3224 
3225 **/
3226 VOID
3227 EFIAPI
BiosVideoNotifyExitBootServices(IN EFI_EVENT Event,IN VOID * Context)3228 BiosVideoNotifyExitBootServices (
3229   IN  EFI_EVENT Event,
3230   IN  VOID      *Context
3231   )
3232 {
3233   BIOS_VIDEO_DEV         *BiosVideoPrivate;
3234   EFI_IA32_REGISTER_SET  Regs;
3235 
3236   BiosVideoPrivate  = (BIOS_VIDEO_DEV *)Context;
3237 
3238   //
3239   // Set the 80x25 Text VGA Mode
3240   //
3241   Regs.H.AH = 0x00;
3242   Regs.H.AL = 0x03;
3243   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3244 
3245   Regs.H.AH = 0x00;
3246   Regs.H.AL = 0x83;
3247   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3248 
3249   Regs.H.AH = 0x11;
3250   Regs.H.AL = 0x04;
3251   Regs.H.BL = 0;
3252   BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3253 }
3254 
3255 /**
3256   The user Entry Point for module UefiBiosVideo. The user code starts with this function.
3257 
3258   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
3259   @param[in] SystemTable    A pointer to the EFI System Table.
3260 
3261   @retval EFI_SUCCESS       The entry point is executed successfully.
3262   @retval other             Some error occurs when executing this entry point.
3263 
3264 **/
3265 EFI_STATUS
3266 EFIAPI
BiosVideoEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)3267 BiosVideoEntryPoint(
3268   IN EFI_HANDLE           ImageHandle,
3269   IN EFI_SYSTEM_TABLE     *SystemTable
3270   )
3271 {
3272   EFI_STATUS  Status;
3273 
3274   //
3275   // Install driver model protocol(s).
3276   //
3277   Status = EfiLibInstallDriverBindingComponentName2 (
3278              ImageHandle,
3279              SystemTable,
3280              &gBiosVideoDriverBinding,
3281              ImageHandle,
3282              &gBiosVideoComponentName,
3283              &gBiosVideoComponentName2
3284              );
3285   ASSERT_EFI_ERROR (Status);
3286 
3287   //
3288   // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
3289   //
3290   return gBS->InstallMultipleProtocolInterfaces (
3291                 &ImageHandle,
3292                 &gEfiLegacyBiosGuid,
3293                 NULL,
3294                 NULL
3295                 );
3296 }
3297 
3298