diff options
Diffstat (limited to 'Core/EM/CSM/thunk/CsmVideo/UefiBiosVideo.c')
-rw-r--r-- | Core/EM/CSM/thunk/CsmVideo/UefiBiosVideo.c | 3886 |
1 files changed, 3886 insertions, 0 deletions
diff --git a/Core/EM/CSM/thunk/CsmVideo/UefiBiosVideo.c b/Core/EM/CSM/thunk/CsmVideo/UefiBiosVideo.c new file mode 100644 index 0000000..ddbe46c --- /dev/null +++ b/Core/EM/CSM/thunk/CsmVideo/UefiBiosVideo.c @@ -0,0 +1,3886 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +/*++ + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement +--*/ +/*++ + +Copyright (c) 2006 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + BiosVideo.c + +Abstract: + + ConsoleOut Routines that speak VGA. + +Revision History + +--*/ + +//*** AMI PORTING BEGIN ***// +#include "AcpiRes.h" +//*** AMI PORTING END *****// +#include "UefiBiosVideo.h" + +#define TRACE_BIOS_VIDEO TRACE_ALWAYS +//#define TRACE_BIOS_VIDEO TRACE_NEVER + +// +// EFI Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = { + BiosVideoDriverBindingSupported, + BiosVideoDriverBindingStart, + BiosVideoDriverBindingStop, + 0x00000024, + NULL, + NULL +}; + +typedef struct _TEXT_MODE { + INT32 ModeNum; + INT32 Col; + INT32 Row; + UINT32 VideoCol; // horizontal pixels + UINT32 VideoRow; // vertical pixels +} TEXT_MODE; + +#if CORE_COMBINED_VERSION < 0x4028e +const TEXT_MODE TextModeArray[] = {GC_MODE_LIST}; +const INT32 MaxTextMode=(sizeof(TextModeArray)/sizeof(TEXT_MODE)); +#else +extern TEXT_MODE TextModeArray[]; +extern INT32 MaxTextMode; +#endif + +// remove the following line when Protocol/EdidOverride.h becomes available +EFI_GUID gEfiEdidOverrideProtocolGuid = EFI_EDID_OVERRIDE_PROTOCOL_GUID; + +//*** AMI PORTING BEGIN ***// +#if INT10_VGA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +// +// 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 }; + +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 } +}; + +//*** AMI PORTING BEGIN ***// +#endif //if INT10_VGA_GO_SUPPORT==1 +#if INT10_VESA_GO_SUPPORT==1 +//*** AMI PORTING END *****// + +// +// 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} +}; +//*** AMI PORTING BEGIN ***// +#endif //if INT10_VESA_GO_SUPPORT==1 +//*** AMI PORTING END *****// + +UINT32 SupportedResolutions[29] = { 0 }; + +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 +BiosVideoChildHandleUninstall ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + EFI_HANDLE Handle + ) +; + +VOID +BiosVideoDeviceReleaseResource ( + BIOS_VIDEO_DEV *BiosVideoPrivate + ) +; + +//*** AMI PORTING BEGIN ***// +//CsmVideo Policy Protocol support +//The protocol can be used to set the driver policy. +// The two supported policies are: +// SimpleTextOut over the text mode 3 (TextMode=TRUE) +// GOP over graphical mode (TextMode=FALSE) +EFI_HANDLE VgaControllerHandle = NULL; +BOOLEAN TextModePolicy = FALSE; + +EFI_STATUS CsmVideoPolicySetMode( + IN CSM_VIDEO_POLICY_PROTOCOL *This, + IN BOOLEAN TextMode, IN BOOLEAN ForceModeChange +){ +#if INT10_SIMPLE_TEXT_SUPPORT==0 + return (TextMode) ? EFI_UNSUPPORTED : EFI_SUCCESS; +#else + EFI_STATUS Status; + BOOLEAN OriginalPolicy=TextModePolicy; + EFI_HANDLE Handle; + + TextModePolicy = TextMode; + if ( VgaControllerHandle == NULL + || OriginalPolicy==TextModePolicy && !ForceModeChange + ) return EFI_SUCCESS; + + // save the VGA handle + // the global variable VgaControllerHandle will be nullified + // by the Stop function during Disconnect. + Handle = VgaControllerHandle; + Status = pBS->DisconnectController( Handle, NULL, NULL ); + if (!EFI_ERROR(Status)) + Status = pBS->ConnectController( Handle, NULL, NULL, TRUE ); + else + TextModePolicy = OriginalPolicy; + if (EFI_ERROR(Status)) return Status; + return (TextModePolicy==TextMode) ? EFI_SUCCESS : EFI_UNSUPPORTED; +#endif +} + +EFI_STATUS CsmVideoPolicyGetMode( + IN CSM_VIDEO_POLICY_PROTOCOL *This,IN BOOLEAN *IsTextMode +){ + if (IsTextMode!=NULL) *IsTextMode = TextModePolicy; + return (VgaControllerHandle == NULL) ? EFI_NOT_STARTED : EFI_SUCCESS; +} + +CSM_VIDEO_POLICY_PROTOCOL CsmVideoPolicyProtocol = { + CsmVideoPolicyGetMode, CsmVideoPolicySetMode +}; +//*** AMI PORTING END *****// + +EFI_STATUS GetBadEdid ( + IN EFI_EDID_OVERRIDE_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle, + OUT UINT32 *Attributes, + IN OUT UINTN *EdidSize, + IN OUT UINT8 **Edid + ) +{ + static UINT8 EdidData[0x80] = {0}; + EdidData[0x7f] = 1; // invalid checksum + + *Edid = EdidData; + *EdidSize = 0x80; + *Attributes = 0; + + return EFI_SUCCESS; +} + + +// +// Driver Entry Point +// +EFI_DRIVER_ENTRY_POINT (BiosVideoDriverEntryPoint) + +EFI_STATUS +EFIAPI +BiosVideoDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + + Routine Description: + + Driver Entry Point. + + Arguments: + + ImageHandle - Handle of driver image. + SystemTable - Pointer to system table. + + Returns: + + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + static EFI_GUID gCsmThunkDriverGuid = + { 0x2362ea9c, 0x84e5, 0x4dff, 0x83, 0xbc, 0xb5, 0xac, 0xec, 0xb5, 0x7c, 0xbb }; + + Status = EfiLibInstallAllDriverProtocols ( + ImageHandle, + SystemTable, + &gBiosVideoDriverBinding, + ImageHandle, +#if EFI_SPECIFICATION_VERSION <= 0x20000 + &gBiosVideoComponentName, +#else + &gBiosVideoComponentName2, +#endif + NULL, + NULL + ); +//*** AMI PORTING BEGIN ***// +#if INT10_SIMPLE_TEXT_SUPPORT==1 +{ +//create new handle + EFI_HANDLE Handle = NULL; + VgaClassDriverEntryPoint(Handle,SystemTable); +} +#endif + +#if INT10_TRUST_EDID_INFORMATION == 0 +{ + // Install EdidOverride with the dummy EDID information; this is needed to ignore + // bad EDID information + EFI_STATUS Status; + static EFI_EDID_OVERRIDE_PROTOCOL EdidOverride = { GetBadEdid }; + + Status = gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gEfiEdidOverrideProtocolGuid, &EdidOverride, + NULL + ); +} +#endif + +// Install CsmVideoPolicy protocol + gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gCsmVideoPolicyProtocolGuid, &CsmVideoPolicyProtocol, + &gCsmThunkDriverGuid, NULL, + NULL + ); + +//AMI CSM Core does not need Legacy BIOS GUID +//Just return the status + return Status; +/* + if (EFI_ERROR (Status)) { + return Status; + } + // + // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver + // + return gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiLegacyBiosGuid, + NULL, + NULL + ); +*/ +//*** AMI PORTING END *****// +} +//*** AMI PORTING BEGIN ***// +//Exit Boot Services callback is not needed. +/* +VOID +BiosVideoExitBootServices ( + EFI_EVENT Event, + VOID *Context + ) +*/ +/*++ + +Routine Description: + + Callback function for exit boot service event + +Arguments: + + Event - EFI_EVENT structure + Context - Event context + +Returns: + + None + +--*/ +/*{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_IA32_REGISTER_SET Regs; + + // + // Get our context + // + BiosVideoPrivate = (BIOS_VIDEO_DEV *) Context; + + // + // 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); +} +*/ +//*** AMI PORTING END *****// + +EFI_STATUS +EFIAPI +BiosVideoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Supported. + + Arguments: + + This - Pointer to driver binding protocol + Controller - Controller handle to connect + RemainingDevicePath - A pointer to the remaining portion of a device path + + + Returns: + + EFI_STATUS - EFI_SUCCESS:This controller can be managed by this driver, + Otherwise, this controller cannot be managed by this driver + +--*/ +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // 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)) { + return Status; + } + // + // 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; + } + +Done: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +BiosVideoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Install Graphics Output Protocol onto VGA device handles + + Arguments: + + This - Pointer to driver binding protocol + Controller - Controller handle to connect + RemainingDevicePath - A pointer to the remaining portion of a device path + + Returns: + + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Flags; +//*** AMI PORTING BEGIN ***// +// See comments below regarding the Capabilities usage + UINT64 Capabilities = 0; +//*** AMI PORTING END *****// + + PciIo = NULL; + // + // Prepare for status code + // + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 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)) { + goto Done; + } + + // + // See if the Legacy BIOS Protocol is available + // + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + goto Done; + } + + ReportStatusCodeWithDevicePath ( + EFI_PROGRESS_CODE, + EFI_P_PC_ENABLE, + 0, + &gEfiCallerIdGuid, + ParentDevicePath + ); + // + // Enable the device and make sure VGA cycles are being forwarded to this VGA device + // +//*** AMI PORTING BEGIN ***// +// We need to check what is supported by the hardware before enabling attributes + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Capabilities + ); + + if ( EFI_ERROR(Status) ) { + goto Done; + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Capabilities & EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, + NULL + ); +/* + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, + NULL + ); +*/ +//*** AMI PORTING END *****// + if (EFI_ERROR (Status)) { + ReportStatusCodeWithDevicePath ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT, + 0, + &gEfiCallerIdGuid, + 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. + // + ReportStatusCodeWithDevicePath ( + EFI_PROGRESS_CODE, + EFI_P_PC_RESET, + 0, + &gEfiCallerIdGuid, + ParentDevicePath + ); + Status = LegacyBios->InstallPciRom ( + LegacyBios, + Controller, + NULL, + &Flags, + NULL, + NULL, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + ReportStatusCodeWithDevicePath ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + 0, + &gEfiCallerIdGuid, + ParentDevicePath + ); + goto Done; + } + + // + // Create child handle and install GraphicsOutputProtocol on it + // + Status = BiosVideoChildHandleInstall ( + This, + Controller, + PciIo, + LegacyBios, + ParentDevicePath, + RemainingDevicePath + ); + +Done: + if (EFI_ERROR (Status)) { + if (PciIo != NULL) { + ReportStatusCodeWithDevicePath ( + EFI_PROGRESS_CODE, + EFI_P_PC_DISABLE, + 0, + &gEfiCallerIdGuid, + ParentDevicePath + ); + // + // Turn off the PCI device and disable forwarding of VGA cycles to this device + // + if (Capabilities != 0) + { + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, +//*** AMI PORTING BEGIN ***// + Capabilities & EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, +// EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, +//*** AMI PORTING END *****// + NULL + ); + } + // + // Release PCI I/O Protocols on the controller handle. + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +BiosVideoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + + Stop. + + Arguments: + + This - Pointer to driver binding protocol + Controller - Controller handle to connect + NumberOfChilren - Number of children handle created by this driver + ChildHandleBuffer - Buffer containing child handle created + + Returns: + + EFI_SUCCESS - Driver disconnected successfully from controller + EFI_UNSUPPORTED - Cannot find BIOS_VIDEO_DEV structure + +--*/ +{ + EFI_STATUS Status; + BIOS_VIDEO_DEV *BiosVideoPrivate; + BOOLEAN AllChildrenStopped; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 Capabilities; + + BiosVideoPrivate = NULL; + + if (NumberOfChildren == 0) { +//*** AMI PORTING BEGIN ***// +//In text mode, the child handle is not created +//and the mini port protocol is installed on the PciIo handle. +//Original implementation does not stop controller in this case +//Here is the fix: +#if INT10_SIMPLE_TEXT_SUPPORT==1 + Status = gBS->OpenProtocol ( + Controller, + &gEfiVgaMiniPortProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR(Status)){ + return BiosVideoChildHandleUninstall (This, Controller, Controller); + } +#endif + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR(Status); + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Capabilities + ); + ASSERT_EFI_ERROR(Status); + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + Capabilities & EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, + NULL + ); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return EFI_DEVICE_ERROR; +//*** AMI PORTING END *****// + // + // Close PCI I/O protocol on the controller handle + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + for (Index = 0; Index < NumberOfChildren; Index++) { + Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]); + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + Install child handles if the Handle supports MBR format. + +Arguments: + This - Calling context. + Handle - Parent Handle + PciIo - Parent PciIo interface + LegacyBios - Parent LegacyBios interface + DevicePath - Parent Device Path + +Returns: + EFI_SUCCESS - If a child handle was added + other - A child handle was not added + +--*/ +{ + EFI_STATUS Status; + BIOS_VIDEO_DEV *BiosVideoPrivate; + PCI_TYPE00 Pci; + ACPI_ADR_DEVICE_PATH AcpiDeviceNode; + + // + // Allocate the private device structure for video device + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (BIOS_VIDEO_DEV), + &BiosVideoPrivate + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + EfiZeroMem (BiosVideoPrivate, sizeof (BIOS_VIDEO_DEV)); + + // + // 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)) { + ReportStatusCodeWithDevicePath ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + 0, + &gEfiCallerIdGuid, + 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; + } + + // + // Initialize the child private structure + // + BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE; + BiosVideoPrivate->Handle = NULL; + +//*** AMI PORTING BEGIN ***// +//Exit Boot Services callback is not needed. +/* + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + EFI_TPL_NOTIFY, + BiosVideoExitBootServices, + BiosVideoPrivate, + &BiosVideoPrivate->ExitBootServicesEvent + ); + if (EFI_ERROR (Status)) { + goto Done; + } +*/ +//*** AMI PORTING END *****// + + // + // Fill in Graphics Output specific mode structures + // + BiosVideoPrivate->HardwareNeedsStarting = TRUE; + BiosVideoPrivate->ModeData = NULL; + BiosVideoPrivate->LineBuffer = NULL; + BiosVideoPrivate->VgaFrameBuffer = NULL; + BiosVideoPrivate->VbeFrameBuffer = NULL; + +//*** AMI PORTING BEGIN ***// +//Let's do it only if VgaMiniPort is going to be installed +/* + // + // 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; +*/ + // + // 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) { + EfiZeroMem (&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->DevicePath = EfiAppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode + ); + } else { + BiosVideoPrivate->DevicePath = EfiAppendDevicePathNode (ParentDevicePath, RemainingDevicePath); + } + + // + // Create child handle associated with device path + // The newely created handle can be used for calling EDID_OVERRIDE_PROTOCOL + // + BiosVideoPrivate->Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &BiosVideoPrivate->Handle, + &gEfiDevicePathProtocolGuid, + BiosVideoPrivate->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // 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 + // +//*** AMI PORTING BEGIN ***// +// Status = BiosVideoCheckForVbe (BiosVideoPrivate); +#if INT10_VESA_GO_SUPPORT==1 + if ( TextModePolicy ) + Status = EFI_UNSUPPORTED; + else + Status = BiosVideoCheckForVbe (BiosVideoPrivate, &Pci); +#else + Status = EFI_UNSUPPORTED; +#endif +//*** AMI PORTING END *****// + 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 + // +//*** AMI PORTING BEGIN ***// +// if (BiosVideoPrivate->VgaCompatible) { +// Status = BiosVideoCheckForVga (BiosVideoPrivate); +// } +#if INT10_VGA_GO_SUPPORT==1 + if (!TextModePolicy && BiosVideoPrivate->VgaCompatible) { + Status = BiosVideoCheckForVga (BiosVideoPrivate); + } +#endif +//*** AMI PORTING END *****// + + if (EFI_ERROR (Status)) { + // + // 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; + } + } + + if (BiosVideoPrivate->ProduceGraphicsOutput) { + // + // Create 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 + ); + } + } else { +//*** AMI PORTING BEGIN ***// +#if INT10_SIMPLE_TEXT_SUPPORT==1 +//The code if moved here from BiosVideoChildHandleInstall + // + // 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; +//*** AMI PORTING END *****// +//*** AMI PORTING BEGIN ***// + //This is needed! Otherwise VgaClass driver rejects VgaMiniPort + //device due to the lack of PciIo protocol + BiosVideoPrivate->Handle=ParentHandle; +//*** AMI PORTING END *****// + // + // Install VGA Mini Port Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &BiosVideoPrivate->Handle, + &gEfiVgaMiniPortProtocolGuid, + &BiosVideoPrivate->VgaMiniPort, + NULL + ); +//*** AMI PORTING BEGIN ***// +#else +#endif //INT10_SIMPLE_TEXT_SUPPORT==1 +//*** AMI PORTING END *****// + } + +Done: + if (EFI_ERROR (Status)) { + // + // Free private data structure + // + BiosVideoDeviceReleaseResource (BiosVideoPrivate); + } +//*** AMI PORTING BEGIN ***// +// The protocols are installed. +// Update global variables used by the CsmVideoPolicy protocol implementation. + TextModePolicy = !BiosVideoPrivate->ProduceGraphicsOutput; + VgaControllerHandle = ParentHandle; +//*** AMI PORTING END *****// + return Status; +} + +EFI_STATUS +BiosVideoChildHandleUninstall ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Deregister an video child handle and free resources + +Arguments: + + This - Protocol instance pointer. + Controller - Video controller handle + Handle - Video child handle + +Returns: + + EFI_STATUS + +--*/ +{ + 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; + + 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); + } + + 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; + } + + // + // 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->DevicePath, + &gEfiGraphicsOutputProtocolGuid, + &BiosVideoPrivate->GraphicsOutput, + &gEfiEdidDiscoveredProtocolGuid, + &BiosVideoPrivate->EdidDiscovered, + &gEfiEdidActiveProtocolGuid, + &BiosVideoPrivate->EdidActive, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + BiosVideoPrivate->Handle, + &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; + } + + // + // 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); + + // + // Do not disable IO/memory decode since that would prevent legacy ROM from working + // + + // + // Release all allocated resources + // + BiosVideoDeviceReleaseResource (BiosVideoPrivate); +//*** AMI PORTING BEGIN ***// +// The protocols are uninstalled. +// Update global variables used by the CsmVideoPolicy protocol implementation. + VgaControllerHandle = NULL; +//*** AMI PORTING END *****// + return EFI_SUCCESS; +} + +VOID +BiosVideoDeviceReleaseResource ( + BIOS_VIDEO_DEV *BiosVideoPrivate + ) +/*++ +Routing Description: + + Release resources of an video child device before stopping it. + +Arguments: + + BiosVideoPrivate - Video child device private data structure + +Returns: + + NONE + +---*/ +{ + if (BiosVideoPrivate == NULL) { + return ; + } + + // + // Release all the resourses occupied by the BIOS_VIDEO_DEV + // + + // + // Free VGA Frame Buffer + // + if (BiosVideoPrivate->VgaFrameBuffer != NULL) { + gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer); + BiosVideoPrivate->VgaFrameBuffer = NULL; + } + // + // Free VBE Frame Buffer + // + if (BiosVideoPrivate->VbeFrameBuffer != NULL) { + gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer); + BiosVideoPrivate->VbeFrameBuffer = NULL; + } + // + // Free line buffer + // + if (BiosVideoPrivate->LineBuffer != NULL) { + gBS->FreePool (BiosVideoPrivate->LineBuffer); + BiosVideoPrivate->LineBuffer = NULL; + } + // + // Free mode data + // + if (BiosVideoPrivate->ModeData != NULL) { + gBS->FreePool (BiosVideoPrivate->ModeData); + BiosVideoPrivate->ModeData = NULL; + } + // + // 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) { + gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); + BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL; + } + gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode); + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + } + // + // Free EDID discovered protocol occupied resource + // + if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) { + gBS->FreePool (BiosVideoPrivate->EdidDiscovered.Edid); + BiosVideoPrivate->EdidDiscovered.Edid = NULL; + } + // + // Free EDID active protocol occupied resource + // + if (BiosVideoPrivate->EdidActive.Edid != NULL) { + gBS->FreePool (BiosVideoPrivate->EdidActive.Edid); + BiosVideoPrivate->EdidActive.Edid = NULL; + } + + if (BiosVideoPrivate->DevicePath!= NULL) { + gBS->FreePool (BiosVideoPrivate->DevicePath); + BiosVideoPrivate->DevicePath = NULL; + } + + // + // Close the ExitBootServices event + // +//*** AMI PORTING BEGIN ***// +//ExitBootServicesEvent is not used +/* + if (BiosVideoPrivate->ExitBootServicesEvent != NULL) { + gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent); + } +*/ +//*** AMI PORTING END *****// + + gBS->FreePool (BiosVideoPrivate); + + return ; +} + +//*** AMI PORTING BEGIN ***// +#if INT10_VESA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +STATIC +UINT32 +CalculateEdidKey ( + VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming + ) +/*++ + + Routine Description: + + Generate a search key for a specified timing data. + + Arguments: + + EdidTiming - Pointer to EDID timing + + Returns: + The 32 bit unique key for search. + +--*/ +{ + UINT32 Key; + + // + // Be sure no conflicts for all standard timing defined by VESA. + // + Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution + EdidTiming->RefreshRate; + return Key; +} + +STATIC +BOOLEAN +ParseEdidData ( + UINT8 *EdidBuffer + ) +/*++ + + Routine Description: + + Parse the Established Timing and Standard Timing in EDID data block. + + Arguments: + + EdidBuffer - Pointer to EDID data block + ValidEdidTiming - Valid EDID timing information + + Returns: + TRUE - The EDID data is valid. + FALSE - The EDID data is invalid. + +--*/ +{ + UINT8 CheckSum; + UINT32 Index; + UINT32 ValidNumber; + UINT32 TimingBits; + UINT8 *BufferIndex; + UINT16 HorizontalResolution; + UINT16 VerticalResolution; + UINT8 AspectRatio; + 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 = CheckSum + EdidBuffer[Index]; + } + if (CheckSum != 0) { + TRACE((TRACE_BIOS_VIDEO, "EDID checksum is invalid, EDID will be ignored.\n")); + return FALSE; + } + + ValidNumber = 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) { + SupportedResolutions[Index] = mEstablishedEdidTiming[Index].VerticalResolution | + (mEstablishedEdidTiming[Index].HorizontalResolution << 16); + ValidNumber ++; + } + TimingBits = TimingBits >> 1; + } + + // + // If no Established timing data, read the standard timing data + // + BufferIndex = &EdidDataBlock->StandardTimingIdentification[0]; + for (Index = 0; Index < 8; Index ++) { + if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){ + // + // A valid Standard Timing + // + HorizontalResolution = BufferIndex[0] * 8 + 248; + AspectRatio = BufferIndex[1] >> 6; + switch (AspectRatio) { + case 0: + VerticalResolution = HorizontalResolution / 16 * 10; + break; + case 1: + VerticalResolution = HorizontalResolution / 4 * 3; + break; + case 2: + VerticalResolution = HorizontalResolution / 5 * 4; + break; + case 3: + VerticalResolution = HorizontalResolution / 16 * 9; + break; + default: + VerticalResolution = HorizontalResolution / 4 * 3; + break; + } + + SupportedResolutions[Index + 17] = VerticalResolution |(HorizontalResolution << 16); + ValidNumber ++; + } + BufferIndex += 2; + } + + if ( (EdidDataBlock->FeatureSupport & 2) == 2) { + // Preferred timing mode is indicated in the first detailed timing block + for (Index = 0; Index < 4; Index ++) { + if ((EdidDataBlock->DetailedTimingDescriptions[Index*18 + 0] | + EdidDataBlock->DetailedTimingDescriptions[Index*18 + 1]) && + (EdidDataBlock->DetailedTimingDescriptions[Index*18 + 2] | + (EdidDataBlock->DetailedTimingDescriptions[Index*18 + 4] & 0xf0))) { + + SupportedResolutions[Index + 25] = + (EdidDataBlock->DetailedTimingDescriptions[Index*18 + 5] | ((UINT16)(EdidDataBlock->DetailedTimingDescriptions[Index*18 + 7] & 0xF0) << 4)) + | ((UINT32)(EdidDataBlock->DetailedTimingDescriptions[Index*18 + 2] | ((UINT16)(EdidDataBlock->DetailedTimingDescriptions[Index*18 + 4] & 0xF0) << 4)) << 16); + +TRACE((TRACE_BIOS_VIDEO, "EDID Detailed timing[%d]: inserted resolution 0x%x (%dx%d)\n", Index, SupportedResolutions[Index + 25], + EdidDataBlock->DetailedTimingDescriptions[Index*18 + 2] | ((EdidDataBlock->DetailedTimingDescriptions[Index*18 + 4] & 0xF0) << 4), + EdidDataBlock->DetailedTimingDescriptions[Index*18 + 5] | ((EdidDataBlock->DetailedTimingDescriptions[Index*18 + 7] & 0xF0) << 4) +)); + + ValidNumber ++; + } + } + } + +//*** AMI PORTING BEGIN ***// +// Bug fix. The function was returning TRUE even when no valid timings found. +// return TRUE; + return (ValidNumber != 0); +//*** AMI PORTING END ***// +} + +STATIC +BOOLEAN +SearchEdidTiming ( + UINT32 ResolutionKey + ) +/*++ + + Routine Description: + + Search a specified Timing in all the valid EDID timings. + + Arguments: + + ValidEdidTiming - All valid EDID timing information. + EdidTiming - The Timing to search for. + + Returns: + + TRUE - Found. + FALSE - Not found. + +--*/ +{ + UINT32 Index; + for (Index = 0; Index < 29; Index ++) { + if (ResolutionKey == SupportedResolutions[Index]) { + return TRUE; + } + } + + return FALSE; +} + +//*** AMI PORTING BEGIN ***// +#if CSM_VGA_64BITBAR_WORKAROUND +BOOLEAN CheckAbove4g(PCI_TYPE00 *PciConfSpace){ + UINTN i; +//--------------------- + for(i=0; i<PCI_MAX_BAR-1;i++){ + //check all six bars if + if((PciConfSpace->Device.Bar[i] & 0x04) && ( PciConfSpace->Device.Bar[i+1]!=0) ) return TRUE; + } + return FALSE; +} + + +EFI_STATUS Update64BitLinearBufferAddr(EFI_PCI_IO_PROTOCOL *PciIo, UINT64 *LowerAddrPart, PCI_TYPE00 *PciConfSpace){ + UINTN i,j; + EFI_STATUS Status; + ASLR_QWORD_ASD *BarRes=NULL; + UINT64 start, end, bar, test; + UINT32 *pUp32; +//----------------------------- + + //pBS->SetMem(&BarRes[0], sizeof(BarRes), 0); + //Get PciIo Bar ACPI QW Resource Descriptor and Count... + + for(i=0; i<PCI_MAX_BAR; i++){ + //Free Memory allocated for us by PciBus Driver... + //if we got here by continue statement... + if(BarRes!=NULL){ + pBS->FreePool(BarRes); + BarRes=NULL; + } + + Status = PciIo->GetBarAttributes(PciIo,(UINT8)i, NULL, &BarRes); + if(EFI_ERROR(Status)) return Status; + + //care only about 64 bit resources end filter out Unused BARs and NOT64bit BARs + if(BarRes->Hdr.Name==ASLV_SR_EndTag) continue; + if(BarRes->_GRA < 64) continue; + + start=BarRes->_MIN; + end=BarRes->_MAX; + test=*LowerAddrPart; + + //Free Memory allocated for us by PciBus Driver... + if(BarRes!=NULL){ + pBS->FreePool(BarRes); + BarRes=NULL; + } + + //now try to match what we read from PCI Config to Res Descriptor returned by the call to PciIo... + for(j=0, bar=0; j<PCI_MAX_BAR-1;j++){ + if(PciConfSpace->Device.Bar[j] & 0x04){ + //here we got 64 bit BAR.... + bar=PciConfSpace->Device.Bar[j] & (~0xF); //Mask read only Bar Type bits... + //fill Upper Part of BAR address + j++; + pUp32=((UINT32*)&bar)+1; + *pUp32=PciConfSpace->Device.Bar[j]; + pUp32=((UINT32*)&test)+1; + *pUp32=PciConfSpace->Device.Bar[j]; + + //Check if we found match? + if(start==bar){ + if((start <= test) && (test < end)) { + *LowerAddrPart=test; + return EFI_SUCCESS; + } else break; + } + } + } + } + return EFI_SUCCESS; +} +#endif +//*** AMI PORTING END *****// + +EFI_STATUS CheckForDuplicateMode (BIOS_VIDEO_DEV *VideoDev, UINTN ModeNumber) +{ + UINT16 Xres = VideoDev->VbeModeInformationBlock->XResolution; + UINT16 Yres = VideoDev->VbeModeInformationBlock->YResolution; + UINTN i; + BIOS_VIDEO_MODE_DATA *ModeData = VideoDev->ModeData; + + // walk through the list of published modes, see if there is a match + for (i = 0; i < ModeNumber; i++) + { + if (ModeData->HorizontalResolution == Xres + && ModeData->VerticalResolution == Yres) + { + return EFI_SUCCESS; + } + ModeData++; + } + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +BiosVideoCheckForVbe ( + IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate, +//*** AMI PORTING BEGIN ***// + PCI_TYPE00 *PciConfSpace +//*** AMI PORTING END *****// + ) +/*++ + + Routine Description: + + Check for VBE device + + Arguments: + + BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure + + Returns: + + EFI_SUCCESS - VBE device found + +--*/ +{ + EFI_STATUS Status; + EFI_IA32_REGISTER_SET Regs; + UINT16 *ModeNumberPtr; + BOOLEAN ModeFound; + BOOLEAN EdidFound; + BOOLEAN EdidMatch; + BIOS_VIDEO_MODE_DATA *ModeBuffer; + BIOS_VIDEO_MODE_DATA *CurrentModeData; + UINTN PreferMode; + UINTN ModeNumber; + UINT32 ResolutionKey; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *GraphicsOutputMode; + INT32 i; + EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride; + UINT32 EdidAttributes; + BOOLEAN EdidOverrideFound; + UINTN EdidOverrideDataSize; + UINT8 *EdidOverrideDataBlock; + UINTN EdidActiveDataSize; + UINT8 *EdidActiveDataBlock; +//*** AMI PORTING BEGIN ***// +#if CSM_VGA_64BITBAR_WORKAROUND + BOOLEAN Above4g; +#endif +//*** AMI PORTING END *****// + + EdidOverrideFound = FALSE; + EdidOverrideDataBlock = NULL; + EdidActiveDataSize = 0; + EdidActiveDataBlock = NULL; + +//*** AMI PORTING BEGIN ***// +#if CSM_VGA_64BITBAR_WORKAROUND + Above4g=CheckAbove4g(PciConfSpace); +#endif +//*** AMI PORTING END *****// + + // + // 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; + } + + // + // Fill in the Graphics Output Protocol + // + BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode; + BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode; + BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt; + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + + // + // 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->VbeModeInformationBlock + 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; + + // + // Check if EDID Override protocol is installed by platform. + // + Status = gBS->LocateProtocol ( + &gEfiEdidOverrideProtocolGuid, + NULL, + (VOID **) &EdidOverride + ); + + if (!EFI_ERROR (Status)) { + // + // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof ((VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2)), + &EdidOverrideDataBlock + ); + + if (EFI_ERROR(Status)) { + goto Done; + } + + Status = EdidOverride->GetEdid ( + EdidOverride, + BiosVideoPrivate->Handle, + &EdidAttributes, + &EdidOverrideDataSize, + (UINT8 **) &EdidOverrideDataBlock + ); + if (!EFI_ERROR (Status) && +//*** AMI PORTING BEGIN ***// +// EdidAttributes == 0 && +//*** AMI PORTING END ***// + EdidOverrideDataSize != 0) { + // + // Succeeded to get EDID Override Data + // + TRACE((TRACE_BIOS_VIDEO, "EDID override protocol found: data size %x, attribute %x\n", EdidOverrideDataSize, EdidAttributes)); + EdidOverrideFound = TRUE; + } + } + + + // "EdidFound" is forcibly FALSE, + // because some SSUs(Server Switch Unit) return invalid response. + 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 and fill in EdidDiscovered structure + // + 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); + if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { + + BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; + Status = gBS->AllocatePool ( + EfiBootServicesData, + VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE, + &BiosVideoPrivate->EdidDiscovered.Edid + ); + if (EFI_ERROR (Status)) { + goto Done; + } + gBS->CopyMem ( + BiosVideoPrivate->EdidDiscovered.Edid, + BiosVideoPrivate->VbeEdidDataBlock, + VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE + ); + + EdidFound = TRUE; + } + } + + // + // Set up ActiveEdid data pointer and size + // + 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) == TRUE) { + // + // Copy EDID Override Data to EDID Active Data + // + BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32)EdidActiveDataSize; + Status = gBS->AllocatePool ( + EfiBootServicesData, + EdidActiveDataSize, + &BiosVideoPrivate->EdidActive.Edid + ); + if (EFI_ERROR (Status)) { + goto Done; + } + gBS->CopyMem ( + BiosVideoPrivate->EdidActive.Edid, + EdidActiveDataBlock, + EdidActiveDataSize + ); + } + } 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; + + TRACE((TRACE_BIOS_VIDEO, "VESA: fetching the list of VESA modes supported by the controller from %x\n", ModeNumberPtr)); + + for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) { + // + // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number. + // + TRACE((TRACE_BIOS_VIDEO,"VESA mode %x ", *ModeNumberPtr)); + + if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) { + TRACE((TRACE_BIOS_VIDEO,".. skipping as it is not a proper VESA mode number\n")); + 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 = *ModeNumberPtr; + 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) { + TRACE((TRACE_BIOS_VIDEO,".. skipping as we can not retrieve mode details\n")); + continue; + } + + TRACE((TRACE_BIOS_VIDEO, "(%dx%d) ", BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution)); + + // + // See if the mode supported in hardware. If it doesn't then try the next mode. + // + if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_HARDWARE) == 0) { + TRACE((TRACE_BIOS_VIDEO,"skipping as the mode is not supported in hardware...\n")); + 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) { + TRACE((TRACE_BIOS_VIDEO,"is invalid, skipping...\n")); + 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) { + TRACE((TRACE_BIOS_VIDEO,"skipping as the mode is not graphical...\n")); + 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) { + TRACE((TRACE_BIOS_VIDEO,"skipping as the mode has not linear frame buffer...\n")); + 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 Pixel. 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) { + TRACE((TRACE_BIOS_VIDEO,"skipping as BPP (%d) is less than 24...\n", BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel)); + continue; + } + + if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) { + TRACE((TRACE_BIOS_VIDEO,"skipping as BPP (%d) is more than 32...\n", BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel)); + continue; + } + + if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) { + TRACE((TRACE_BIOS_VIDEO,"skipping as BPP (%d) modulo 8 is non-zero...\n", BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel)); + 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) { + TRACE((TRACE_BIOS_VIDEO,"skipping as PhysBasePtr is zero...\n")); + continue; + } + EdidMatch = FALSE; + if (EdidFound) { + // + // EDID exist, check whether this mode match with any mode in EDID + // + ResolutionKey = BiosVideoPrivate->VbeModeInformationBlock->YResolution | + (BiosVideoPrivate->VbeModeInformationBlock->XResolution << 16); + + if (SearchEdidTiming (ResolutionKey) == TRUE) { + EdidMatch = TRUE; + TRACE((TRACE_BIOS_VIDEO, "EDID match found.\n")); + } + } + + // + // Select a reasonable mode to be set for current display mode + // + ModeFound = FALSE; + + for(i = 0; i < MaxTextMode; i++) + { + if(TextModeArray[i].VideoCol == BiosVideoPrivate->VbeModeInformationBlock->XResolution && + TextModeArray[i].VideoRow == BiosVideoPrivate->VbeModeInformationBlock->YResolution) + { + ModeFound = TRUE; + TRACE((TRACE_BIOS_VIDEO, "MODE match found (%d).\n", i)); + } + } + if ((!EdidMatch) && (!ModeFound)) { + // + // When EDID exist and if the timing matches with VESA add it. + // And also add three possible resolutions, i.e. 1024x768, 800x600, 640x480 + // + TRACE((TRACE_BIOS_VIDEO, "neither EDID nor MODE match is found.\n", i)); + continue; + } + + if (CheckForDuplicateMode(BiosVideoPrivate, ModeNumber) == EFI_SUCCESS) + { + TRACE((TRACE_BIOS_VIDEO, "skipping as the same resolution (%dx%d) is already available\n", + BiosVideoPrivate->VbeModeInformationBlock->XResolution, + BiosVideoPrivate->VbeModeInformationBlock->YResolution)); + continue; + } + + // + // Add mode to the list of available modes + // + ModeNumber ++; + Status = gBS->AllocatePool ( + EfiBootServicesData, + ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA), + (VOID **) &ModeBuffer + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (ModeNumber > 1) { + gBS->CopyMem ( + ModeBuffer, + BiosVideoPrivate->ModeData, + (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA) + ); + } + + if (BiosVideoPrivate->ModeData != NULL) { + gBS->FreePool (BiosVideoPrivate->ModeData); + BiosVideoPrivate->ModeData = NULL; + } + + CurrentModeData = &ModeBuffer[ModeNumber - 1]; + CurrentModeData->VbeModeNumber = *ModeNumberPtr; + 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); + } +//*** AMI PORTING BEGIN ***// +//Bug fix: The original logic did not work for a modes with 24-bit pixels. +// For a 24-bit pixels, the PixelFormat must be set to PixelBitMask, which +// was not happening with the original "if" statement +// if ((CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) { + if ( (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) + && (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff) + ) { +//*** AMI PORTING END *****// + if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8)) { + CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor; + } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8)) { + CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + } + } else { + CurrentModeData->PixelFormat = PixelBitMask; + } + 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; + +//*** AMI PORTING BEGIN ***// +#if CSM_VGA_64BITBAR_WORKAROUND + if(Above4g){ + UINT64 PhysBasePtr4g=BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr; + //------------------------------------ + Status=Update64BitLinearBufferAddr(BiosVideoPrivate->PciIo, &PhysBasePtr4g, PciConfSpace); + if (EFI_ERROR (Status)) { + goto Done; + } + + CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)PhysBasePtr4g; + }else +#endif + { + CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr; + } + //CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr; + +//*** AMI PORTING END *****// + CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution; + CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution; + + CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel; + +//*** AMI PORTING BEGIN ***// +// UEFI SCT 2.3.1 Summer Summit version reports that framebuffersize mismatch in query mode of SCT test +// Calculated the framebuffersize based for each mode configuration + if(CurrentModeData->PixelFormat == PixelRedGreenBlueReserved8BitPerColor || + CurrentModeData->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { + CurrentModeData->FrameBufferSize=((CurrentModeData->BytesPerScanLine * 8) / CurrentModeData->BitsPerPixel) * + CurrentModeData->VerticalResolution * + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } else { + CurrentModeData->FrameBufferSize = BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024; + } +//*** AMI PORTING END *****// + + CurrentModeData->RefreshRate = 60; + + 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; + } + + // + // Allocate buffer for Graphics Output Protocol mode information + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), + (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode + ); + if (EFI_ERROR (Status)) { + goto Done; + } + GraphicsOutputMode = BiosVideoPrivate->GraphicsOutput.Mode; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), + (VOID **) &GraphicsOutputMode->Info + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + GraphicsOutputMode->MaxMode = (UINT32) ModeNumber; + // + // Current mode is still unknown, set it to an invalid mode. + // + GraphicsOutputMode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; + TRACE((TRACE_BIOS_VIDEO, "Total number of GOP modes: %d\n", ModeNumber)); + // + // Find the best mode to initialize + // + 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) { + gBS->FreePool (BiosVideoPrivate->ModeData); + BiosVideoPrivate->ModeData = NULL; + } + if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { + if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { + gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); + BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL; + } + gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode); + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + } + } + + return Status; +} + +//*** AMI PORTING BEGIN ***// +#endif//if INT10_VESA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +//*** AMI PORTING BEGIN ***// +#if INT10_VGA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +EFI_STATUS +EFIAPI +BiosVideoCheckForVga ( + IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate + ) +/*++ + + Routine Description: + + Check for VGA device + + Arguments: + + BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure + + Returns: + + EFI_SUCCESS - Standard VGA device found + +--*/ +{ + EFI_STATUS Status; + BIOS_VIDEO_MODE_DATA *ModeBuffer; + + // + // Fill in the Graphics Output Protocol + // + BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode; + BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode; + BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt; + + // + // Allocate buffer for Graphics Output Protocol mode information + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), + (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode + ); + if (EFI_ERROR (Status)) { + goto Done; + } + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), + (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode->Info + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Add mode to the list of available modes + // + BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (BIOS_VIDEO_MODE_DATA), + (VOID **) &ModeBuffer + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + ModeBuffer->VbeModeNumber = 0x0012; + ModeBuffer->BytesPerScanLine = 640; + ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000); + ModeBuffer->FrameBufferSize = 0; + ModeBuffer->HorizontalResolution = 640; + ModeBuffer->VerticalResolution = 480; + ModeBuffer->RefreshRate = 60; + ModeBuffer->PixelFormat = PixelBltOnly; +//*** AMI PORTING BEGIN ***// +//Bug fix: initialize BitsPerPixel + ModeBuffer->BitsPerPixel = 4; +//*** AMI PORTING END *****// + + 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) { + gBS->FreePool (BiosVideoPrivate->ModeData); + BiosVideoPrivate->ModeData = NULL; + } + if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { + if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { + gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); + BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL; + } + gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode); + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + } + } + return Status; +} +//*** AMI PORTING BEGIN ***// +#endif//if INT10_VGA_GO_SUPPORT==1 +//*** AMI PORTING END *****// + +// +// Graphics Output Protocol Member Functions for VESA BIOS Extensions +// +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +/*++ + +Routine Description: + + Graphics Output protocol interface to get video mode + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to return information on. + Info - Caller allocated buffer that returns information about ModeNumber. + SizeOfInfo - A pointer to the size, in bytes, of the Info buffer. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_STATUS Status; + BIOS_VIDEO_MODE_DATA *ModeData; + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + + if (BiosVideoPrivate->HardwareNeedsStarting) { + ReportStatusCodeWithDevicePath ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR, + 0, + &gEfiCallerIdGuid, + BiosVideoPrivate->DevicePath + ); + return EFI_NOT_STARTED; + } + + if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), + Info + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *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; + (*Info)->PixelInformation = ModeData->PixelBitMask; + + (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel; + + return EFI_SUCCESS; +} + +//*** AMI PORTING BEGIN ***// +// The AllocateTheBuffers function below and certain modifications of +// the BiosVideoGraphicsOutputVbeBlt nd BiosVideoVgaMiniPortSetMode functions +// are made to address the issues reaised in EIP 35682. +// +// The BLT function (BiosVideoGraphicsOutputVbeBlt) uses several memory buffers. +// Default implementation allocates the buffers in the SetMode(BiosVideoVgaMiniPortSetMode) +// function. We are changing implementation to allocate the buffers right in the BLT function +// before the first use. The code that releases the buffers is still in the SetMode function. +// +// This is a workaround for the "UEFI Windows 7 Startup Repair" bug. +// When Startup Repair option is selected, it crashes with the 0xc0000225 error prior +// to the call to ExitBootServices. +// The problem is caused by the Windows inability to handle memory map changes. +// The memory map changes when Windows calls Gop->SetMode and our implementation of the +// SetMode(BiosVideoGraphicsOutputVbeBlt) allocates the buffers. +// This workaround moves buffer allocation to the BLT function (BiosVideoGraphicsOutputVbeBlt), +// which Windows never calls and therefore memory map never changes. +EFI_STATUS AllocateTheBuffers(BIOS_VIDEO_DEV *BiosVideoPrivate){ + EFI_STATUS Status; + BIOS_VIDEO_MODE_DATA *ModeData; + UINT16 MaxBytesPerScanLine = 0; + UINT32 MaxVerticalResolution = 0; + UINT32 CurrentMode = (BiosVideoPrivate->GraphicsOutput).Mode->Mode; + UINT32 MaxMode = (BiosVideoPrivate->GraphicsOutput).Mode->MaxMode; + UINT32 Index; + + TRACE((TRACE_BIOS_VIDEO, "UefiBiosVideo AllocateTheBuffers()\n")); + for(Index = 0; Index < MaxMode; Index++) { + ModeData = &BiosVideoPrivate->ModeData[Index]; + + if (MaxBytesPerScanLine < ModeData->BytesPerScanLine) { + MaxBytesPerScanLine = ModeData->BytesPerScanLine; + } + if (MaxVerticalResolution < ModeData->VerticalResolution) { + MaxVerticalResolution = ModeData->VerticalResolution; + } + + TRACE((TRACE_BIOS_VIDEO, "VbeModeNumber: 0x%x\n", ModeData->VbeModeNumber)); + TRACE((TRACE_BIOS_VIDEO, "BytesPerScanLine: 0x%x\n", \ + ModeData->BytesPerScanLine)); + TRACE((TRACE_BIOS_VIDEO, "HorizontalResolution: 0x%x\n", \ + ModeData->HorizontalResolution)); + TRACE((TRACE_BIOS_VIDEO, "VerticalResolution: 0x%x\n", \ + ModeData->VerticalResolution)); + } + + TRACE((TRACE_BIOS_VIDEO, "MaxBytesPerScanLine: 0x%x\n", MaxBytesPerScanLine)); + TRACE((TRACE_BIOS_VIDEO, "MaxVerticalResolution: 0x%x\n", \ + MaxVerticalResolution)); + + ModeData = &BiosVideoPrivate->ModeData[CurrentMode]; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + MaxBytesPerScanLine, + &BiosVideoPrivate->LineBuffer + ); + if (EFI_ERROR (Status)) { + BiosVideoPrivate->LineBuffer=NULL; + return Status; + } + MemSet(BiosVideoPrivate->LineBuffer, MaxBytesPerScanLine, 0); + + // + // Allocate a working buffer for BLT operations to the VGA frame buffer + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + 4 * 480 * 80, + &BiosVideoPrivate->VgaFrameBuffer + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (BiosVideoPrivate->LineBuffer); + BiosVideoPrivate->LineBuffer=NULL; + return Status; + } + MemSet(BiosVideoPrivate->VgaFrameBuffer, 4 * 480 * 80, 0); + + // + // Allocate a working buffer for BLT operations to the VBE frame buffer + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + MaxBytesPerScanLine * MaxVerticalResolution, + &BiosVideoPrivate->VbeFrameBuffer + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (BiosVideoPrivate->LineBuffer); + BiosVideoPrivate->LineBuffer=NULL; + return Status; + } + MemSet( + BiosVideoPrivate->VbeFrameBuffer, + MaxBytesPerScanLine * MaxVerticalResolution, + 0 + ); + + // + // Initialize the state of the VbeFrameBuffer + // + if (ModeData->VbeModeNumber >= 0x100) { + gBS->CopyMem ( + BiosVideoPrivate->VbeFrameBuffer, + ModeData->LinearFrameBuffer, + (ModeData->BytesPerScanLine * ModeData->VerticalResolution)); + + } + return Status; +} + +//*** AMI PORTING END *****// + +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, + IN UINT32 ModeNumber + ) +/*++ + +Routine Description: + + Graphics Output protocol interface to set video mode + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to be set. + + Returns: + EFI_SUCCESS - Graphics mode was changed. + EFI_DEVICE_ERROR - The device had an error and could not complete the request. + EFI_UNSUPPORTED - ModeNumber is not supported by this device. + +--*/ +{ +//*** AMI PORTING BEGIN ***// +//Workaround for EIP 35682. See comments above +//AllocateTheBuffers function for additional details. +// EFI_STATUS Status; +//*** AMI PORTING END *****// + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_IA32_REGISTER_SET Regs; + BIOS_VIDEO_MODE_DATA *ModeData; + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ModeNumber >= This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } +/* + if (ModeNumber == This->Mode->Mode) { + return EFI_SUCCESS; + } +*/ + ModeData = &BiosVideoPrivate->ModeData[ModeNumber]; + + if (BiosVideoPrivate->LineBuffer) { + gBS->FreePool (BiosVideoPrivate->LineBuffer); + BiosVideoPrivate->LineBuffer = NULL; + } + + if (BiosVideoPrivate->VgaFrameBuffer) { + gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer); + BiosVideoPrivate->VgaFrameBuffer = NULL; + } + + if (BiosVideoPrivate->VbeFrameBuffer) { + gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer); + BiosVideoPrivate->VbeFrameBuffer = NULL; + } + + BiosVideoPrivate->LineBuffer = NULL; +//*** AMI PORTING BEGIN ***// +// Workaround for EIP 35682. +// Buffer allocation code is moved to AllocateTheBuffers function, +// which is called from the BiosVideoGraphicsOutputVbeBlt. +// See comments above AllocateTheBuffers function for additional details. +/* + Status = gBS->AllocatePool ( + EfiBootServicesData, + ModeData->BytesPerScanLine, + &BiosVideoPrivate->LineBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } +*/ +//*** AMI PORTING END *****// + // + // Clear all registers + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + + if (ModeData->VbeModeNumber < 0x100) { + // + // Allocate a working buffer for BLT operations to the VGA frame buffer + // + BiosVideoPrivate->VgaFrameBuffer = NULL; +//*** AMI PORTING BEGIN ***// +//*** AMI PORTING BEGIN ***// +// Workaround for EIP 35682. +// Buffer allocation code is moved to AllocateTheBuffers function, +// which is called from the BiosVideoGraphicsOutputVbeBlt. +// See comments above AllocateTheBuffers function for additional details. +/* + Status = gBS->AllocatePool ( + EfiBootServicesData, + 4 * 480 * 80, + &BiosVideoPrivate->VgaFrameBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } +*/ +//*** AMI PORTING END *****// + // + // 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 = NULL; +//*** AMI PORTING BEGIN ***// +//*** AMI PORTING BEGIN ***// +// Workaround for EIP 35682. +// Buffer allocation code is moved to AllocateTheBuffers function, +// which is called from the BiosVideoGraphicsOutputVbeBlt. +// See comments above AllocateTheBuffers function for additional details. +/* + Status = gBS->AllocatePool ( + EfiBootServicesData, + ModeData->BytesPerScanLine * ModeData->VerticalResolution, + &BiosVideoPrivate->VbeFrameBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } +*/ +//*** AMI PORTING END *****// + // + // 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); + gBS->SetMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK), 0); + 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) { + ReportStatusCodeWithDevicePath ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR, + 0, + &gEfiCallerIdGuid, + BiosVideoPrivate->DevicePath + ); + return EFI_DEVICE_ERROR; + } +//*** AMI PORTING BEGIN ***// + // + // 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; + } +*/ +// Workaround for EIP 35682. +// Buffer allocation and initialization code is moved to AllocateTheBuffers function, +// which is called from the BiosVideoGraphicsOutputVbeBlt. +// See comments above AllocateTheBuffers function for additional details. +/* + gBS->CopyMem ( + BiosVideoPrivate->VbeFrameBuffer, + ModeData->LinearFrameBuffer, + (ModeData->BytesPerScanLine * ModeData->VerticalResolution)); +*/ + } +//*** AMI PORTING END ***// + + 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; + This->Mode->Info->PixelInformation = ModeData->PixelBitMask; + This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel; + This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + // + // Frame BufferSize remain unchanged + // + This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) ModeData->LinearFrameBuffer; + This->Mode->FrameBufferSize = ModeData->FrameBufferSize; + + BiosVideoPrivate->HardwareNeedsStarting = FALSE; + + return EFI_SUCCESS; +} + +//*** AMI PORTING BEGIN ***// +#if INT10_VESA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +// +// BUGBUG : Add Blt for 16 bit color, 15 bit color, and 8 bit color modes +// +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 + ) +/*++ + +Routine Description: + + Graphics Output protocol instance to block transfer for VBE device + +Arguments: + + This - Pointer to Graphics Output protocol instance + BltBuffer - The data to transfer to screen + BltOperation - The operation to perform + SourceX - The X coordinate of the source for BltOperation + SourceY - The Y coordinate of the source for BltOperation + DestinationX - The X coordinate of the destination for BltOperation + DestinationY - The Y coordinate of the destination for BltOperation + Width - The width of a rectangle in the blt rectangle in pixels + Height - The height of a rectangle in the blt rectangle in pixels + 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. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter passed in + EFI_SUCCESS - Blt operation success + +--*/ +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + 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; + +//*** AMI PORTING BEGIN ***// +//Bug fix: This is accessed before it's checked on NULL + if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) { + return EFI_INVALID_PARAMETER; + } +//*** AMI PORTING END *****// + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); +//*** AMI PORTING BEGIN ***// +// Workaround for EIP 35682. +// Allocate memory buffers during the first call of the funciton. +// See comments above AllocateTheBuffers function for additional details. + if (BiosVideoPrivate->LineBuffer==NULL){ + EFI_STATUS Status = AllocateTheBuffers(BiosVideoPrivate); + if (EFI_ERROR(Status)) return Status; + } +//*** AMI PORTING END *****// + Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode]; + PciIo = BiosVideoPrivate->PciIo; + + VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer; + MemAddress = Mode->LinearFrameBuffer; + BytesPerScanLine = Mode->BytesPerScanLine; + VbePixelWidth = Mode->BitsPerPixel / 8; + BltUint8 = (UINT8 *) BltBuffer; + +//*** AMI PORTING BEGIN ***// +//These parameter checks are moved to the beginning of the function +/* + if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) { + return EFI_INVALID_PARAMETER; + } +*/ +//*** AMI PORTING END *****// + + 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 (EFI_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 = *(UINT32 *) (VbeBuffer); + 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, + Width * VbePixelWidth + ); + + if (VbePixelWidth == 4) { +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with CopyMem to optimize performance +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) ((UINTN) MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth), + Width, + VbeBuffer + ); +*/ + gBS->CopyMem ((UINT8*)MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth, + (UINT8*)VbeBuffer, + Width * VbePixelWidth); +//*** AMI PORTING END *****// + } else { +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with CopyMem to optimize performance +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) ((UINTN) MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth), + Width * VbePixelWidth, + VbeBuffer + ); +*/ + gBS->CopyMem ((UINT8*)MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth, + (UINT8*)VbeBuffer, + Width * VbePixelWidth); + } +//*** AMI PORTING END *****// + } + 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, + Width * VbePixelWidth + ); + } + + for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) { +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with CopyMem to optimize performance +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) ((UINTN) MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth), + Width * VbePixelWidth, + VbeBuffer + ); +*/ + gBS->CopyMem ((UINT8*)MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth, + (UINT8*)VbeBuffer, + Width * VbePixelWidth); +//*** AMI PORTING END *****// + } + break; + + case EfiBltBufferToVideo: +//*** AMI PORTING BEGIN ***// +//The original BLT loop is replaced to optimize performance by: +// replacing PciIo->Mem.Write with CopyMem and +// replacing multiplication with addition +/* + 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)); + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) ((UINTN) MemAddress + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth), + Width * VbePixelWidth, + VbeBuffer + ); + } +*/ +{ + UINTN VbeBufferOffset = DestinationY * BytesPerScanLine + DestinationX * VbePixelWidth; + UINT8* BltBufferAddress = BltUint8 + SourceY * Delta + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + UINTN VbeLineWidth = VbePixelWidth*Width; + UINTN BufferOffset = VbeBufferOffset; + + for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) { + + VbeBuffer = (UINT8 *) VbeFrameBuffer + BufferOffset; + + if (Mode->PixelFormat != PixelBlueGreenRedReserved8BitPerColor){ + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)BltBufferAddress; + 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 + BufferOffset; + }else{ + gBS->CopyMem (VbeBuffer, BltBufferAddress, VbeLineWidth); + } + BufferOffset += BytesPerScanLine; + BltBufferAddress += Delta; + } + BufferOffset = VbeBufferOffset; + for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) { + gBS->CopyMem ((UINT8*)MemAddress + BufferOffset, + (UINT8 *)VbeFrameBuffer + BufferOffset, + VbeLineWidth); + BufferOffset += BytesPerScanLine; + } +} +//*** AMI PORTING END *****// + break; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} +//*** AMI PORTING BEGIN ***// +#endif //if INT10_VESA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +//*** AMI PORTING BEGIN ***// +#if INT10_VGA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +STATIC +VOID +WriteGraphicsController ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINTN Address, + IN UINTN Data + ) +/*++ + +Routine Description: + + Write graphics controller registers + +Arguments: + + PciIo - Pointer to PciIo protocol instance of the controller + Address - Register address + Data - Data to be written to register + +Returns: + + None + +--*/ +{ + Address = Address | (Data << 8); + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER, + 1, + &Address + ); +} + +VOID +VgaReadBitPlanes ( + EFI_PCI_IO_PROTOCOL *PciIo, + UINT8 *HardwareBuffer, + UINT8 *MemoryBuffer, + UINTN WidthInBytes, + UINTN Height + ) +/*++ + +Routine Description: + + Read the four bit plane of VGA frame buffer + +Arguments: + + PciIo - Pointer to PciIo protocol instance of the controller + HardwareBuffer - Hardware VGA frame buffer address + MemoryBuffer - Memory buffer address + WidthInBytes - Number of bytes in a line to read + Height - Height of the area to read + +Returns: + + None + +--*/ +{ + 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) { +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with CopyMem to optimize performance +/* + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Source, + WidthInBytes, + (VOID *) Destination + ); +*/ + gBS->CopyMem ((UINT8*)Source, + (UINT8*)Destination, + WidthInBytes); +//*** AMI PORTING END *****// + } + } +} + +VOID +VgaConvertToGraphicsOutputColor ( + UINT8 *MemoryBuffer, + UINTN X, + UINTN Y, + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer + ) +/*++ + +Routine Description: + + Internal routine to convert VGA color to Grahpics Output color + +Arguments: + + MemoryBuffer - Buffer containing VGA color + X - The X coordinate of pixel on screen + Y - The Y coordinate of pixel on screen + BltBuffer - Buffer to contain converted Grahpics Output color + +Returns: + + None + +--*/ +{ + UINTN Mask; + UINTN Bit; + UINTN Color; + + MemoryBuffer += ((Y << 6) + (Y << 4) + (X >> 3)); + Mask = mVgaBitMaskTable[X & 0x07]; + for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) { + if (*MemoryBuffer & Mask) { + Color |= Bit; + } + } + + *BltBuffer = mVgaColorToGraphicsOutputColor[Color]; +} + +UINT8 +VgaConvertColor ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer + ) +/*++ + +Routine Description: + + Internal routine to convert Grahpics Output color to VGA color + +Arguments: + + BltBuffer - buffer containing Grahpics Output color + +Returns: + + Converted VGA color + +--*/ +{ + UINT8 Color; + + Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04)); +//*** AMI PORTING BEGIN ***// +// if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) { + if ((BltBuffer->Red >= 0xC0) || (BltBuffer->Blue >= 0xC0) || (BltBuffer->Green >= 0xC0)) { + Color |= 0x08; + } + // Prevent "washing out" of single color + if (((BltBuffer->Red >= 0xC0) && (BltBuffer->Blue == 0) && (BltBuffer->Green == 0)) || \ + ((BltBuffer->Blue >= 0xC0) && (BltBuffer->Red == 0) && (BltBuffer->Green == 0)) || \ + ((BltBuffer->Green >= 0xC0) && (BltBuffer->Blue == 0) && (BltBuffer->Red == 0))) { + Color &= 0x07; + } +//*** AMI PORTING END ***// + + return Color; +} + +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 + ) +/*++ + +Routine Description: + + Grahpics Output protocol instance to block transfer for VGA device + +Arguments: + + This - Pointer to Grahpics Output protocol instance + BltBuffer - The data to transfer to screen + BltOperation - The operation to perform + SourceX - The X coordinate of the source for BltOperation + SourceY - The Y coordinate of the source for BltOperation + DestinationX - The X coordinate of the destination for BltOperation + DestinationY - The Y coordinate of the destination for BltOperation + Width - The width of a rectangle in the blt rectangle in pixels + Height - The height of a rectangle in the blt rectangle in pixels + 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. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter passed in + EFI_SUCCESS - Blt operation success + +--*/ +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_TPL OriginalTPL; + UINT8 *MemAddress; + UINTN BytesPerScanLine; + UINTN BytesPerBitPlane; + 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 X; + UINTN Y; + UINTN CurrentMode; + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + +//*** AMI PORTING BEGIN ***// +// Workaround for EIP 35682. +// Allocate memory buffers during the first call of the funciton. +// See comments above AllocateTheBuffers function for additional details. + if (BiosVideoPrivate->LineBuffer==NULL){ + EFI_STATUS Status = AllocateTheBuffers(BiosVideoPrivate); + if (EFI_ERROR(Status)) return Status; + } +//*** AMI PORTING END *****// + + CurrentMode = This->Mode->Mode; + PciIo = BiosVideoPrivate->PciIo; + MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer; + BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3; + BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution; + VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer; + + if (This == NULL || ((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 > 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 (EFI_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, Y = SourceY; Rows < Height; Rows++, Y++, BltBuffer += (Delta >> 2)) { + for (Columns = 0, X = SourceX; Columns < Width; Columns++, X++, BltBuffer++) { + VgaConvertToGraphicsOutputColor (VgaFrameBuffer, X, Y, 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) (DestinationAddress + Offset), + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (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 &= 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 + // +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with direct memory access to optimize performance +/* + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address, + 1, + &Data + ); +*/ + Data = *(volatile UINT8*)(UINTN)Address; +//*** AMI PORTING END *****// + // + // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask + // +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with direct memory access to optimize performance +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address, + 1, + &PixelColor + ); +*/ + *(volatile UINT8*)(UINTN)Address = PixelColor; +//*** AMI PORTING END *****// + } + } + + 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) { +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with SetMem to optimize performance +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthFillUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address, + Bytes - 1, + &PixelColor + ); +*/ + gBS->SetMem((VOID*)Address, Bytes - 1, PixelColor); +//*** AMI PORTING END ***// + } + } + + 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 + // +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with direct memory access to optimize performance +/* + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address, + 1, + &Data + ); +*/ + Data = *(volatile UINT8*)(UINTN)Address; +//*** AMI PORTING END *****// + // + // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask + // +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with direct memory access to optimize performance +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address, + 1, + &PixelColor + ); +*/ + *(volatile UINT8*)(UINTN)Address = PixelColor; +//*** AMI PORTING END *****// + } + } + 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 + // +//*** AMI PORTING BEGIN ***// +// Replace PciIo.Mem with direct memory access to optimize performance +/* + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address1, + 1, + &Data + ); +*/ + Data = *(volatile UINT8*)(UINTN)Address1; + +/* + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Address1, + 1, + &BiosVideoPrivate->LineBuffer[Index1] + ); +*/ + *(volatile UINT8*)(UINTN)Address1 = BiosVideoPrivate->LineBuffer[Index1]; +//*** AMI PORTING END *****// + } + + LeftMask = (UINT8) (LeftMask >> 1); + if (LeftMask == 0) { + LeftMask = 0x80; + AddressFix++; + } + } + } + + break; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} +//*** AMI PORTING BEGIN ***// +#endif //if INT10_VGA_GO_SUPPORT==1 +//*** AMI PORTING END *****// +//*** AMI PORTING BEGIN ***// +#if INT10_SIMPLE_TEXT_SUPPORT==1 +//*** AMI PORTING END *****// +// +// VGA Mini Port Protocol Functions +// +EFI_STATUS +EFIAPI +BiosVideoVgaMiniPortSetMode ( + IN EFI_VGA_MINI_PORT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + +Routine Description: + + VgaMiniPort protocol interface to set mode + +Arguments: + + This - Pointer to VgaMiniPort protocol instance + ModeNumber - The index of the mode + +Returns: + + EFI_UNSUPPORTED - The requested mode is not supported + EFI_SUCCESS - The requested mode is set successfully + +--*/ +{ + 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; +} +//*** AMI PORTING BEGIN ***// +#endif //if INT10_SIMPLE_TEXT_SUPPORT==1 +//*** AMI PORTING END *****// +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |