--- /dev/null
+/** @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