]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
OvmfPkg: Copy the required CSM components from framework packages
[mirror_edk2.git] / OvmfPkg / Csm / BiosThunk / VideoDxe / BiosVideo.c
diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
new file mode 100644 (file)
index 0000000..0640656
--- /dev/null
@@ -0,0 +1,3289 @@
+/** @file\r
+  ConsoleOut Routines that speak VGA.\r
+\r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "BiosVideo.h"\r
+\r
+//\r
+// EFI Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {\r
+  BiosVideoDriverBindingSupported,\r
+  BiosVideoDriverBindingStart,\r
+  BiosVideoDriverBindingStop,\r
+  0x3,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Global lookup tables for VGA graphics modes\r
+//\r
+UINT8                          mVgaLeftMaskTable[]   = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };\r
+\r
+UINT8                          mVgaRightMaskTable[]  = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };\r
+\r
+UINT8                          mVgaBitMaskTable[]    = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };\r
+\r
+//\r
+// Save controller attributes during first start\r
+//\r
+UINT64                         mOriginalPciAttributes;\r
+BOOLEAN                        mPciAttributesSaved = FALSE;\r
+\r
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL  mVgaColorToGraphicsOutputColor[] = {\r
+  { 0x00, 0x00, 0x00, 0x00 },\r
+  { 0x98, 0x00, 0x00, 0x00 },\r
+  { 0x00, 0x98, 0x00, 0x00 },\r
+  { 0x98, 0x98, 0x00, 0x00 },\r
+  { 0x00, 0x00, 0x98, 0x00 },\r
+  { 0x98, 0x00, 0x98, 0x00 },\r
+  { 0x00, 0x98, 0x98, 0x00 },\r
+  { 0x98, 0x98, 0x98, 0x00 },\r
+  { 0x10, 0x10, 0x10, 0x00 },\r
+  { 0xff, 0x10, 0x10, 0x00 },\r
+  { 0x10, 0xff, 0x10, 0x00 },\r
+  { 0xff, 0xff, 0x10, 0x00 },\r
+  { 0x10, 0x10, 0xff, 0x00 },\r
+  { 0xf0, 0x10, 0xff, 0x00 },\r
+  { 0x10, 0xff, 0xff, 0x00 },\r
+  { 0xff, 0xff, 0xff, 0x00 }\r
+};\r
+\r
+//\r
+// Standard timing defined by VESA EDID\r
+//\r
+VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = {\r
+  //\r
+  // Established Timing I\r
+  //\r
+  {800, 600, 60},\r
+  {800, 600, 56},\r
+  {640, 480, 75},\r
+  {640, 480, 72},\r
+  {640, 480, 67},\r
+  {640, 480, 60},\r
+  {720, 400, 88},\r
+  {720, 400, 70},\r
+  //\r
+  // Established Timing II\r
+  //\r
+  {1280, 1024, 75},\r
+  {1024,  768, 75},\r
+  {1024,  768, 70},\r
+  {1024,  768, 60},\r
+  {1024,  768, 87},\r
+  {832,   624, 75},\r
+  {800,   600, 75},\r
+  {800,   600, 72},\r
+  //\r
+  // Established Timing III\r
+  //\r
+  {1152, 870, 75}\r
+};\r
+\r
+/**\r
+  Supported.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  RemainingDevicePath    A pointer to the remaining portion of a device\r
+                                 path\r
+\r
+  @retval EFI_STATUS             EFI_SUCCESS:This controller can be managed by this\r
+                                 driver, Otherwise, this controller cannot be\r
+                                 managed by this driver\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                Pci;\r
+  EFI_DEV_PATH              *Node;\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    //\r
+    // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,\r
+    // because VgaMiniPort protocol is installed on controller handle directly.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiVgaMiniPortProtocolGuid,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+  //\r
+  // See if this is a PCI Graphics Controller by looking at the Command register and\r
+  // Class Code Register\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        0,\r
+                        sizeof (Pci) / sizeof (UINT32),\r
+                        &Pci\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+  if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {\r
+\r
+    Status = EFI_SUCCESS;\r
+    //\r
+    // If this is a graphics controller,\r
+    // go further check RemainingDevicePath validation\r
+    //\r
+    if (RemainingDevicePath != NULL) {\r
+      Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+      //\r
+      // Check if RemainingDevicePath is the End of Device Path Node,\r
+      // if yes, return EFI_SUCCESS\r
+      //\r
+      if (!IsDevicePathEnd (Node)) {\r
+        //\r
+        // If RemainingDevicePath isn't the End of Device Path Node,\r
+        // check its validation\r
+        //\r
+        if (Node->DevPath.Type != ACPI_DEVICE_PATH ||\r
+            Node->DevPath.SubType != ACPI_ADR_DP ||\r
+            DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {\r
+          Status = EFI_UNSUPPORTED;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+Done:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Install Graphics Output Protocol onto VGA device handles.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  RemainingDevicePath    A pointer to the remaining portion of a device\r
+                                 path\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Flags;\r
+  UINT64                    Supports;\r
+\r
+  //\r
+  // Initialize local variables\r
+  //\r
+  PciIo            = NULL;\r
+  ParentDevicePath = NULL;\r
+\r
+  //\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Prepare for status code\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Save original PCI attributes\r
+  //\r
+  if (!mPciAttributesSaved) {\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationGet,\r
+                      0,\r
+                      &mOriginalPciAttributes\r
+                      );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    mPciAttributesSaved = TRUE;\r
+  }\r
+\r
+  //\r
+  // Get supported PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
+  if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,\r
+    ParentDevicePath\r
+    );\r
+  //\r
+  // Enable the device and make sure VGA cycles are being forwarded to this VGA device\r
+  //\r
+  Status = PciIo->Attributes (\r
+             PciIo,\r
+             EfiPciIoAttributeOperationEnable,\r
+             EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,\r
+      ParentDevicePath\r
+      );\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check to see if there is a legacy option ROM image associated with this PCI device\r
+  //\r
+  Status = LegacyBios->CheckPciRom (\r
+                         LegacyBios,\r
+                         Controller,\r
+                         NULL,\r
+                         NULL,\r
+                         &Flags\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Post the legacy option ROM if it is available.\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_P_PC_RESET,\r
+    ParentDevicePath\r
+    );\r
+  Status = LegacyBios->InstallPciRom (\r
+                         LegacyBios,\r
+                         Controller,\r
+                         NULL,\r
+                         &Flags,\r
+                         NULL,\r
+                         NULL,\r
+                         NULL,\r
+                         NULL\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,\r
+      ParentDevicePath\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (RemainingDevicePath != NULL) {\r
+    if (IsDevicePathEnd (RemainingDevicePath) &&\r
+        (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) {\r
+      //\r
+      // If RemainingDevicePath is the End of Device Path Node,\r
+      // don't create any child device and return EFI_SUCESS\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create child handle and install GraphicsOutputProtocol on it\r
+  //\r
+  Status = BiosVideoChildHandleInstall (\r
+             This,\r
+             Controller,\r
+             PciIo,\r
+             LegacyBios,\r
+             ParentDevicePath,\r
+             RemainingDevicePath\r
+             );\r
+\r
+Done:\r
+  if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,\r
+      ParentDevicePath\r
+      );\r
+\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,\r
+      ParentDevicePath\r
+      );\r
+    if (!HasChildHandle (Controller)) {\r
+      if (mPciAttributesSaved) {\r
+        //\r
+        // Restore original PCI attributes\r
+        //\r
+        PciIo->Attributes (\r
+                        PciIo,\r
+                        EfiPciIoAttributeOperationSet,\r
+                        mOriginalPciAttributes,\r
+                        NULL\r
+                        );\r
+      }\r
+    }\r
+    //\r
+    // Release PCI I/O Protocols on the controller handle.\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  NumberOfChildren       Number of children handle created by this driver\r
+  @param  ChildHandleBuffer      Buffer containing child handle created\r
+\r
+  @retval EFI_SUCCESS            Driver disconnected successfully from controller\r
+  @retval EFI_UNSUPPORTED        Cannot find BIOS_VIDEO_DEV structure\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  BOOLEAN                      AllChildrenStopped;\r
+  UINTN                        Index;\r
+  EFI_PCI_IO_PROTOCOL          *PciIo;\r
+\r
+  AllChildrenStopped = TRUE;\r
+\r
+  if (NumberOfChildren == 0) {\r
+    //\r
+    // Close PCI I/O protocol on the controller handle\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+    Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+    }\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (!HasChildHandle (Controller)) {\r
+    if (mPciAttributesSaved) {\r
+      Status = gBS->HandleProtocol (\r
+                      Controller,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &PciIo\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      //\r
+      // Restore original PCI attributes\r
+      //\r
+      Status = PciIo->Attributes (\r
+                        PciIo,\r
+                        EfiPciIoAttributeOperationSet,\r
+                        mOriginalPciAttributes,\r
+                        NULL\r
+                        );\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  }\r
+\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Install child handles if the Handle supports MBR format.\r
+\r
+  @param  This                   Calling context.\r
+  @param  ParentHandle           Parent Handle\r
+  @param  ParentPciIo            Parent PciIo interface\r
+  @param  ParentLegacyBios       Parent LegacyBios interface\r
+  @param  ParentDevicePath       Parent Device Path\r
+  @param  RemainingDevicePath    Remaining Device Path\r
+\r
+  @retval EFI_SUCCESS            If a child handle was added\r
+  @retval other                  A child handle was not added\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoChildHandleInstall (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ParentHandle,\r
+  IN  EFI_PCI_IO_PROTOCOL          *ParentPciIo,\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL     *ParentLegacyBios,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  BIOS_VIDEO_DEV           *BiosVideoPrivate;\r
+  PCI_TYPE00               Pci;\r
+  ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;\r
+  BOOLEAN                  ProtocolInstalled;\r
+\r
+  //\r
+  // Allocate the private device structure for video device\r
+  //\r
+  BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool (\r
+                                          sizeof (BIOS_VIDEO_DEV)\r
+                                          );\r
+  if (NULL == BiosVideoPrivate) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // See if this is a VGA compatible controller or not\r
+  //\r
+  Status = ParentPciIo->Pci.Read (\r
+                          ParentPciIo,\r
+                          EfiPciIoWidthUint32,\r
+                          0,\r
+                          sizeof (Pci) / sizeof (UINT32),\r
+                          &Pci\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,\r
+      ParentDevicePath\r
+      );\r
+    goto Done;\r
+  }\r
+  BiosVideoPrivate->VgaCompatible = FALSE;\r
+  if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) {\r
+    BiosVideoPrivate->VgaCompatible = TRUE;\r
+  }\r
+\r
+  if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) {\r
+    BiosVideoPrivate->VgaCompatible = TRUE;\r
+  }\r
+\r
+ if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {\r
+    //\r
+    // Create EXIT_BOOT_SERIVES Event\r
+    //\r
+    Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    BiosVideoNotifyExitBootServices,\r
+                    BiosVideoPrivate,\r
+                    &gEfiEventExitBootServicesGuid,\r
+                    &BiosVideoPrivate->ExitBootServicesEvent\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Initialize the child private structure\r
+  //\r
+  BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;\r
+\r
+  //\r
+  // Fill in Graphics Output specific mode structures\r
+  //\r
+  BiosVideoPrivate->HardwareNeedsStarting = TRUE;\r
+  BiosVideoPrivate->ModeData              = NULL;\r
+  BiosVideoPrivate->LineBuffer            = NULL;\r
+  BiosVideoPrivate->VgaFrameBuffer        = NULL;\r
+  BiosVideoPrivate->VbeFrameBuffer        = NULL;\r
+\r
+  //\r
+  // Fill in the Graphics Output Protocol\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;\r
+  BiosVideoPrivate->GraphicsOutput.SetMode   = BiosVideoGraphicsOutputSetMode;\r
+\r
+\r
+  //\r
+  // Allocate buffer for Graphics Output Protocol mode information\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (\r
+                                             sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)\r
+                                             );\r
+  if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (\r
+                                             sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)\r
+                                             );\r
+  if (NULL ==  BiosVideoPrivate->GraphicsOutput.Mode->Info) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Assume that Graphics Output Protocol will be produced until proven otherwise\r
+  //\r
+  BiosVideoPrivate->ProduceGraphicsOutput = TRUE;\r
+\r
+  //\r
+  // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.\r
+  //\r
+  if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {\r
+    if (RemainingDevicePath == NULL) {\r
+      ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
+      AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
+      AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
+      AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
+      SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
+\r
+      BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (\r
+                                          ParentDevicePath,\r
+                                          (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
+                                          );\r
+    } else {\r
+      BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);\r
+    }\r
+\r
+    //\r
+    // Creat child handle and device path protocol firstly\r
+    //\r
+    BiosVideoPrivate->Handle = NULL;\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &BiosVideoPrivate->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    BiosVideoPrivate->GopDevicePath,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Fill in the VGA Mini Port Protocol fields\r
+  //\r
+  BiosVideoPrivate->VgaMiniPort.SetMode                   = BiosVideoVgaMiniPortSetMode;\r
+  BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset           = 0xb8000;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset    = 0x3d5;\r
+  BiosVideoPrivate->VgaMiniPort.VgaMemoryBar              = EFI_PCI_IO_PASS_THROUGH_BAR;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar    = EFI_PCI_IO_PASS_THROUGH_BAR;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar       = EFI_PCI_IO_PASS_THROUGH_BAR;\r
+\r
+  //\r
+  // Child handle need to consume the Legacy Bios protocol\r
+  //\r
+  BiosVideoPrivate->LegacyBios = ParentLegacyBios;\r
+\r
+  //\r
+  // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally\r
+  //\r
+  BiosVideoPrivate->PciIo                 = ParentPciIo;\r
+\r
+  //\r
+  // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output\r
+  //\r
+  if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) {\r
+    Status = BiosVideoCheckForVbe (BiosVideoPrivate);\r
+    DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status));\r
+  } else {\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support\r
+    // for the standard 640x480 16 color VGA mode\r
+    //\r
+    DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible));\r
+    if (BiosVideoPrivate->VgaCompatible) {\r
+      if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) {\r
+        Status = BiosVideoCheckForVga (BiosVideoPrivate);\r
+        DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status));\r
+      } else {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Free GOP mode structure if it is not freed before\r
+      // VgaMiniPort does not need this structure any more\r
+      //\r
+      if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {\r
+        if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {\r
+          FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);\r
+          BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;\r
+        }\r
+        FreePool (BiosVideoPrivate->GraphicsOutput.Mode);\r
+        BiosVideoPrivate->GraphicsOutput.Mode = NULL;\r
+      }\r
+\r
+      //\r
+      // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do\r
+      // not produce the Graphics Output protocol.  Instead, produce the VGA MiniPort Protocol.\r
+      //\r
+      BiosVideoPrivate->ProduceGraphicsOutput = FALSE;\r
+\r
+      //\r
+      // INT services are available, so on the 80x25 and 80x50 text mode are supported\r
+      //\r
+      BiosVideoPrivate->VgaMiniPort.MaxMode = 2;\r
+    }\r
+  }\r
+\r
+  ProtocolInstalled = FALSE;\r
+\r
+  if (BiosVideoPrivate->ProduceGraphicsOutput) {\r
+    //\r
+    // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &BiosVideoPrivate->Handle,\r
+                    &gEfiGraphicsOutputProtocolGuid,\r
+                    &BiosVideoPrivate->GraphicsOutput,\r
+                    &gEfiEdidDiscoveredProtocolGuid,\r
+                    &BiosVideoPrivate->EdidDiscovered,\r
+                    &gEfiEdidActiveProtocolGuid,\r
+                    &BiosVideoPrivate->EdidActive,\r
+                    NULL\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Open the Parent Handle for the child\r
+      //\r
+      Status = gBS->OpenProtocol (\r
+                      ParentHandle,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &BiosVideoPrivate->PciIo,\r
+                      This->DriverBindingHandle,\r
+                      BiosVideoPrivate->Handle,\r
+                      EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      ProtocolInstalled = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!ProtocolInstalled) {\r
+    //\r
+    // Install VGA Mini Port Protocol\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &ParentHandle,\r
+                    &gEfiVgaMiniPortProtocolGuid,\r
+                    &BiosVideoPrivate->VgaMiniPort,\r
+                    NULL\r
+                    );\r
+  }\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) {\r
+      gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);\r
+    }\r
+    //\r
+    // Free private data structure\r
+    //\r
+    BiosVideoDeviceReleaseResource (BiosVideoPrivate);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Deregister an video child handle and free resources.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Controller             Video controller handle\r
+  @param  Handle                 Video child handle\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoChildHandleUninstall (\r
+  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  EFI_HANDLE                     Controller,\r
+  EFI_HANDLE                     Handle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_IA32_REGISTER_SET        Regs;\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+  EFI_VGA_MINI_PORT_PROTOCOL   *VgaMiniPort;\r
+  BIOS_VIDEO_DEV               *BiosVideoPrivate;\r
+  EFI_PCI_IO_PROTOCOL          *PciIo;\r
+\r
+  BiosVideoPrivate = NULL;\r
+  GraphicsOutput   = NULL;\r
+  PciIo            = NULL;\r
+  Status           = EFI_UNSUPPORTED;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiGraphicsOutputProtocolGuid,\r
+                  (VOID **) &GraphicsOutput,\r
+                  This->DriverBindingHandle,\r
+                  Handle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+      BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                   Handle,\r
+                   &gEfiVgaMiniPortProtocolGuid,\r
+                   (VOID **) &VgaMiniPort,\r
+                   This->DriverBindingHandle,\r
+                   Handle,\r
+                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                   );\r
+    if (!EFI_ERROR (Status)) {\r
+      BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);\r
+    }\r
+  }\r
+\r
+  if (BiosVideoPrivate == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Set the 80x25 Text VGA Mode\r
+  //\r
+  Regs.H.AH = 0x00;\r
+  Regs.H.AL = 0x03;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Regs.H.AH = 0x11;\r
+  Regs.H.AL = 0x14;\r
+  Regs.H.BL = 0;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  //\r
+  // Close PCI I/O protocol that opened by child handle\r
+  //\r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Handle\r
+                  );\r
+\r
+  //\r
+  // Uninstall protocols on child handle\r
+  //\r
+  if (BiosVideoPrivate->ProduceGraphicsOutput) {\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    BiosVideoPrivate->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    BiosVideoPrivate->GopDevicePath,\r
+                    &gEfiGraphicsOutputProtocolGuid,\r
+                    &BiosVideoPrivate->GraphicsOutput,\r
+                    &gEfiEdidDiscoveredProtocolGuid,\r
+                    &BiosVideoPrivate->EdidDiscovered,\r
+                    &gEfiEdidActiveProtocolGuid,\r
+                    &BiosVideoPrivate->EdidActive,\r
+                    NULL\r
+                    );\r
+  }\r
+  if (!BiosVideoPrivate->ProduceGraphicsOutput) {\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    Controller,\r
+                    &gEfiVgaMiniPortProtocolGuid,\r
+                    &BiosVideoPrivate->VgaMiniPort,\r
+                    NULL\r
+                    );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->OpenProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           (VOID **) &PciIo,\r
+           This->DriverBindingHandle,\r
+           Handle,\r
+           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+           );\r
+    return Status;\r
+  }\r
+\r
+  if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {\r
+    //\r
+    // Close EXIT_BOOT_SERIVES Event\r
+    //\r
+    gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);\r
+  }\r
+\r
+  //\r
+  // Release all allocated resources\r
+  //\r
+  BiosVideoDeviceReleaseResource (BiosVideoPrivate);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Release resource for biso video instance.\r
+\r
+  @param  BiosVideoPrivate       Video child device private data structure\r
+\r
+**/\r
+VOID\r
+BiosVideoDeviceReleaseResource (\r
+  BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  )\r
+{\r
+  if (BiosVideoPrivate == NULL) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Release all the resourses occupied by the BIOS_VIDEO_DEV\r
+  //\r
+\r
+  //\r
+  // Free VGA Frame Buffer\r
+  //\r
+  if (BiosVideoPrivate->VgaFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VgaFrameBuffer);\r
+  }\r
+  //\r
+  // Free VBE Frame Buffer\r
+  //\r
+  if (BiosVideoPrivate->VbeFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VbeFrameBuffer);\r
+  }\r
+  //\r
+  // Free line buffer\r
+  //\r
+  if (BiosVideoPrivate->LineBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->LineBuffer);\r
+  }\r
+  //\r
+  // Free mode data\r
+  //\r
+  if (BiosVideoPrivate->ModeData != NULL) {\r
+    FreePool (BiosVideoPrivate->ModeData);\r
+  }\r
+  //\r
+  // Free memory allocated below 1MB\r
+  //\r
+  if (BiosVideoPrivate->PagesBelow1MB != 0) {\r
+    gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);\r
+  }\r
+\r
+  if (BiosVideoPrivate->VbeSaveRestorePages != 0) {\r
+    gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);\r
+  }\r
+\r
+  //\r
+  // Free graphics output protocol occupied resource\r
+  //\r
+  if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {\r
+    if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {\r
+        FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);\r
+        BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;\r
+    }\r
+    FreePool (BiosVideoPrivate->GraphicsOutput.Mode);\r
+    BiosVideoPrivate->GraphicsOutput.Mode = NULL;\r
+  }\r
+  //\r
+  // Free EDID discovered protocol occupied resource\r
+  //\r
+  if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {\r
+    FreePool (BiosVideoPrivate->EdidDiscovered.Edid);\r
+  }\r
+  //\r
+  // Free EDID active protocol occupied resource\r
+  //\r
+  if (BiosVideoPrivate->EdidActive.Edid != NULL) {\r
+    FreePool (BiosVideoPrivate->EdidActive.Edid);\r
+  }\r
+\r
+  if (BiosVideoPrivate->GopDevicePath!= NULL) {\r
+    FreePool (BiosVideoPrivate->GopDevicePath);\r
+  }\r
+\r
+  FreePool (BiosVideoPrivate);\r
+\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Generate a search key for a specified timing data.\r
+\r
+  @param  EdidTiming             Pointer to EDID timing\r
+\r
+  @return The 32 bit unique key for search.\r
+\r
+**/\r
+UINT32\r
+CalculateEdidKey (\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING       *EdidTiming\r
+  )\r
+{\r
+  UINT32 Key;\r
+\r
+  //\r
+  // Be sure no conflicts for all standard timing defined by VESA.\r
+  //\r
+  Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;\r
+  return Key;\r
+}\r
+\r
+\r
+/**\r
+  Parse the Established Timing and Standard Timing in EDID data block.\r
+\r
+  @param  EdidBuffer             Pointer to EDID data block\r
+  @param  ValidEdidTiming        Valid EDID timing information\r
+\r
+  @retval TRUE                   The EDID data is valid.\r
+  @retval FALSE                  The EDID data is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+ParseEdidData (\r
+  UINT8                                      *EdidBuffer,\r
+  VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING     *ValidEdidTiming\r
+  )\r
+{\r
+  UINT8  CheckSum;\r
+  UINT32 Index;\r
+  UINT32 ValidNumber;\r
+  UINT32 TimingBits;\r
+  UINT8  *BufferIndex;\r
+  UINT16 HorizontalResolution;\r
+  UINT16 VerticalResolution;\r
+  UINT8  AspectRatio;\r
+  UINT8  RefreshRate;\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING     TempTiming;\r
+  VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;\r
+\r
+  EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;\r
+\r
+  //\r
+  // Check the checksum of EDID data\r
+  //\r
+  CheckSum = 0;\r
+  for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {\r
+    CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);\r
+  }\r
+  if (CheckSum != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  ValidNumber = 0;\r
+  gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);\r
+\r
+  if ((EdidDataBlock->EstablishedTimings[0] != 0) ||\r
+      (EdidDataBlock->EstablishedTimings[1] != 0) ||\r
+      (EdidDataBlock->EstablishedTimings[2] != 0)\r
+      ) {\r
+    //\r
+    // Established timing data\r
+    //\r
+    TimingBits = EdidDataBlock->EstablishedTimings[0] |\r
+                 (EdidDataBlock->EstablishedTimings[1] << 8) |\r
+                 ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;\r
+    for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {\r
+      if ((TimingBits & 0x1) != 0) {\r
+        DEBUG ((EFI_D_INFO, "Established Timing: %d x %d\n",\r
+        mEstablishedEdidTiming[Index].HorizontalResolution, mEstablishedEdidTiming[Index].VerticalResolution));\r
+        ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);\r
+        ValidNumber ++;\r
+      }\r
+      TimingBits = TimingBits >> 1;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Parse the standard timing data\r
+  //\r
+  BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];\r
+  for (Index = 0; Index < 8; Index ++) {\r
+    //\r
+    // Check if this is a valid Standard Timing entry\r
+    // VESA documents unused fields should be set to 01h\r
+    //\r
+    if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){\r
+      //\r
+      // A valid Standard Timing\r
+      //\r
+      HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);\r
+      AspectRatio = (UINT8) (BufferIndex[1] >> 6);\r
+      switch (AspectRatio) {\r
+        case 0:\r
+          VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);\r
+          break;\r
+        case 1:\r
+          VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
+          break;\r
+        case 2:\r
+          VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);\r
+          break;\r
+        case 3:\r
+          VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);\r
+          break;\r
+        default:\r
+          VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
+          break;\r
+      }\r
+      RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);\r
+      DEBUG ((EFI_D_INFO, "Standard Timing: %d x %d\n", HorizontalResolution, VerticalResolution));\r
+      TempTiming.HorizontalResolution = HorizontalResolution;\r
+      TempTiming.VerticalResolution = VerticalResolution;\r
+      TempTiming.RefreshRate = RefreshRate;\r
+      ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);\r
+      ValidNumber ++;\r
+    }\r
+    BufferIndex += 2;\r
+  }\r
+\r
+  //\r
+  // Parse the Detailed Timing data\r
+  //\r
+  BufferIndex = &EdidDataBlock->DetailedTimingDescriptions[0];\r
+  for (Index = 0; Index < 4; Index ++, BufferIndex += VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE) {\r
+    if ((BufferIndex[0] == 0x0) && (BufferIndex[1] == 0x0)) {\r
+      //\r
+      // Check if this is a valid Detailed Timing Descriptor\r
+      // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor\r
+      //\r
+      continue;\r
+    }\r
+    //\r
+    // Calculate Horizontal and Vertical resolution\r
+    //\r
+    TempTiming.HorizontalResolution = ((UINT16)(BufferIndex[4] & 0xF0) << 4) | (BufferIndex[2]);\r
+    TempTiming.VerticalResolution = ((UINT16)(BufferIndex[7] & 0xF0) << 4) | (BufferIndex[5]);\r
+    DEBUG ((EFI_D_INFO, "Detailed Timing %d: %d x %d\n",\r
+            Index, TempTiming.HorizontalResolution, TempTiming.VerticalResolution));\r
+    ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);\r
+    ValidNumber ++;\r
+  }\r
+\r
+  ValidEdidTiming->ValidNumber = ValidNumber;\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Search a specified Timing in all the valid EDID timings.\r
+\r
+  @param  ValidEdidTiming        All valid EDID timing information.\r
+  @param  EdidTiming             The Timing to search for.\r
+\r
+  @retval TRUE                   Found.\r
+  @retval FALSE                  Not found.\r
+\r
+**/\r
+BOOLEAN\r
+SearchEdidTiming (\r
+  VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING       *EdidTiming\r
+  )\r
+{\r
+  UINT32 Index;\r
+  UINT32 Key;\r
+\r
+  Key = CalculateEdidKey (EdidTiming);\r
+\r
+  for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {\r
+    if (Key == ValidEdidTiming->Key[Index]) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check if all video child handles have been uninstalled.\r
+\r
+  @param  Controller             Video controller handle\r
+\r
+  @return TRUE                   Child handles exist.\r
+  @return FALSE                  All video child handles have been uninstalled.\r
+\r
+**/\r
+BOOLEAN\r
+HasChildHandle (\r
+  IN EFI_HANDLE  Controller\r
+  )\r
+{\r
+  UINTN                                Index;\r
+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;\r
+  UINTN                                EntryCount;\r
+  BOOLEAN                              HasChild;\r
+\r
+  EntryCount = 0;\r
+  HasChild   = FALSE;\r
+  gBS->OpenProtocolInformation (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         &OpenInfoBuffer,\r
+         &EntryCount\r
+         );\r
+  for (Index = 0; Index < EntryCount; Index++) {\r
+    if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+      HasChild = TRUE;\r
+    }\r
+  }\r
+\r
+  return HasChild;\r
+}\r
+\r
+/**\r
+  Check for VBE device.\r
+\r
+  @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure\r
+\r
+  @retval EFI_SUCCESS            VBE device found\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoCheckForVbe (\r
+  IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  )\r
+{\r
+  EFI_STATUS                             Status;\r
+  EFI_IA32_REGISTER_SET                  Regs;\r
+  UINT16                                 *ModeNumberPtr;\r
+  UINT16                                 VbeModeNumber;\r
+  BOOLEAN                                ModeFound;\r
+  BOOLEAN                                EdidFound;\r
+  BIOS_VIDEO_MODE_DATA                   *ModeBuffer;\r
+  BIOS_VIDEO_MODE_DATA                   *CurrentModeData;\r
+  UINTN                                  PreferMode;\r
+  UINTN                                  ModeNumber;\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING       Timing;\r
+  VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;\r
+  EFI_EDID_OVERRIDE_PROTOCOL             *EdidOverride;\r
+  UINT32                                 EdidAttributes;\r
+  BOOLEAN                                EdidOverrideFound;\r
+  UINTN                                  EdidOverrideDataSize;\r
+  UINT8                                  *EdidOverrideDataBlock;\r
+  UINTN                                  EdidActiveDataSize;\r
+  UINT8                                  *EdidActiveDataBlock;\r
+  UINT32                                 HighestHorizontalResolution;\r
+  UINT32                                 HighestVerticalResolution;\r
+  UINTN                                  HighestResolutionMode;\r
+\r
+  EdidFound             = TRUE;\r
+  EdidOverrideFound     = FALSE;\r
+  EdidOverrideDataBlock = NULL;\r
+  EdidActiveDataSize    = 0;\r
+  EdidActiveDataBlock   = NULL;\r
+  HighestHorizontalResolution = 0;\r
+  HighestVerticalResolution   = 0;\r
+  HighestResolutionMode       = 0;\r
+\r
+  //\r
+  // Allocate buffer under 1MB for VBE data structures\r
+  //\r
+  BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)\r
+                                              );\r
+\r
+  BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;\r
+\r
+  Status = gBS->AllocatePages (\r
+                  AllocateMaxAddress,\r
+                  EfiBootServicesData,\r
+                  BiosVideoPrivate->NumberOfPagesBelow1MB,\r
+                  &BiosVideoPrivate->PagesBelow1MB\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));\r
+\r
+  //\r
+  // Fill in the VBE related data structures\r
+  //\r
+  BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);\r
+  BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);\r
+  BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);\r
+  BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);\r
+  BiosVideoPrivate->VbeSaveRestorePages   = 0;\r
+  BiosVideoPrivate->VbeSaveRestoreBuffer  = 0;\r
+\r
+  //\r
+  // Test to see if the Video Adapter is compliant with VBE 3.0\r
+  //\r
+  gBS->SetMem (&Regs, sizeof (Regs), 0);\r
+  Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;\r
+  gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);\r
+  BiosVideoPrivate->VbeInformationBlock->VESASignature  = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;\r
+  Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);\r
+  Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);\r
+\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  //\r
+  // See if the VESA call succeeded\r
+  //\r
+  if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check for 'VESA' signature\r
+  //\r
+  if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check to see if this is VBE 2.0 or higher\r
+  //\r
+  if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {\r
+    return Status;\r
+  }\r
+\r
+  EdidFound            = FALSE;\r
+  EdidAttributes       = 0xff;\r
+  EdidOverrideDataSize = 0;\r
+\r
+  //\r
+  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                   &gEfiEdidOverrideProtocolGuid,\r
+                   NULL,\r
+                   (VOID **) &EdidOverride\r
+                   );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow\r
+    //\r
+    EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);\r
+    if (NULL == EdidOverrideDataBlock) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    Status = EdidOverride->GetEdid (\r
+                             EdidOverride,\r
+                             BiosVideoPrivate->Handle,\r
+                             &EdidAttributes,\r
+                             &EdidOverrideDataSize,\r
+                             (UINT8 **) &EdidOverrideDataBlock\r
+                             );\r
+    if (!EFI_ERROR (Status)  &&\r
+         EdidAttributes == 0 &&\r
+         EdidOverrideDataSize != 0) {\r
+      //\r
+      // Succeeded to get EDID Override Data\r
+      //\r
+      EdidOverrideFound = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {\r
+    //\r
+    // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,\r
+    // read EDID information through INT10 call\r
+    //\r
+\r
+    gBS->SetMem (&Regs, sizeof (Regs), 0);\r
+    Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;\r
+    Regs.X.BX = 1;\r
+    Regs.X.CX = 0;\r
+    Regs.X.DX = 0;\r
+    Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);\r
+    Regs.X.DI = EFI_OFFSET  ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);\r
+\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    //\r
+    // See if the VESA call succeeded\r
+    //\r
+    if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+      //\r
+      // Set EDID Discovered Data\r
+      //\r
+      BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;\r
+       BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (\r
+                                                          VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,\r
+                                                          BiosVideoPrivate->VbeEdidDataBlock\r
+                                                           );\r
+\r
+      if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {\r
+         Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+\r
+      EdidFound = TRUE;\r
+    }\r
+  }\r
+\r
+  if (EdidFound) {\r
+    EdidActiveDataSize  = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;\r
+    EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;\r
+  } else if (EdidOverrideFound) {\r
+    EdidActiveDataSize  = EdidOverrideDataSize;\r
+    EdidActiveDataBlock = EdidOverrideDataBlock;\r
+    EdidFound = TRUE;\r
+   }\r
+\r
+   if (EdidFound) {\r
+    //\r
+    // Parse EDID data structure to retrieve modes supported by monitor\r
+    //\r
+    if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {\r
+      //\r
+      // Copy EDID Override Data to EDID Active Data\r
+      //\r
+      BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;\r
+      BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (\r
+                                                      EdidActiveDataSize,\r
+                                                      EdidActiveDataBlock\r
+                                                      );\r
+      if (NULL ==  BiosVideoPrivate->EdidActive.Edid) {\r
+         Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+    }\r
+  } else {\r
+    BiosVideoPrivate->EdidActive.SizeOfEdid = 0;\r
+    BiosVideoPrivate->EdidActive.Edid = NULL;\r
+    EdidFound = FALSE;\r
+  }\r
+\r
+  //\r
+  // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode\r
+  //\r
+  ModeNumberPtr = (UINT16 *)\r
+    (\r
+      (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |\r
+        ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)\r
+    );\r
+\r
+  PreferMode = 0;\r
+  ModeNumber = 0;\r
+\r
+  //\r
+  // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.\r
+  //\r
+  for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);\r
+       VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;\r
+       VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {\r
+    //\r
+    // Make sure this is a mode number defined by the VESA VBE specification.  If it isn'tm then skip this mode number.\r
+    //\r
+    if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // Get the information about the mode\r
+    //\r
+    gBS->SetMem (&Regs, sizeof (Regs), 0);\r
+    Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;\r
+    Regs.X.CX = VbeModeNumber;\r
+    gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);\r
+    Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);\r
+    Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);\r
+\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+    //\r
+    // See if the call succeeded.  If it didn't, then try the next mode.\r
+    //\r
+    if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports color.  If it doesn't then try the next mode.\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports graphics.  If it doesn't then try the next mode.\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports a linear frame buffer.  If it doesn't then try the next mode.\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports 32 bit color.  If it doesn't then try the next mode.\r
+    // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the\r
+    // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel\r
+    //\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {\r
+      continue;\r
+    }\r
+\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {\r
+      continue;\r
+    }\r
+\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the physical base pointer for the linear mode is valid.  If it isn't then try the next mode.\r
+    //\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",\r
+            VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));\r
+\r
+    if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {\r
+      //\r
+      // EDID exist, check whether this mode match with any mode in EDID\r
+      //\r
+      Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
+      Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
+      if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {\r
+        //\r
+        // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,\r
+        // but INT10 can support these modes, we add them into GOP mode.\r
+        //\r
+        if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&\r
+            !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&\r
+            !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&\r
+            !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {\r
+        continue;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Select a reasonable mode to be set for current display mode\r
+    //\r
+    ModeFound = FALSE;\r
+\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&\r
+        BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768\r
+        ) {\r
+      ModeFound = TRUE;\r
+    }\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&\r
+        BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600\r
+        ) {\r
+      ModeFound = TRUE;\r
+      PreferMode = ModeNumber;\r
+    }\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&\r
+        BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480\r
+        ) {\r
+      ModeFound = TRUE;\r
+    }\r
+\r
+    if ((!EdidFound) && (!ModeFound)) {\r
+      //\r
+      // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480\r
+      //\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Record the highest resolution mode to set later\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||\r
+        ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) &&\r
+         (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {\r
+      HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
+      HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
+      HighestResolutionMode = ModeNumber;\r
+    }\r
+\r
+    //\r
+    // Add mode to the list of available modes\r
+    //\r
+    ModeNumber ++;\r
+    ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (\r
+                                            ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)\r
+                                            );\r
+    if (NULL == ModeBuffer) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    if (ModeNumber > 1) {\r
+      CopyMem (\r
+        ModeBuffer,\r
+        BiosVideoPrivate->ModeData,\r
+        (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)\r
+        );\r
+    }\r
+\r
+    if (BiosVideoPrivate->ModeData != NULL) {\r
+      FreePool (BiosVideoPrivate->ModeData);\r
+    }\r
+\r
+    CurrentModeData = &ModeBuffer[ModeNumber - 1];\r
+    CurrentModeData->VbeModeNumber = VbeModeNumber;\r
+    if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {\r
+      CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;\r
+      CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;\r
+      CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);\r
+      CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;\r
+      CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);\r
+      CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;\r
+      CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);\r
+      CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;\r
+      CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);\r
+    } else {\r
+      CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;\r
+      CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;\r
+      CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);\r
+      CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;\r
+      CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);\r
+      CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;\r
+      CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);\r
+      CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;\r
+      CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);\r
+    }\r
+\r
+    CurrentModeData->PixelFormat = PixelBitMask;\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&\r
+        (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {\r
+      if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {\r
+        CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;\r
+      } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {\r
+        CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;\r
+      }\r
+    }\r
+\r
+    CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;\r
+    CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;\r
+    CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;\r
+    CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;\r
+\r
+    CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;\r
+    CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
+    CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
+\r
+    CurrentModeData->BitsPerPixel  = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;\r
+    CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;\r
+    //\r
+    // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.\r
+    //\r
+    ASSERT (CurrentModeData->FrameBufferSize <= ((UINT32)BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));\r
+\r
+    BiosVideoPrivate->ModeData = ModeBuffer;\r
+  }\r
+  //\r
+  // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT\r
+  //\r
+  if (ModeNumber == 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Assign Gop's Blt function\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVbeBlt;\r
+\r
+  BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;\r
+  //\r
+  // Current mode is unknow till now, set it to an invalid mode.\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;\r
+\r
+  //\r
+  // Find the best mode to initialize\r
+  //\r
+  if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {\r
+    DEBUG_CODE (\r
+      BIOS_VIDEO_MODE_DATA    *ModeData;\r
+      ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];\r
+      DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",\r
+              ModeData->HorizontalResolution, ModeData->VerticalResolution));\r
+    );\r
+    PreferMode = HighestResolutionMode;\r
+  }\r
+  Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);\r
+  if (EFI_ERROR (Status)) {\r
+    for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {\r
+      Status = BiosVideoGraphicsOutputSetMode (\r
+                &BiosVideoPrivate->GraphicsOutput,\r
+                (UINT32) PreferMode\r
+                );\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    }\r
+    if (PreferMode == ModeNumber) {\r
+      //\r
+      // None mode is set successfully.\r
+      //\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+Done:\r
+  //\r
+  // If there was an error, then free the mode structure\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    if (BiosVideoPrivate->ModeData != NULL) {\r
+      FreePool (BiosVideoPrivate->ModeData);\r
+      BiosVideoPrivate->ModeData  = NULL;\r
+      BiosVideoPrivate->MaxMode   = 0;\r
+    }\r
+    if (EdidOverrideDataBlock != NULL) {\r
+      FreePool (EdidOverrideDataBlock);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Check for VGA device.\r
+\r
+  @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure\r
+\r
+  @retval EFI_SUCCESS            Standard VGA device found\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoCheckForVga (\r
+  IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  BIOS_VIDEO_MODE_DATA  *ModeBuffer;\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  //\r
+  // Assign Gop's Blt function\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVgaBlt;\r
+\r
+  //\r
+  // Add mode to the list of available modes\r
+  // caller should guarantee that Mode has been allocated.\r
+  //\r
+  ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);\r
+  BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;\r
+\r
+  ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (\r
+                                          sizeof (BIOS_VIDEO_MODE_DATA)\r
+                                          );\r
+  if (NULL == ModeBuffer) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  ModeBuffer->VbeModeNumber         = 0x0012;\r
+  ModeBuffer->BytesPerScanLine      = 640;\r
+  ModeBuffer->LinearFrameBuffer     = (VOID *) (UINTN) (0xa0000);\r
+  ModeBuffer->HorizontalResolution  = 640;\r
+  ModeBuffer->VerticalResolution    = 480;\r
+  ModeBuffer->PixelFormat           = PixelBltOnly;\r
+  ModeBuffer->BitsPerPixel          = 8;\r
+  ModeBuffer->ColorDepth            = 32;\r
+  ModeBuffer->RefreshRate           = 60;\r
+\r
+  BiosVideoPrivate->ModeData = ModeBuffer;\r
+\r
+  //\r
+  // Test to see if the Video Adapter support the 640x480 16 color mode\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;\r
+  Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);\r
+\r
+Done:\r
+  //\r
+  // If there was an error, then free the mode structure\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    if (BiosVideoPrivate->ModeData != NULL) {\r
+      FreePool (BiosVideoPrivate->ModeData);\r
+      BiosVideoPrivate->ModeData = NULL;\r
+    }\r
+    if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {\r
+      if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {\r
+        FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);\r
+        BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;\r
+      }\r
+      FreePool (BiosVideoPrivate->GraphicsOutput.Mode);\r
+      BiosVideoPrivate->GraphicsOutput.Mode = NULL;\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+//\r
+// Graphics Output Protocol Member Functions for VESA BIOS Extensions\r
+//\r
+\r
+/**\r
+  Graphics Output protocol interface to get video mode.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ModeNumber             The mode number to return information on.\r
+  @param  SizeOfInfo             A pointer to the size, in bytes, of the Info\r
+                                 buffer.\r
+  @param  Info                   Caller allocated buffer that returns information\r
+                                 about ModeNumber.\r
+\r
+  @retval EFI_SUCCESS            Mode information returned.\r
+  @retval EFI_DEVICE_ERROR       A hardware error occurred trying to retrieve the\r
+                                 video mode.\r
+  @retval EFI_NOT_STARTED        Video display is not initialized. Call SetMode ()\r
+  @retval EFI_INVALID_PARAMETER  One of the input args was NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputQueryMode (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,\r
+  IN  UINT32                                ModeNumber,\r
+  OUT UINTN                                 *SizeOfInfo,\r
+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV        *BiosVideoPrivate;\r
+  BIOS_VIDEO_MODE_DATA  *ModeData;\r
+\r
+  BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+\r
+  if (BiosVideoPrivate->HardwareNeedsStarting) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,\r
+      BiosVideoPrivate->GopDevicePath\r
+      );\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (\r
+                                                    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)\r
+                                                    );\r
+  if (NULL == *Info) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+\r
+  ModeData = &BiosVideoPrivate->ModeData[ModeNumber];\r
+  (*Info)->Version = 0;\r
+  (*Info)->HorizontalResolution = ModeData->HorizontalResolution;\r
+  (*Info)->VerticalResolution   = ModeData->VerticalResolution;\r
+  (*Info)->PixelFormat = ModeData->PixelFormat;\r
+  CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));\r
+\r
+  (*Info)->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Worker function to set video mode.\r
+\r
+  @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV.\r
+  @param  ModeData               The mode data to be set.\r
+  @param  DevicePath             Pointer to Device Path Protocol.\r
+\r
+  @retval EFI_SUCCESS            Graphics mode was changed.\r
+  @retval EFI_DEVICE_ERROR       The device had an error and could not complete the\r
+                                 request.\r
+  @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoSetModeWorker (\r
+  IN  BIOS_VIDEO_DEV               *BiosVideoPrivate,\r
+  IN  BIOS_VIDEO_MODE_DATA         *ModeData,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_IA32_REGISTER_SET   Regs;\r
+\r
+  if (BiosVideoPrivate->LineBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->LineBuffer);\r
+  }\r
+\r
+  if (BiosVideoPrivate->VgaFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VgaFrameBuffer);\r
+  }\r
+\r
+  if (BiosVideoPrivate->VbeFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VbeFrameBuffer);\r
+  }\r
+\r
+  BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (\r
+                                             ModeData->BytesPerScanLine\r
+                                             );\r
+  if (NULL == BiosVideoPrivate->LineBuffer) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Clear all registers\r
+  //\r
+  ZeroMem (&Regs, sizeof (Regs));\r
+\r
+  if (ModeData->VbeModeNumber < 0x100) {\r
+    //\r
+    // Allocate a working buffer for BLT operations to the VGA frame buffer\r
+    //\r
+    BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);\r
+    if (NULL == BiosVideoPrivate->VgaFrameBuffer) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Set VGA Mode\r
+    //\r
+    Regs.X.AX = ModeData->VbeModeNumber;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  } else {\r
+    //\r
+    // Allocate a working buffer for BLT operations to the VBE frame buffer\r
+    //\r
+    BiosVideoPrivate->VbeFrameBuffer =\r
+      (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (\r
+                                          ModeData->BytesPerScanLine * ModeData->VerticalResolution\r
+                                          );\r
+    if (NULL == BiosVideoPrivate->VbeFrameBuffer) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Set VBE mode\r
+    //\r
+    Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;\r
+    Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);\r
+    ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));\r
+    Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);\r
+    Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+    //\r
+    // Check to see if the call succeeded\r
+    //\r
+    if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+      REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,\r
+        DevicePath\r
+        );\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // Initialize the state of the VbeFrameBuffer\r
+    //\r
+    Status = BiosVideoPrivate->PciIo->Mem.Read (\r
+                                            BiosVideoPrivate->PciIo,\r
+                                            EfiPciIoWidthUint32,\r
+                                            EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                                            (UINT64) (UINTN) ModeData->LinearFrameBuffer,\r
+                                            (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,\r
+                                            BiosVideoPrivate->VbeFrameBuffer\r
+                                            );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Graphics Output protocol interface to set video mode.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ModeNumber             The mode number to be set.\r
+\r
+  @retval EFI_SUCCESS            Graphics mode was changed.\r
+  @retval EFI_DEVICE_ERROR       The device had an error and could not complete the\r
+                                 request.\r
+  @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputSetMode (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,\r
+  IN  UINT32                       ModeNumber\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BIOS_VIDEO_DEV          *BiosVideoPrivate;\r
+  BIOS_VIDEO_MODE_DATA    *ModeData;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+\r
+  ModeData = &BiosVideoPrivate->ModeData[ModeNumber];\r
+\r
+  if (ModeNumber >= This->Mode->MaxMode) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (ModeNumber == This->Mode->Mode) {\r
+    //\r
+    // Clear screen to black\r
+    //\r
+    ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+    BiosVideoGraphicsOutputVbeBlt (\r
+                        This,\r
+                        &Background,\r
+                        EfiBltVideoFill,\r
+                        0,\r
+                        0,\r
+                        0,\r
+                        0,\r
+                        ModeData->HorizontalResolution,\r
+                        ModeData->VerticalResolution,\r
+                        0\r
+    );\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  This->Mode->Mode = ModeNumber;\r
+  This->Mode->Info->Version = 0;\r
+  This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;\r
+  This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;\r
+  This->Mode->Info->PixelFormat = ModeData->PixelFormat;\r
+  CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));\r
+  This->Mode->Info->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;\r
+  This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+  This->Mode->FrameBufferSize = ModeData->FrameBufferSize;\r
+  This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;\r
+\r
+  BiosVideoPrivate->HardwareNeedsStarting = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.\r
+\r
+  @param   PciIo              The pointer of EFI_PCI_IO_PROTOCOL\r
+  @param   VbeBuffer          The data to transfer to screen\r
+  @param   MemAddress         Physical frame buffer base address\r
+  @param   DestinationX       The X coordinate of the destination for BltOperation\r
+  @param   DestinationY       The Y coordinate of the destination for BltOperation\r
+  @param   TotalBytes         The total bytes of copy\r
+  @param   VbePixelWidth      Bytes per pixel\r
+  @param   BytesPerScanLine   Bytes per scan line\r
+\r
+**/\r
+VOID\r
+CopyVideoBuffer (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT8                 *VbeBuffer,\r
+  IN  VOID                  *MemAddress,\r
+  IN  UINTN                 DestinationX,\r
+  IN  UINTN                 DestinationY,\r
+  IN  UINTN                 TotalBytes,\r
+  IN  UINT32                VbePixelWidth,\r
+  IN  UINTN                 BytesPerScanLine\r
+  )\r
+{\r
+  UINTN                 FrameBufferAddr;\r
+  UINTN                 CopyBlockNum;\r
+  UINTN                 RemainingBytes;\r
+  UINTN                 UnalignedBytes;\r
+  EFI_STATUS            Status;\r
+\r
+  FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;\r
+\r
+  //\r
+  // If TotalBytes is less than 4 bytes, only start byte copy.\r
+  //\r
+  if (TotalBytes < 4) {\r
+    Status = PciIo->Mem.Write (\r
+                     PciIo,\r
+                     EfiPciIoWidthUint8,\r
+                     EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                     (UINT64) FrameBufferAddr,\r
+                     TotalBytes,\r
+                     VbeBuffer\r
+                     );\r
+    ASSERT_EFI_ERROR (Status);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // If VbeBuffer is not 4-byte aligned, start byte copy.\r
+  //\r
+  UnalignedBytes  = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;\r
+\r
+  if (UnalignedBytes != 0) {\r
+    Status = PciIo->Mem.Write (\r
+                     PciIo,\r
+                     EfiPciIoWidthUint8,\r
+                     EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                     (UINT64) FrameBufferAddr,\r
+                     UnalignedBytes,\r
+                     VbeBuffer\r
+                     );\r
+    ASSERT_EFI_ERROR (Status);\r
+    FrameBufferAddr += UnalignedBytes;\r
+    VbeBuffer       += UnalignedBytes;\r
+  }\r
+\r
+  //\r
+  // Calculate 4-byte block count and remaining bytes.\r
+  //\r
+  CopyBlockNum   = (TotalBytes - UnalignedBytes) >> 2;\r
+  RemainingBytes = (TotalBytes - UnalignedBytes) &  3;\r
+\r
+  //\r
+  // Copy 4-byte block and remaining bytes to physical frame buffer.\r
+  //\r
+  if (CopyBlockNum != 0) {\r
+    Status = PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint32,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) FrameBufferAddr,\r
+                    CopyBlockNum,\r
+                    VbeBuffer\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (RemainingBytes != 0) {\r
+    FrameBufferAddr += (CopyBlockNum << 2);\r
+    VbeBuffer       += (CopyBlockNum << 2);\r
+    Status = PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) FrameBufferAddr,\r
+                    RemainingBytes,\r
+                    VbeBuffer\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
+/**\r
+  Worker function to block transfer for VBE device.\r
+\r
+  @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+  @param  Mode                   Mode data.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoVbeBltWorker (\r
+  IN  BIOS_VIDEO_DEV                     *BiosVideoPrivate,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta,\r
+  IN  BIOS_VIDEO_MODE_DATA               *Mode\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL            *PciIo;\r
+  EFI_TPL                        OriginalTPL;\r
+  UINTN                          DstY;\r
+  UINTN                          SrcY;\r
+  UINTN                          DstX;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *Blt;\r
+  VOID                           *MemAddress;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *VbeFrameBuffer;\r
+  UINTN                          BytesPerScanLine;\r
+  UINTN                          Index;\r
+  UINT8                          *VbeBuffer;\r
+  UINT8                          *VbeBuffer1;\r
+  UINT8                          *BltUint8;\r
+  UINT32                         VbePixelWidth;\r
+  UINT32                         Pixel;\r
+  UINTN                          TotalBytes;\r
+\r
+  PciIo             = BiosVideoPrivate->PciIo;\r
+\r
+  VbeFrameBuffer    = BiosVideoPrivate->VbeFrameBuffer;\r
+  MemAddress        = Mode->LinearFrameBuffer;\r
+  BytesPerScanLine  = Mode->BytesPerScanLine;\r
+  VbePixelWidth     = Mode->BitsPerPixel / 8;\r
+  BltUint8          = (UINT8 *) BltBuffer;\r
+  TotalBytes        = Width * VbePixelWidth;\r
+\r
+  if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Width == 0 || Height == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // We need to fill the Virtual Screen buffer with the blt data.\r
+  // The virtual screen is upside down, as the first row is the bootom row of\r
+  // the image.\r
+  //\r
+  if (BltOperation == EfiBltVideoToBltBuffer) {\r
+    //\r
+    // Video to BltBuffer: Source is Video, destination is BltBuffer\r
+    //\r
+    if (SourceY + Height > Mode->VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (SourceX + Width > Mode->HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // BltBuffer to Video: Source is BltBuffer, destination is Video\r
+    //\r
+    if (DestinationY + Height > Mode->VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (DestinationX + Width > Mode->HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // If Delta is zero, then the entire BltBuffer is being used, so Delta\r
+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,\r
+  // the number of bytes in each row can be computed.\r
+  //\r
+  if (Delta == 0) {\r
+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
+  }\r
+  //\r
+  // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
+  // We would not want a timer based event (Cursor, ...) to come in while we are\r
+  // doing this operation.\r
+  //\r
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  switch (BltOperation) {\r
+  case EfiBltVideoToBltBuffer:\r
+    for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {\r
+      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+      //\r
+      // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL\r
+      //\r
+      VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));\r
+      for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {\r
+        Pixel         = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;\r
+        Blt->Red      = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);\r
+        Blt->Blue     = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);\r
+        Blt->Green    = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);\r
+        Blt->Reserved = 0;\r
+        Blt++;\r
+        VbeBuffer += VbePixelWidth;\r
+      }\r
+\r
+    }\r
+    break;\r
+\r
+  case EfiBltVideoToVideo:\r
+    for (Index = 0; Index < Height; Index++) {\r
+      if (DestinationY <= SourceY) {\r
+        SrcY  = SourceY + Index;\r
+        DstY  = DestinationY + Index;\r
+      } else {\r
+        SrcY  = SourceY + Height - Index - 1;\r
+        DstY  = DestinationY + Height - Index - 1;\r
+      }\r
+\r
+      VbeBuffer   = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);\r
+      VbeBuffer1  = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);\r
+\r
+      gBS->CopyMem (\r
+            VbeBuffer,\r
+            VbeBuffer1,\r
+            TotalBytes\r
+            );\r
+\r
+      //\r
+      // Update physical frame buffer.\r
+      //\r
+      CopyVideoBuffer (\r
+        PciIo,\r
+        VbeBuffer,\r
+        MemAddress,\r
+        DestinationX,\r
+        DstY,\r
+        TotalBytes,\r
+        VbePixelWidth,\r
+        BytesPerScanLine\r
+        );\r
+    }\r
+    break;\r
+\r
+  case EfiBltVideoFill:\r
+    VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);\r
+    Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;\r
+    //\r
+    // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer\r
+    //\r
+    Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |\r
+      (\r
+        (Blt->Green & Mode->Green.Mask) <<\r
+        Mode->Green.Position\r
+      ) |\r
+          ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);\r
+\r
+    for (Index = 0; Index < Width; Index++) {\r
+      gBS->CopyMem (\r
+            VbeBuffer,\r
+            &Pixel,\r
+            VbePixelWidth\r
+            );\r
+      VbeBuffer += VbePixelWidth;\r
+    }\r
+\r
+    VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);\r
+    for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {\r
+      gBS->CopyMem (\r
+            (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),\r
+            VbeBuffer,\r
+            TotalBytes\r
+            );\r
+    }\r
+\r
+    for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {\r
+      //\r
+      // Update physical frame buffer.\r
+      //\r
+      CopyVideoBuffer (\r
+        PciIo,\r
+        VbeBuffer,\r
+        MemAddress,\r
+        DestinationX,\r
+        DstY,\r
+        TotalBytes,\r
+        VbePixelWidth,\r
+        BytesPerScanLine\r
+        );\r
+    }\r
+    break;\r
+\r
+  case EfiBltBufferToVideo:\r
+    for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {\r
+      Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+      VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));\r
+      for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {\r
+        //\r
+        // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer\r
+        //\r
+        Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |\r
+          ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |\r
+            ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);\r
+        gBS->CopyMem (\r
+              VbeBuffer,\r
+              &Pixel,\r
+              VbePixelWidth\r
+              );\r
+        Blt++;\r
+        VbeBuffer += VbePixelWidth;\r
+      }\r
+\r
+      VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));\r
+\r
+      //\r
+      // Update physical frame buffer.\r
+      //\r
+      CopyVideoBuffer (\r
+        PciIo,\r
+        VbeBuffer,\r
+        MemAddress,\r
+        DestinationX,\r
+        DstY,\r
+        TotalBytes,\r
+        VbePixelWidth,\r
+        BytesPerScanLine\r
+        );\r
+    }\r
+    break;\r
+\r
+    default: ;\r
+  }\r
+\r
+  gBS->RestoreTPL (OriginalTPL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Graphics Output protocol instance to block transfer for VBE device.\r
+\r
+  @param  This                   Pointer to Graphics Output protocol instance\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputVbeBlt (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV                 *BiosVideoPrivate;\r
+  BIOS_VIDEO_MODE_DATA           *Mode;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+  Mode              = &BiosVideoPrivate->ModeData[This->Mode->Mode];\r
+\r
+  return BiosVideoVbeBltWorker (\r
+           BiosVideoPrivate,\r
+           BltBuffer,\r
+           BltOperation,\r
+           SourceX,\r
+           SourceY,\r
+           DestinationX,\r
+           DestinationY,\r
+           Width,\r
+           Height,\r
+           Delta,\r
+           Mode\r
+           );\r
+}\r
+\r
+/**\r
+  Write graphics controller registers.\r
+\r
+  @param  PciIo                  Pointer to PciIo protocol instance of the\r
+                                 controller\r
+  @param  Address                Register address\r
+  @param  Data                   Data to be written to register\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+WriteGraphicsController (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  UINTN                Address,\r
+  IN  UINTN                Data\r
+  )\r
+{\r
+  Address = Address | (Data << 8);\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,\r
+              1,\r
+              &Address\r
+              );\r
+}\r
+\r
+\r
+/**\r
+  Read the four bit plane of VGA frame buffer.\r
+\r
+  @param  PciIo                  Pointer to PciIo protocol instance of the\r
+                                 controller\r
+  @param  HardwareBuffer         Hardware VGA frame buffer address\r
+  @param  MemoryBuffer           Memory buffer address\r
+  @param  WidthInBytes           Number of bytes in a line to read\r
+  @param  Height                 Height of the area to read\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+VgaReadBitPlanes (\r
+  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  UINT8                *HardwareBuffer,\r
+  UINT8                *MemoryBuffer,\r
+  UINTN                WidthInBytes,\r
+  UINTN                Height\r
+  )\r
+{\r
+  UINTN BitPlane;\r
+  UINTN Rows;\r
+  UINTN FrameBufferOffset;\r
+  UINT8 *Source;\r
+  UINT8 *Destination;\r
+\r
+  //\r
+  // Program the Mode Register Write mode 0, Read mode 0\r
+  //\r
+  WriteGraphicsController (\r
+    PciIo,\r
+    VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+    VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0\r
+    );\r
+\r
+  for (BitPlane = 0, FrameBufferOffset = 0;\r
+       BitPlane < VGA_NUMBER_OF_BIT_PLANES;\r
+       BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE\r
+      ) {\r
+    //\r
+    // Program the Read Map Select Register to select the correct bit plane\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,\r
+      BitPlane\r
+      );\r
+\r
+    Source      = HardwareBuffer;\r
+    Destination = MemoryBuffer + FrameBufferOffset;\r
+\r
+    for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {\r
+      PciIo->Mem.Read (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint8,\r
+                  EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                  (UINT64) (UINTN) Source,\r
+                  WidthInBytes,\r
+                  (VOID *) Destination\r
+                  );\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Internal routine to convert VGA color to Grahpics Output color.\r
+\r
+  @param  MemoryBuffer           Buffer containing VGA color\r
+  @param  CoordinateX            The X coordinate of pixel on screen\r
+  @param  CoordinateY            The Y coordinate of pixel on screen\r
+  @param  BltBuffer              Buffer to contain converted Grahpics Output color\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+VgaConvertToGraphicsOutputColor (\r
+  UINT8                          *MemoryBuffer,\r
+  UINTN                          CoordinateX,\r
+  UINTN                          CoordinateY,\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *BltBuffer\r
+  )\r
+{\r
+  UINTN Mask;\r
+  UINTN Bit;\r
+  UINTN Color;\r
+\r
+  MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));\r
+  Mask = mVgaBitMaskTable[CoordinateX & 0x07];\r
+  for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {\r
+    if ((*MemoryBuffer & Mask) != 0) {\r
+      Color |= Bit;\r
+    }\r
+  }\r
+\r
+  *BltBuffer = mVgaColorToGraphicsOutputColor[Color];\r
+}\r
+\r
+/**\r
+  Internal routine to convert Grahpics Output color to VGA color.\r
+\r
+  @param  BltBuffer              buffer containing Grahpics Output color\r
+\r
+  @return Converted VGA color\r
+\r
+**/\r
+UINT8\r
+VgaConvertColor (\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL          *BltBuffer\r
+  )\r
+{\r
+  UINT8 Color;\r
+\r
+  Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));\r
+  if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {\r
+    Color |= 0x08;\r
+  }\r
+\r
+  return Color;\r
+}\r
+\r
+\r
+/**\r
+  Grahpics Output protocol instance to block transfer for VGA device.\r
+\r
+  @param  This                   Pointer to Grahpics Output protocol instance\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputVgaBlt (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV      *BiosVideoPrivate;\r
+  EFI_TPL             OriginalTPL;\r
+  UINT8               *MemAddress;\r
+  UINTN               BytesPerScanLine;\r
+  UINTN               Bit;\r
+  UINTN               Index;\r
+  UINTN               Index1;\r
+  UINTN               StartAddress;\r
+  UINTN               Bytes;\r
+  UINTN               Offset;\r
+  UINT8               LeftMask;\r
+  UINT8               RightMask;\r
+  UINTN               Address;\r
+  UINTN               AddressFix;\r
+  UINT8               *Address1;\r
+  UINT8               *SourceAddress;\r
+  UINT8               *DestinationAddress;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINT8               Data;\r
+  UINT8               PixelColor;\r
+  UINT8               *VgaFrameBuffer;\r
+  UINTN               SourceOffset;\r
+  UINTN               SourceWidth;\r
+  UINTN               Rows;\r
+  UINTN               Columns;\r
+  UINTN               CoordinateX;\r
+  UINTN               CoordinateY;\r
+  UINTN               CurrentMode;\r
+\r
+  if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+\r
+  CurrentMode = This->Mode->Mode;\r
+  PciIo             = BiosVideoPrivate->PciIo;\r
+  MemAddress        = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;\r
+  BytesPerScanLine  = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;\r
+  VgaFrameBuffer    = BiosVideoPrivate->VgaFrameBuffer;\r
+\r
+\r
+  if (Width == 0 || Height == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // We need to fill the Virtual Screen buffer with the blt data.\r
+  // The virtual screen is upside down, as the first row is the bootom row of\r
+  // the image.\r
+  //\r
+  if (BltOperation == EfiBltVideoToBltBuffer) {\r
+    //\r
+    // Video to BltBuffer: Source is Video, destination is BltBuffer\r
+    //\r
+    if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // BltBuffer to Video: Source is BltBuffer, destination is Video\r
+    //\r
+    if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // If Delta is zero, then the entire BltBuffer is being used, so Delta\r
+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,\r
+  // the number of bytes in each row can be computed.\r
+  //\r
+  if (Delta == 0) {\r
+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
+  }\r
+  //\r
+  // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
+  // We would not want a timer based event (Cursor, ...) to come in while we are\r
+  // doing this operation.\r
+  //\r
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  //\r
+  // Compute some values we need for VGA\r
+  //\r
+  switch (BltOperation) {\r
+  case EfiBltVideoToBltBuffer:\r
+\r
+    SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);\r
+    SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;\r
+\r
+    //\r
+    // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer\r
+    //\r
+    VgaReadBitPlanes (\r
+      PciIo,\r
+      MemAddress + SourceOffset,\r
+      VgaFrameBuffer + SourceOffset,\r
+      SourceWidth,\r
+      Height\r
+      );\r
+\r
+    //\r
+    // Convert VGA Bit Planes to a Graphics Output 32-bit color value\r
+    //\r
+    BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);\r
+    for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {\r
+      for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {\r
+        VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);\r
+      }\r
+\r
+      BltBuffer -= Width;\r
+    }\r
+\r
+    break;\r
+\r
+  case EfiBltVideoToVideo:\r
+    //\r
+    // Check for an aligned Video to Video operation\r
+    //\r
+    if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {\r
+      //\r
+      // Program the Mode Register Write mode 1, Read mode 0\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+        VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1\r
+        );\r
+\r
+      SourceAddress       = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));\r
+      DestinationAddress  = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));\r
+      Bytes               = Width >> 3;\r
+      for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {\r
+        PciIo->CopyMem (\r
+                PciIo,\r
+                EfiPciIoWidthUint8,\r
+                EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                (UINT64) (UINTN) (DestinationAddress + Offset),\r
+                EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                (UINT64) (UINTN) (SourceAddress + Offset),\r
+                Bytes\r
+                );\r
+      }\r
+    } else {\r
+      SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);\r
+      SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;\r
+\r
+      //\r
+      // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer\r
+      //\r
+      VgaReadBitPlanes (\r
+        PciIo,\r
+        MemAddress + SourceOffset,\r
+        VgaFrameBuffer + SourceOffset,\r
+        SourceWidth,\r
+        Height\r
+        );\r
+    }\r
+\r
+    break;\r
+\r
+  case EfiBltVideoFill:\r
+    StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));\r
+    Bytes         = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);\r
+    LeftMask      = mVgaLeftMaskTable[DestinationX & 0x07];\r
+    RightMask     = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];\r
+    if (Bytes == 0) {\r
+      LeftMask = (UINT8) (LeftMask & RightMask);\r
+      RightMask = 0;\r
+    }\r
+\r
+    if (LeftMask == 0xff) {\r
+      StartAddress--;\r
+      Bytes++;\r
+      LeftMask = 0;\r
+    }\r
+\r
+    if (RightMask == 0xff) {\r
+      Bytes++;\r
+      RightMask = 0;\r
+    }\r
+\r
+    PixelColor = VgaConvertColor (BltBuffer);\r
+\r
+    //\r
+    // Program the Mode Register Write mode 2, Read mode 0\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2\r
+      );\r
+\r
+    //\r
+    // Program the Data Rotate/Function Select Register to replace\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE\r
+      );\r
+\r
+    if (LeftMask != 0) {\r
+      //\r
+      // Program the BitMask register with the Left column mask\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+        LeftMask\r
+        );\r
+\r
+      for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {\r
+        //\r
+        // Read data from the bit planes into the latches\r
+        //\r
+        PciIo->Mem.Read (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &Data\r
+                    );\r
+        //\r
+        // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask\r
+        //\r
+        PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &PixelColor\r
+                    );\r
+      }\r
+    }\r
+\r
+    if (Bytes > 1) {\r
+      //\r
+      // Program the BitMask register with the middle column mask of 0xff\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+        0xff\r
+        );\r
+\r
+      for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {\r
+        PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthFillUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    Bytes - 1,\r
+                    &PixelColor\r
+                    );\r
+      }\r
+    }\r
+\r
+    if (RightMask != 0) {\r
+      //\r
+      // Program the BitMask register with the Right column mask\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+        RightMask\r
+        );\r
+\r
+      for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {\r
+        //\r
+        // Read data from the bit planes into the latches\r
+        //\r
+        PciIo->Mem.Read (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &Data\r
+                    );\r
+        //\r
+        // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask\r
+        //\r
+        PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &PixelColor\r
+                    );\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EfiBltBufferToVideo:\r
+    StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));\r
+    LeftMask      = mVgaBitMaskTable[DestinationX & 0x07];\r
+\r
+    //\r
+    // Program the Mode Register Write mode 2, Read mode 0\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2\r
+      );\r
+\r
+    //\r
+    // Program the Data Rotate/Function Select Register to replace\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE\r
+      );\r
+\r
+    for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {\r
+      for (Index1 = 0; Index1 < Width; Index1++) {\r
+        BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);\r
+      }\r
+      AddressFix = Address;\r
+\r
+      for (Bit = 0; Bit < 8; Bit++) {\r
+        //\r
+        // Program the BitMask register with the Left column mask\r
+        //\r
+        WriteGraphicsController (\r
+          PciIo,\r
+          VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+          LeftMask\r
+          );\r
+\r
+        for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {\r
+          //\r
+          // Read data from the bit planes into the latches\r
+          //\r
+          PciIo->Mem.Read (\r
+                      PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      (UINT64) (UINTN) Address1,\r
+                      1,\r
+                      &Data\r
+                      );\r
+\r
+          PciIo->Mem.Write (\r
+                      PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      (UINT64) (UINTN) Address1,\r
+                      1,\r
+                      &BiosVideoPrivate->LineBuffer[Index1]\r
+                      );\r
+        }\r
+\r
+        LeftMask = (UINT8) (LeftMask >> 1);\r
+        if (LeftMask == 0) {\r
+          LeftMask = 0x80;\r
+          AddressFix++;\r
+        }\r
+      }\r
+    }\r
+\r
+    break;\r
+\r
+    default: ;\r
+  }\r
+\r
+  gBS->RestoreTPL (OriginalTPL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// VGA Mini Port Protocol Functions\r
+//\r
+\r
+/**\r
+  VgaMiniPort protocol interface to set mode.\r
+\r
+  @param  This                   Pointer to VgaMiniPort protocol instance\r
+  @param  ModeNumber             The index of the mode\r
+\r
+  @retval EFI_UNSUPPORTED        The requested mode is not supported\r
+  @retval EFI_SUCCESS            The requested mode is set successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoVgaMiniPortSetMode (\r
+  IN  EFI_VGA_MINI_PORT_PROTOCOL  *This,\r
+  IN  UINTN                       ModeNumber\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV        *BiosVideoPrivate;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Make sure the ModeNumber is a valid value\r
+  //\r
+  if (ModeNumber >= This->MaxMode) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Get the device structure for this device\r
+  //\r
+  BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);\r
+\r
+  switch (ModeNumber) {\r
+  case 0:\r
+    //\r
+    // Set the 80x25 Text VGA Mode\r
+    //\r
+    Regs.H.AH = 0x00;\r
+    Regs.H.AL = 0x83;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+    Regs.H.AH = 0x11;\r
+    Regs.H.AL = 0x14;\r
+    Regs.H.BL = 0;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    break;\r
+\r
+  case 1:\r
+    //\r
+    // Set the 80x50 Text VGA Mode\r
+    //\r
+    Regs.H.AH = 0x00;\r
+    Regs.H.AL = 0x83;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    Regs.H.AH = 0x11;\r
+    Regs.H.AL = 0x12;\r
+    Regs.H.BL = 0;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    break;\r
+\r
+  default:\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Event handler for Exit Boot Service.\r
+\r
+  @param  Event       The event that be siganlled when exiting boot service.\r
+  @param  Context     Pointer to instance of BIOS_VIDEO_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosVideoNotifyExitBootServices (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV         *BiosVideoPrivate;\r
+  EFI_IA32_REGISTER_SET  Regs;\r
+\r
+  BiosVideoPrivate  = (BIOS_VIDEO_DEV *)Context;\r
+\r
+  //\r
+  // Set the 80x25 Text VGA Mode\r
+  //\r
+  Regs.H.AH = 0x00;\r
+  Regs.H.AL = 0x03;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Regs.H.AH = 0x00;\r
+  Regs.H.AL = 0x83;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Regs.H.AH = 0x11;\r
+  Regs.H.AL = 0x04;\r
+  Regs.H.BL = 0;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+}\r
+\r
+/**\r
+  The user Entry Point for module UefiBiosVideo. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoEntryPoint(\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gBiosVideoDriverBinding,\r
+             ImageHandle,\r
+             &gBiosVideoComponentName,\r
+             &gBiosVideoComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver\r
+  //\r
+  return gBS->InstallMultipleProtocolInterfaces (\r
+                &ImageHandle,\r
+                &gEfiLegacyBiosGuid,\r
+                NULL,\r
+                NULL\r
+                );\r
+}\r
+\r