1177 lines
35 KiB
C
1177 lines
35 KiB
C
/** @file
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
/**
|
|
This module install ACPI Boot Graphics Resource Table (BGRT).
|
|
|
|
Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
**/
|
|
|
|
#include <BootGraphicsResourceTableDxe.h>
|
|
#include <Protocol/AcpiSupport.h>
|
|
#include <IndustryStandard/Pci22.h>
|
|
|
|
//
|
|
// ACPI table information used to initialize tables.
|
|
//
|
|
#define EFI_ACPI_OEM_ID 'I','N','S','Y','D','E'
|
|
#define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64('H','2','O',' ','B','I','O','S')
|
|
#define EFI_ACPI_OEM_REVISION 0x00000001
|
|
#define EFI_ACPI_CREATOR_ID SIGNATURE_32('A','C','P','I')
|
|
#define EFI_ACPI_CREATOR_REVISION 0x00040000
|
|
|
|
//
|
|
// Module globals.
|
|
//
|
|
EFI_EVENT mBootGraphicsReadyToBootEvent;
|
|
EFI_EVENT mBootGraphicsLegacyBootEvent;
|
|
UINTN mBootGraphicsResourceTableKey = 0;
|
|
|
|
EFI_HANDLE mBootLogoHandle = NULL;
|
|
BOOLEAN mIsLogoValid = FALSE;
|
|
BOOLEAN mIsMonitor = FALSE;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mLogoBltBuffer = NULL;
|
|
UINTN mLogoDestX = 0;
|
|
UINTN mLogoDestY = 0;
|
|
UINTN mLogoWidth = 0;
|
|
UINTN mLogoHeight = 0;
|
|
|
|
BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {
|
|
'B', // CharB
|
|
'M', // CharM
|
|
0, // Size will be updated at runtime
|
|
{0, 0}, // Reserved
|
|
sizeof (BMP_IMAGE_HEADER), // ImageOffset
|
|
sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
|
|
0, // PixelWidth will be updated at runtime
|
|
0, // PixelHeight will be updated at runtime
|
|
1, // Planes
|
|
24, // BitPerPixel
|
|
0, // CompressionType
|
|
0, // ImageSize will be updated at runtime
|
|
0, // XPixelsPerMeter
|
|
0, // YPixelsPerMeter
|
|
0, // NumberOfColors
|
|
0 // ImportantColors
|
|
};
|
|
|
|
BOOLEAN mAcpiBgrtInstalled = FALSE;
|
|
|
|
EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = {
|
|
{
|
|
EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE,
|
|
sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
|
|
EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION, // Revision
|
|
0x00, // Checksum will be updated at runtime
|
|
//
|
|
// It is expected that these values will be updated at runtime.
|
|
//
|
|
EFI_ACPI_OEM_ID, // OEMID is a 6 bytes long field
|
|
EFI_ACPI_OEM_TABLE_ID, // OEM table identification(8 bytes long)
|
|
EFI_ACPI_OEM_REVISION, // OEM revision number
|
|
EFI_ACPI_CREATOR_ID, // ASL compiler vendor ID
|
|
EFI_ACPI_CREATOR_REVISION, // ASL compiler revision number
|
|
},
|
|
EFI_ACPI_5_0_BGRT_VERSION, // Version
|
|
EFI_ACPI_5_0_BGRT_STATUS_VALID, // Status
|
|
EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP, // Image Type
|
|
0, // Image Address
|
|
0, // Image Offset X
|
|
0 // Image Offset Y
|
|
};
|
|
|
|
HOOKED_GOP_BLT_SET_MODE *mGopHookedList = NULL;
|
|
UINTN mNumberofGops = 0;
|
|
UINT32 mLogoResolutionX = 0;
|
|
UINT32 mLogoResolutionY = 0;
|
|
BOOLEAN mIsUpdateCoordinate = FALSE;
|
|
UINTN mCurNoGopDrvBinding = 0;
|
|
HOOKED_GOP_DRV_BINDING *mGopBindingHookedList = NULL;
|
|
|
|
/**
|
|
Update information of logo image drawn on screen.
|
|
|
|
@param This The pointer to the Boot Logo protocol instance.
|
|
@param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
|
|
is set to NULL, it indicates that logo image is no
|
|
longer on the screen.
|
|
@param DestinationX X coordinate of destination for the BltBuffer.
|
|
@param DestinationY Y coordinate of destination for the BltBuffer.
|
|
@param Width Width of rectangle in BltBuffer in pixels.
|
|
@param Height Hight of rectangle in BltBuffer in pixels.
|
|
|
|
@retval EFI_SUCCESS The boot logo information was updated.
|
|
@retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
|
|
@retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
|
|
insufficient memory resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetBootLogo (
|
|
IN EFI_BOOT_LOGO_PROTOCOL *This,
|
|
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
|
|
IN UINTN DestinationX,
|
|
IN UINTN DestinationY,
|
|
IN UINTN Width,
|
|
IN UINTN Height
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DummyBlt (
|
|
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 OPTIONAL
|
|
);
|
|
|
|
EFI_STATUS
|
|
UninstallBootGraphicsResourceTable (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EFIAPI
|
|
GopInstallCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DummySetMode (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
|
|
IN UINT32 ModeNumber
|
|
);
|
|
|
|
VOID
|
|
BgrtGetLogoCoordinate (
|
|
IN UINTN ResolutionX,
|
|
IN UINTN ResolutionY,
|
|
IN UINTN ImageWidth,
|
|
IN UINTN ImageHeight,
|
|
OUT UINTN *CoordinateX,
|
|
OUT UINTN *CoordinateY
|
|
);
|
|
|
|
VOID
|
|
UpdateLogoPosition (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput
|
|
);
|
|
|
|
VOID
|
|
HookGopStartFun (
|
|
VOID
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DummyGopBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
CheckGopHook (
|
|
VOID
|
|
);
|
|
|
|
EFI_BOOT_LOGO_PROTOCOL mBootLogoProtocolTemplate = { SetBootLogo };
|
|
|
|
/**
|
|
Update information of logo image drawn on screen.
|
|
|
|
@param This The pointer to the Boot Logo protocol instance.
|
|
@param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
|
|
is set to NULL, it indicates that logo image is no
|
|
longer on the screen.
|
|
@param DestinationX X coordinate of destination for the BltBuffer.
|
|
@param DestinationY Y coordinate of destination for the BltBuffer.
|
|
@param Width Width of rectangle in BltBuffer in pixels.
|
|
@param Height Hight of rectangle in BltBuffer in pixels.
|
|
|
|
@retval EFI_SUCCESS The boot logo information was updated.
|
|
@retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
|
|
@retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
|
|
insufficient memory resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetBootLogo (
|
|
IN EFI_BOOT_LOGO_PROTOCOL *This,
|
|
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
|
|
IN UINTN DestinationX,
|
|
IN UINTN DestinationY,
|
|
IN UINTN Width,
|
|
IN UINTN Height
|
|
)
|
|
{
|
|
UINT64 BufferSize;
|
|
EFI_STATUS Status;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
|
|
|
if (BltBuffer == NULL) {
|
|
mIsLogoValid = FALSE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (Width == 0 || Height == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (mLogoBltBuffer != NULL) {
|
|
FreePool (mLogoBltBuffer);
|
|
mLogoBltBuffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Ensure the Height * Width doesn't overflow
|
|
//
|
|
if (Height > DivU64x64Remainder ((UINTN) ~0, Width, NULL)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
BufferSize = MultU64x64 (Width, Height);
|
|
|
|
//
|
|
// Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
|
|
//
|
|
if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
mLogoBltBuffer = AllocateCopyPool (
|
|
(UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
|
|
BltBuffer
|
|
);
|
|
if (mLogoBltBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
mLogoDestX = DestinationX;
|
|
mLogoDestY = DestinationY;
|
|
mLogoWidth = Width;
|
|
mLogoHeight = Height;
|
|
|
|
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
|
|
if (!EFI_ERROR (Status)) {
|
|
mLogoResolutionX = GraphicsOutput->Mode->Info->HorizontalResolution;
|
|
mLogoResolutionY = GraphicsOutput->Mode->Info->VerticalResolution;
|
|
}
|
|
if (mNumberofGops == 0) {
|
|
mIsLogoValid = FALSE;
|
|
} else {
|
|
mIsLogoValid = TRUE;
|
|
}
|
|
mIsMonitor = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function calculates and updates an UINT8 checksum.
|
|
|
|
@param[in] Buffer Pointer to buffer to checksum.
|
|
@param[in] Size Number of bytes to checksum.
|
|
|
|
**/
|
|
VOID
|
|
BgrtAcpiTableChecksum (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
UINTN ChecksumOffset;
|
|
|
|
ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
|
|
|
|
//
|
|
// Set checksum to 0 first.
|
|
//
|
|
Buffer[ChecksumOffset] = 0;
|
|
|
|
//
|
|
// Update checksum value.
|
|
//
|
|
Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
|
|
}
|
|
|
|
/**
|
|
Allocate EfiReservedMemoryType below 4G memory address.
|
|
|
|
This function allocates EfiReservedMemoryType below 4G memory address.
|
|
|
|
@param[in] Size Size of memory to allocate.
|
|
|
|
@return Allocated address for output.
|
|
|
|
**/
|
|
VOID *
|
|
BgrtAllocateMemoryBelow4G (
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
UINTN Pages;
|
|
EFI_PHYSICAL_ADDRESS Address;
|
|
EFI_STATUS Status;
|
|
VOID *Buffer;
|
|
|
|
Pages = EFI_SIZE_TO_PAGES (Size);
|
|
Address = 0xffffffff;
|
|
//
|
|
// According to the Acpi5.0, the memory type of Boot image must be the EfiBootServicesData!
|
|
// and BGRT only is supported on Uefi system.
|
|
// That's different to the EDKII implementation of BGRT.
|
|
// The EDKII used the EfiReservedMemoryType memory type which can support the legacy and Uefi system,
|
|
// but it violate the Acpi5.0 spec.
|
|
//
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiBootServicesData,
|
|
Pages,
|
|
&Address
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Buffer = (VOID *) (UINTN) Address;
|
|
ZeroMem (Buffer, Size);
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
/**
|
|
Install Boot Graphics Resource Table to ACPI table.
|
|
|
|
@return Status code.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InstallBootGraphicsResourceTable (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
|
|
UINT8 *ImageBuffer;
|
|
UINTN PaddingSize;
|
|
UINTN BmpSize;
|
|
UINTN OrigBmpSize;
|
|
UINT8 *Image;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
|
|
UINTN Col;
|
|
UINTN Row;
|
|
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
|
|
EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
|
|
|
//
|
|
// Check whether Boot Graphics Resource Table is already installed.
|
|
//
|
|
if (mAcpiBgrtInstalled) {
|
|
Status = UninstallBootGraphicsResourceTable ();
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get ACPI Table protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check whether Logo exist.
|
|
//
|
|
if (mLogoBltBuffer == NULL) {
|
|
Status = LogoLibSetBootLogo ();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
mIsLogoValid = FALSE;
|
|
}
|
|
|
|
if (mLogoBltBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (mBootGraphicsResourceTableTemplate.ImageAddress != 0) {
|
|
//
|
|
// reserve original BGRT buffer size
|
|
//
|
|
OrigBmpSize = mBmpImageHeaderTemplate.ImageSize + sizeof (BMP_IMAGE_HEADER);
|
|
//
|
|
// Free orignal BMP memory
|
|
//
|
|
if (mBootGraphicsResourceTableTemplate.ImageAddress) {
|
|
gBS->FreePages(mBootGraphicsResourceTableTemplate.ImageAddress, EFI_SIZE_TO_PAGES (OrigBmpSize));
|
|
}
|
|
mBootGraphicsResourceTableTemplate.ImageAddress = 0;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for BMP file.
|
|
//
|
|
PaddingSize = mLogoWidth & 0x3;
|
|
|
|
//
|
|
// First check mLogoWidth * 3 + PaddingSize doesn't overflow
|
|
//
|
|
if (mLogoWidth > (((UINT32) ~0) - PaddingSize) / 3 ) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
|
|
//
|
|
if (mLogoHeight > (((UINT32) ~0) - sizeof (BMP_IMAGE_HEADER)) / (mLogoWidth * 3 + PaddingSize)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
BmpSize = (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER);
|
|
ImageBuffer = BgrtAllocateMemoryBelow4G (BmpSize);
|
|
if (ImageBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
mBmpImageHeaderTemplate.Size = (UINT32) BmpSize;
|
|
mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER);
|
|
mBmpImageHeaderTemplate.PixelWidth = (UINT32) mLogoWidth;
|
|
mBmpImageHeaderTemplate.PixelHeight = (UINT32) mLogoHeight;
|
|
CopyMem (ImageBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
|
|
|
|
//
|
|
// Convert BLT buffer to BMP file.
|
|
//
|
|
Image = ImageBuffer + sizeof (BMP_IMAGE_HEADER);
|
|
for (Row = 0; Row < mLogoHeight; Row++) {
|
|
BltPixel = &mLogoBltBuffer[(mLogoHeight - Row - 1) * mLogoWidth];
|
|
|
|
if (BltPixel != NULL) {
|
|
for (Col = 0; Col < mLogoWidth; Col++) {
|
|
*Image++ = BltPixel->Blue;
|
|
*Image++ = BltPixel->Green;
|
|
*Image++ = BltPixel->Red;
|
|
BltPixel++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Padding for 4 byte alignment.
|
|
//
|
|
Image += PaddingSize;
|
|
}
|
|
//
|
|
// Check Screen Mode
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **)&ConsoleControl);
|
|
if (!EFI_ERROR (Status)) {
|
|
ConsoleControl->GetMode (ConsoleControl, &CurrentMode, NULL, NULL);
|
|
if (CurrentMode != EfiConsoleControlScreenGraphics) {
|
|
mIsLogoValid = FALSE;
|
|
}
|
|
}
|
|
|
|
mBootGraphicsResourceTableTemplate.Status = (UINT8) (mIsLogoValid ? EFI_ACPI_5_0_BGRT_STATUS_VALID : EFI_ACPI_5_0_BGRT_STATUS_INVALID);
|
|
mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64) (UINTN) ImageBuffer;
|
|
if (mIsUpdateCoordinate == FALSE) {
|
|
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
|
|
if (!EFI_ERROR (Status)) {
|
|
UpdateLogoPosition (GraphicsOutput);
|
|
}
|
|
mIsUpdateCoordinate = TRUE;
|
|
}
|
|
mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32) mLogoDestX;
|
|
mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32) mLogoDestY;
|
|
|
|
//
|
|
// Update Checksum.
|
|
//
|
|
BgrtAcpiTableChecksum ((UINT8 *) &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE));
|
|
|
|
//
|
|
// Publish Boot Graphics Resource Table.
|
|
//
|
|
Status = AcpiTableProtocol->InstallAcpiTable (
|
|
AcpiTableProtocol,
|
|
&mBootGraphicsResourceTableTemplate,
|
|
sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
|
|
&mBootGraphicsResourceTableKey
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
mAcpiBgrtInstalled = TRUE;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Uninstall Boot Graphics Resource Table to ACPI table.
|
|
|
|
@return Status code.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UninstallBootGraphicsResourceTable (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
|
|
EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport;
|
|
UINTN Index;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table;
|
|
UINTN Handle;
|
|
EFI_ACPI_TABLE_VERSION Version;
|
|
UINT8 *BytePtr;
|
|
UINT8 *BytePtr2;
|
|
BOOLEAN FoundBGRT;
|
|
|
|
//
|
|
//init local vars
|
|
//
|
|
AcpiSupport = NULL;
|
|
Index = 0;
|
|
Table = NULL;
|
|
BytePtr = NULL;
|
|
FoundBGRT = FALSE;
|
|
|
|
//
|
|
// found BGRT table
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiAcpiSupportProtocolGuid,
|
|
NULL,
|
|
(VOID **)&AcpiSupport
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
do {
|
|
Status = AcpiSupport->GetAcpiTable (
|
|
AcpiSupport,
|
|
Index,
|
|
(VOID **)&Table,
|
|
&Version,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (Table->Signature == EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE) {
|
|
FoundBGRT = TRUE;
|
|
break;
|
|
}
|
|
FreePool (Table);
|
|
Table = NULL;
|
|
}
|
|
Index++;
|
|
} while (Status != EFI_NOT_FOUND);
|
|
|
|
if (FoundBGRT == FALSE) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// keep OEM BGRT Information
|
|
//
|
|
BytePtr = (UINT8*)&mBootGraphicsResourceTableTemplate;
|
|
BytePtr2 = (UINT8*)Table;
|
|
gBS->CopyMem (BytePtr + 10, BytePtr2 + 10, 28);
|
|
FreePool (Table);
|
|
|
|
//
|
|
// Get ACPI Table protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (mAcpiBgrtInstalled == TRUE) {
|
|
Status = AcpiTableProtocol->UninstallAcpiTable (
|
|
AcpiTableProtocol,
|
|
mBootGraphicsResourceTableKey
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
|
|
install the Boot Graphics Resource Table.
|
|
|
|
@param[in] Event The Event that is being processed.
|
|
@param[in] Context The Event Context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
BgrtReadyToBootEventNotify (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
InstallBootGraphicsResourceTable ();
|
|
}
|
|
|
|
/**
|
|
Notify function for event EFI_EVENT_LEGACY_BOOT. This is used to
|
|
uninstall the Boot Graphics Resource Table.
|
|
|
|
@param[in] Event The Event that is being processed.
|
|
@param[in] Context The Event Context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
BgrtLegacyBootEventNotify (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
UninstallBootGraphicsResourceTable ();
|
|
}
|
|
|
|
/**
|
|
The module Entry Point of the Boot Graphics Resource Table DXE driver.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval Other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootGraphicsDxeEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_EVENT GopInstallEvent;
|
|
VOID *Registration;
|
|
|
|
//
|
|
// Install Boot Logo protocol.
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&mBootLogoHandle,
|
|
&gEfiBootLogoProtocolGuid,
|
|
&mBootLogoProtocolTemplate,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Register notify function to install BGRT on ReadyToBoot Event.
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
BgrtReadyToBootEventNotify,
|
|
NULL,
|
|
&gEfiEventReadyToBootGuid,
|
|
&mBootGraphicsReadyToBootEvent
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
|
// Create An Event to Hook Physical Gop->Blt
|
|
//
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
GopInstallCallback,
|
|
NULL,
|
|
&GopInstallEvent
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
GopInstallEvent,
|
|
&Registration
|
|
);
|
|
}
|
|
}
|
|
//
|
|
// According to the description of BGRT in ACPI 5.0 spec
|
|
// that the BGRT only supported on Uefi system.
|
|
// Removed the Table when boot to legacy system.
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
BgrtLegacyBootEventNotify,
|
|
NULL,
|
|
&gEfiEventLegacyBootGuid,
|
|
&mBootGraphicsLegacyBootEvent
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DummyBlt (
|
|
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 OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN ListIndex;
|
|
UINTN SizeOfInfo;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if (mNumberofGops <= 0) {
|
|
return EFI_NOT_STARTED;
|
|
}
|
|
|
|
for (ListIndex = 0; ListIndex < mNumberofGops; ListIndex++) {
|
|
if (mGopHookedList[ListIndex].Gop == This) {
|
|
if (BltOperation == EfiBltVideoFill) {
|
|
if (mGopHookedList[ListIndex].BltWidth == 0 && mGopHookedList[ListIndex].BltHeight == 0) {
|
|
//
|
|
// This indicates that screen has already been cleared when gop driver inits screen.
|
|
// So, Save initial clear screen's context.
|
|
//
|
|
This->QueryMode (This, This->Mode->Mode, &SizeOfInfo, &Info);
|
|
mGopHookedList[ListIndex].BltWidth = Info->HorizontalResolution;
|
|
mGopHookedList[ListIndex].BltHeight = Info->VerticalResolution;
|
|
mGopHookedList[ListIndex].BltColor = 0;
|
|
mGopHookedList[ListIndex].BltX = 0;
|
|
mGopHookedList[ListIndex].BltY = 0;
|
|
}
|
|
if (*(UINT32*)BltBuffer == mGopHookedList[ListIndex].BltColor &&
|
|
DestinationX == mGopHookedList[ListIndex].BltX &&
|
|
DestinationY == mGopHookedList[ListIndex].BltY &&
|
|
Width == mGopHookedList[ListIndex].BltWidth &&
|
|
Height == mGopHookedList[ListIndex].BltHeight) {
|
|
//
|
|
// Skip the operation if last operation same as this time
|
|
//
|
|
continue;
|
|
} else {
|
|
//
|
|
// Record the last X, Y, W, H for next comparison
|
|
//
|
|
mGopHookedList[ListIndex].BltColor = *(UINT32*)BltBuffer;
|
|
mGopHookedList[ListIndex].BltX = DestinationX;
|
|
mGopHookedList[ListIndex].BltY = DestinationY;
|
|
mGopHookedList[ListIndex].BltWidth = Width;
|
|
mGopHookedList[ListIndex].BltHeight = Height;
|
|
}
|
|
} else {
|
|
//
|
|
// Destroy the record due to normal Blt be called
|
|
//
|
|
mGopHookedList[ListIndex].BltWidth = (UINTN)-1;
|
|
}
|
|
Status = mGopHookedList[ListIndex].HookedBlt (
|
|
This,
|
|
BltBuffer,
|
|
BltOperation,
|
|
SourceX,
|
|
SourceY,
|
|
DestinationX,
|
|
DestinationY,
|
|
Width,
|
|
Height,
|
|
Delta
|
|
);
|
|
}
|
|
}
|
|
|
|
if (BltOperation != EfiBltVideoToBltBuffer &&
|
|
!EFI_ERROR (Status) &&
|
|
mIsMonitor &&
|
|
mIsLogoValid &&
|
|
(DestinationY <= mLogoDestY + mLogoHeight)) {
|
|
mIsLogoValid = FALSE;
|
|
InstallBootGraphicsResourceTable ();
|
|
}
|
|
return Status;
|
|
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
GopInstallCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
CheckGopHook ();
|
|
HookGopStartFun ();
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DummySetMode (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
|
|
IN UINT32 ModeNumber
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN ListIndex;
|
|
UINTN SizeOfInfo;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if (mNumberofGops <= 0) {
|
|
return EFI_NOT_STARTED;
|
|
}
|
|
|
|
for (ListIndex = 0; ListIndex < mNumberofGops; ListIndex++) {
|
|
if (mGopHookedList[ListIndex].Gop == This) {
|
|
Status = mGopHookedList[ListIndex].HookedSetMode (This,ModeNumber);
|
|
//
|
|
// Get current resolution used for reduce the redundancy clear screen
|
|
//
|
|
This->QueryMode (This, This->Mode->Mode, &SizeOfInfo, &Info);
|
|
mGopHookedList[ListIndex].BltColor = 0;
|
|
mGopHookedList[ListIndex].BltX = 0;
|
|
mGopHookedList[ListIndex].BltY = 0;
|
|
mGopHookedList[ListIndex].BltWidth = Info->HorizontalResolution;
|
|
mGopHookedList[ListIndex].BltHeight = Info->VerticalResolution;
|
|
FreePool (Info);
|
|
Info = NULL;
|
|
}
|
|
}
|
|
|
|
mIsLogoValid = FALSE;
|
|
if ((!EFI_ERROR (Status)) && mIsUpdateCoordinate == TRUE) {
|
|
UpdateLogoPosition (This);
|
|
InstallBootGraphicsResourceTable ();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UpdateLogoPosition (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput
|
|
)
|
|
{
|
|
|
|
if (mLogoResolutionX == GraphicsOutput->Mode->Info->HorizontalResolution &&
|
|
mLogoResolutionY == GraphicsOutput->Mode->Info->VerticalResolution) {
|
|
return;
|
|
}
|
|
|
|
BgrtGetLogoCoordinate (
|
|
GraphicsOutput->Mode->Info->HorizontalResolution,
|
|
GraphicsOutput->Mode->Info->VerticalResolution,
|
|
mLogoWidth,
|
|
mLogoHeight,
|
|
&mLogoDestX,
|
|
&mLogoDestY
|
|
);
|
|
|
|
mLogoResolutionX = GraphicsOutput->Mode->Info->HorizontalResolution;
|
|
mLogoResolutionY = GraphicsOutput->Mode->Info->VerticalResolution;
|
|
mIsLogoValid = FALSE;
|
|
}
|
|
|
|
VOID
|
|
HookGopStartFun (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN NoHandles;
|
|
EFI_HANDLE *HandleBuf;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
|
UINTN EntryCount;
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UINTN Index3;
|
|
EFI_HANDLE ControllerHandle;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT8 BaseClassCode;
|
|
EFI_HANDLE GopDrvImgHandle;
|
|
EFI_STATUS Status;
|
|
UINT32 Attributes;
|
|
EFI_DRIVER_BINDING_PROTOCOL *TempGopDrvBinding;
|
|
|
|
//
|
|
//init locals
|
|
//
|
|
GopDrvImgHandle = NULL;
|
|
TempGopDrvBinding = NULL;
|
|
|
|
//
|
|
// find gop driver's binding protocol
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&NoHandles,
|
|
&HandleBuf
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return ;
|
|
}
|
|
|
|
for (Index = 0; Index < NoHandles; Index++) {
|
|
Status = gBS->OpenProtocolInformation (
|
|
HandleBuf[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
&OpenInfoBuffer,
|
|
&EntryCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
for (Index2 = 0; Index2 < EntryCount; Index2++) {
|
|
ControllerHandle = OpenInfoBuffer[Index2].ControllerHandle;
|
|
Attributes = OpenInfoBuffer[Index2].Attributes;
|
|
|
|
if (ControllerHandle == NULL ||
|
|
Attributes != EFI_OPEN_PROTOCOL_BY_DRIVER) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **)&PciIo
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0x0b,
|
|
1,
|
|
&BaseClassCode
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (BaseClassCode != PCI_CLASS_DISPLAY) {
|
|
continue;
|
|
}
|
|
|
|
GopDrvImgHandle = OpenInfoBuffer[Index2].AgentHandle;
|
|
Status = gBS->HandleProtocol (
|
|
GopDrvImgHandle,
|
|
&gEfiDriverBindingProtocolGuid,
|
|
(VOID **)&TempGopDrvBinding
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
|
|
for (Index3 = 0; Index3 < mCurNoGopDrvBinding; Index3++) {
|
|
if (mGopBindingHookedList != NULL && mGopBindingHookedList[Index3].GopDriverBinding == TempGopDrvBinding) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index3 != mCurNoGopDrvBinding) {
|
|
continue;
|
|
}
|
|
|
|
mGopBindingHookedList = ReallocatePool (
|
|
sizeof (HOOKED_GOP_DRV_BINDING) * mCurNoGopDrvBinding,
|
|
sizeof (HOOKED_GOP_DRV_BINDING) * (mCurNoGopDrvBinding + 1),
|
|
mGopBindingHookedList
|
|
);
|
|
if (mGopBindingHookedList == NULL) {
|
|
continue;
|
|
}
|
|
mCurNoGopDrvBinding += 1;
|
|
|
|
mGopBindingHookedList[mCurNoGopDrvBinding - 1].GopDriverBinding = TempGopDrvBinding;
|
|
mGopBindingHookedList[mCurNoGopDrvBinding - 1].HookedGopStartFun = TempGopDrvBinding->Start;
|
|
TempGopDrvBinding->Start = DummyGopBindingStart;
|
|
}
|
|
|
|
FreePool (OpenInfoBuffer);
|
|
}
|
|
|
|
FreePool (HandleBuf);
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DummyGopBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN ListIndex;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if (mNumberofGops <= 0) {
|
|
return EFI_NOT_STARTED;
|
|
}
|
|
|
|
for (ListIndex = 0; ListIndex < mCurNoGopDrvBinding; ListIndex++) {
|
|
if (mGopBindingHookedList[ListIndex].GopDriverBinding == This) {
|
|
Status = mGopBindingHookedList[ListIndex].HookedGopStartFun (
|
|
This,
|
|
ControllerHandle,
|
|
RemainingDevicePath
|
|
);
|
|
|
|
CheckGopHook ();
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
CheckGopHook (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN NumberOfHandles;
|
|
UINTN Index;
|
|
EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
|
|
EFI_STATUS Status;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
|
HOOKED_GOP_BLT_SET_MODE *ThisGopHookedList;
|
|
UINTN GopCount;
|
|
UINTN ListIndex;
|
|
BOOLEAN NotInHookList;
|
|
|
|
GopCount = 0;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandles,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
ThisGopHookedList = mGopHookedList;
|
|
mGopHookedList = AllocateZeroPool (sizeof (HOOKED_GOP_BLT_SET_MODE) * NumberOfHandles);
|
|
ASSERT (mGopHookedList != NULL);
|
|
if (mGopHookedList == NULL) {
|
|
return ;
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID*)&GopDevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
(VOID **)&GraphicsOutput
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
NotInHookList = TRUE;
|
|
|
|
for (ListIndex = 0; ListIndex < mNumberofGops; ListIndex++) {
|
|
if (ThisGopHookedList[ListIndex].Gop == GraphicsOutput) {
|
|
NotInHookList = FALSE;
|
|
mGopHookedList[GopCount].Gop = ThisGopHookedList[ListIndex].Gop;
|
|
mGopHookedList[GopCount].HookedBlt = ThisGopHookedList[ListIndex].HookedBlt;
|
|
mGopHookedList[GopCount].HookedSetMode = ThisGopHookedList[ListIndex].HookedSetMode;
|
|
mGopHookedList[GopCount].BltColor = ThisGopHookedList[ListIndex].BltColor;
|
|
mGopHookedList[GopCount].BltX = ThisGopHookedList[ListIndex].BltX;
|
|
mGopHookedList[GopCount].BltY = ThisGopHookedList[ListIndex].BltY;
|
|
mGopHookedList[GopCount].BltWidth = ThisGopHookedList[ListIndex].BltWidth;
|
|
mGopHookedList[GopCount].BltHeight = ThisGopHookedList[ListIndex].BltHeight;
|
|
|
|
if(ThisGopHookedList[ListIndex].HookedBlt == GraphicsOutput->Blt &&
|
|
ThisGopHookedList[ListIndex].HookedSetMode == GraphicsOutput->SetMode) {
|
|
//
|
|
// Need to rehook blt & setmode, since blt & setmode has been changed back by gop driver.
|
|
//
|
|
GraphicsOutput->Blt = DummyBlt;
|
|
GraphicsOutput->SetMode = DummySetMode;
|
|
}
|
|
GopCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (NotInHookList == TRUE) {
|
|
mGopHookedList[GopCount].Gop = GraphicsOutput;
|
|
mGopHookedList[GopCount].HookedBlt = GraphicsOutput->Blt;
|
|
mGopHookedList[GopCount].HookedSetMode = GraphicsOutput->SetMode;
|
|
GraphicsOutput->Blt = DummyBlt;
|
|
GraphicsOutput->SetMode = DummySetMode;
|
|
GopCount++;
|
|
}
|
|
}
|
|
|
|
mNumberofGops = GopCount;
|
|
if (ThisGopHookedList) {
|
|
FreePool (ThisGopHookedList);
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
|
|
}
|