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