alder_lake_bios/Insyde/InsydeModulePkg/Library/OemGraphicsLib/Graphics.c

4166 lines
127 KiB
C

/** @file
Support for Basic Graphics operations.
;******************************************************************************
;* Copyright (c) 2012 - 2021, Insyde Software Corporation. 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.
;*
;******************************************************************************
*/
#include "Library/OemGraphicsLib.h"
#include <IndustryStandard/Bmp.h>
#include <Protocol/JpegDecoder.h>
#include <Protocol/PcxDecoder.h>
#include <Protocol/TgaDecoder.h>
#include <Protocol/GifDecoder.h>
#include <Protocol/BmpDecoder.h>
#include <Protocol/PngDecoder.h>
#include <Protocol/BootLogo.h>
#include <Protocol/UgaDraw.h>
#include <Protocol/EndOfDisableQuietBoot.h>
#include <Protocol/ConsoleControl.h>
#include <Protocol/DynamicHotKey.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PcdLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DxeOemSvcKernelLib.h>
#include <Library/VariableLib.h>
#include <Library/H2OCpLib.h>
#include <Guid/Jpeg.h>
#include <Guid/ConsoleOutDevice.h>
#include <Guid/H2OBdsCheckPoint.h>
#include <Guid/EsrtCrbFirmwareGuid.h>
#include <Guid/ImageAuthentication.h>
#include <Guid/EfiSystemResourceTable.h>
#include <Protocol/Hash2.h>
#include <VesaBiosExtensions.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/FlashRegionLib.h>
#include <H2OBoardId.h>
#define SIZE_OF_QA_TEST_KEY 0x311
STATIC UINT8 mQACertificateHashData[SHA256_DIGEST_SIZE] = {
0xF1, 0x47, 0x00, 0xFC, 0xCA, 0x6A, 0xED, 0x9C, 0x5D, 0x33, 0xF3, 0x56, 0xE3, 0xF8, 0xA3, 0x41,
0x3B, 0xED, 0xA7, 0x6D, 0xAC, 0xAA, 0x13, 0x24, 0xB0, 0x0E, 0x3D, 0x0A, 0x05, 0x44, 0x6b, 0x18
};
#define IS_VALID_PERCENTAGE_VALUE(x) (ABS(x) <= 100)
typedef struct {
UINT8 *Blt;
UINTN ImageWidth;
UINTN ImageHeight;
UINTN DestinationX;
UINTN DestinationY;
INT8 Priority;
} LOGO_INFO_DATA;
//
// Record the current VGA Mode from EFI code
//
#define EFI_CURRENT_VGA_MODE_ADDRESS 0x4A3
//
// Record the current VGA Mode from VGA OpRom
//
#define CURRENT_VGA_MODE_ADDRESS 0x449
//
// Priority definition of Logo.
//
#define LOWEST_LOGO_PRIORITY -128
STATIC UINTN mAutoPlaceStrDestY = (UINTN) (-1);
STATIC UINTN mAutoPlaceStrCount;
/**
Get GOP protocol instance.
@param[out] GraphicsOutput Graphics Output Protocol instance pointer.
@retval EFI_SUCCESS Get GOP protocol instance success.
@retval Others Failed to get GOP protocol instance.
**/
EFI_STATUS
GetBootGop (
OUT EFI_GRAPHICS_OUTPUT_PROTOCOL **GraphicsOutput
)
{
EFI_STATUS Status;
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) GraphicsOutput);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
BOOLEAN
IsModeSync (
VOID
);
EFI_STATUS
BgrtDecodeImageToBlt (
IN UINT8 *ImageData,
IN UINTN ImageSize,
IN EFI_BADGING_SUPPORT_FORMAT ImageFormat,
IN OUT UINT8 **Blt,
IN OUT UINTN *Width,
IN OUT UINTN *Height
)
{
EFI_STATUS Status;
UINTN BltSize;
EFI_JPEG_DECODER_PROTOCOL *JpegDecoder;
EFI_PCX_DECODER_PROTOCOL *PcxDecoder;
EFI_TGA_DECODER_PROTOCOL *TgaDecoder;
EFI_GIF_DECODER_PROTOCOL *GifDecoder;
EFI_BMP_DECODER_PROTOCOL *BmpDecoder;
EFI_PNG_DECODER_PROTOCOL *PngDecoder;
BOOLEAN HasAlphaChannel;
TGA_FORMAT TgaFormate;
EFI_JPEG_DECODER_STATUS DecoderStatus;
ANIMATION *Animation;
switch (ImageFormat) {
case EfiBadgingSupportFormatBMP:
Status = gBS->LocateProtocol (&gEfiBmpDecoderProtocolGuid, NULL, (VOID **) &BmpDecoder);
if (EFI_ERROR (Status)) {
break;
}
Status = BmpDecoder->DecodeImage (
BmpDecoder,
ImageData,
ImageSize,
Blt,
&BltSize,
Height,
Width
);
break;
case EfiBadgingSupportFormatTGA:
Status = gBS->LocateProtocol (&gEfiTgaDecoderProtocolGuid, NULL, (VOID **)&TgaDecoder);
if (EFI_ERROR (Status)) {
break;
}
Status = TgaDecoder->DecodeImage (
TgaDecoder,
ImageData,
ImageSize,
Blt,
&BltSize,
Height,
Width,
&TgaFormate,
&HasAlphaChannel
);
break;
case EfiBadgingSupportFormatJPEG:
Status = gBS->LocateProtocol (&gEfiJpegDecoderProtocolGuid, NULL, (VOID **)&JpegDecoder);
if (EFI_ERROR (Status)) {
break;
}
Status = JpegDecoder->DecodeImage (
JpegDecoder,
ImageData,
ImageSize,
Blt,
&BltSize,
Height,
Width,
&DecoderStatus
);
break;
case EfiBadgingSupportFormatPCX:
Status = gBS->LocateProtocol (&gEfiPcxDecoderProtocolGuid, NULL, (VOID **)&PcxDecoder);
if (EFI_ERROR (Status)) {
break;
}
Status = PcxDecoder->DecodeImage (
PcxDecoder,
ImageData,
ImageSize,
Blt,
&BltSize,
Height,
Width
);
break;
case EfiBadgingSupportFormatPNG:
Status = gBS->LocateProtocol (&gEfiPngDecoderProtocolGuid, NULL, (VOID **)&PngDecoder);
if (EFI_ERROR (Status)) {
break;
}
Status = PngDecoder->DecodeImage (
PngDecoder,
ImageData,
ImageSize,
Blt,
&BltSize,
Height,
Width
);
break;
case EfiBadgingSupportFormatGIF:
Status = gBS->LocateProtocol (&gEfiGifDecoderProtocolGuid, NULL, (VOID **)&GifDecoder);
if (EFI_ERROR (Status)) {
break;
}
//
// BGRT only support the first image if .gif file.
//
Status = GifDecoder->CreateAnimationFromMem (
GifDecoder,
ImageData,
ImageSize,
NULL,
&Animation
);
if (!EFI_ERROR (Status)) {
*Width = Animation->Width;
*Height = Animation->Height;
BltSize = Animation->Width * Animation->Height * sizeof (EFI_UGA_PIXEL);
*Blt = AllocateZeroPool (BltSize);
if (*Blt != NULL) {
CopyMem (*Blt, Animation->Frames->Bitmap, BltSize);
GifDecoder->DestroyAnimation (GifDecoder, Animation);
} else {
Status = EFI_OUT_OF_RESOURCES;
}
}
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
EFI_STATUS
BgrtGetImageByBadging (
IN OUT UINT8 **ImageData,
IN OUT UINTN *ImageSize,
IN OUT EFI_BADGING_SUPPORT_FORMAT *ImageFormat
)
{
EFI_STATUS Status;
UINT32 Instance;
EFI_BADGING_SUPPORT_DISPLAY_ATTRIBUTE Attribute;
UINTN CoordinateX;
UINTN CoordinateY;
EFI_BADGING_SUPPORT_IMAGE_TYPE Type;
EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging;
Status = gBS->LocateProtocol (&gEfiOEMBadgingSupportProtocolGuid, NULL, (VOID **)&Badging);
if (EFI_ERROR(Status)) {
return Status;
}
Instance = 0;
Type = EfiBadgingSupportImageBoot;
Status = Badging->GetImage (
Badging,
&Instance,
&Type,
ImageFormat,
ImageData,
ImageSize,
&Attribute,
&CoordinateX,
&CoordinateY
);
return Status;
}
/**
Coordinate logo pos X and Y value by input X and Y unit.
@param[in] PosXUnit Enumerated value that specifies the horizontal origin of the logo.
@param[in] PosYUnit Enumerated value that specifies the vertical origin of the logo.
@param[in, out] PosX Pointer to logo image position X
@param[in, out] PosY Pointer to logo image position Y
@retval EFI_SUCCESS Coordinate logo pos X and Y value successfully.
@retval EFI_INVALID_PARAMETER Input parameter is NULL or logo position is invalid percentage value.
**/
STATIC
EFI_STATUS
CoordinateLogoPosXY (
IN UINT8 PosXUnit,
IN UINT8 PosYUnit,
IN OUT INT16 *PosX,
IN OUT INT16 *PosY
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
if (PosX == NULL || PosY == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
return Status;
}
if (PosXUnit == H2O_FLASH_MAP_REGION_LOGO_POS_X_PERCENTAGE) {
if (!IS_VALID_PERCENTAGE_VALUE(*PosX)) {
return EFI_INVALID_PARAMETER;
}
*PosX = (INT16) (((INT32) *PosX * (INT32) GraphicsOutput->Mode->Info->HorizontalResolution) / 100);
}
if (PosYUnit == H2O_FLASH_MAP_REGION_LOGO_POS_Y_PERCENTAGE) {
if (!IS_VALID_PERCENTAGE_VALUE(*PosY)) {
return EFI_INVALID_PARAMETER;
}
*PosY = (INT16) (((INT32) *PosY * (INT32) GraphicsOutput->Mode->Info->VerticalResolution) / 100);
}
return EFI_SUCCESS;
}
/**
SHA256 HASH calculation
@param [in] Message The message data to be calculated
@param [in] MessageSize The size in byte of the message data
@param [out] Digest The caclulated HASH digest
@retval EFI_SUCCESS The HASH value is calculated
@retval EFI_SECURITY_VIOLATION Failed to calculate the HASH
**/
EFI_STATUS
CalculateHash (
IN UINT8 *Message,
IN UINTN MessageSize,
OUT UINT8 *Digest
)
{
EFI_STATUS Status;
EFI_HASH2_PROTOCOL *Hash2Protocol;
UINTN CaseIndex;
CaseIndex = 0;
Status = gBS->LocateProtocol (
&gEfiHash2ProtocolGuid,
NULL,
(VOID **) &Hash2Protocol
);
if (EFI_ERROR (Status)) {
return Status;
}
SetMem (Digest, SHA256_DIGEST_SIZE, 0);
Status = Hash2Protocol->Hash (
Hash2Protocol,
&gEfiHashAlgorithmSha256Guid,
Message,
MessageSize,
(EFI_HASH2_OUTPUT *) Digest
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
return Status;
}
/**
Check if there is a QA test key in Factory Copy.
@retval TRUE - found the QA test certificate
@retval FALSE - did not found the QA test certificate
**/
BOOLEAN
CheckCertFromFactoryCopy (
VOID
)
{
EFI_STATUS Status;
UINT8 *VarBuffer;
UINTN VariableSize;
EFI_SIGNATURE_LIST *SignatureList;
EFI_SIGNATURE_DATA *SignatureData;
UINTN Offset;
UINT8 Digest[SHA256_DIGEST_SIZE];
VarBuffer = NULL;
Status = CommonGetVariableDataAndSize (
L"dbDefault",
&gEfiGlobalVariableGuid,
&VariableSize,
(VOID **) &VarBuffer
);
if (EFI_ERROR (Status) || VarBuffer == NULL) {
return FALSE;
}
Offset = 0;
while (Offset < VariableSize) {
SignatureList = (EFI_SIGNATURE_LIST *) (VarBuffer + Offset);
SignatureData = (EFI_SIGNATURE_DATA *) ((UINT8 *)SignatureList + sizeof (EFI_SIGNATURE_LIST));
//
// Compare the certificate size first, if the size doesn't match, skip to the next one.
//
if ((SignatureList->SignatureSize - sizeof (EFI_GUID)) == SIZE_OF_QA_TEST_KEY) {
Status = CalculateHash (SignatureData->SignatureData, SIZE_OF_QA_TEST_KEY, Digest);
if (CompareMem (Digest, mQACertificateHashData, SHA256_DIGEST_SIZE) == 0) {
FreePool (VarBuffer);
return TRUE;
}
}
Offset += SignatureList->SignatureListSize;
}
if (VarBuffer != NULL) {
FreePool (VarBuffer);
}
return FALSE;
}
/**
Check if there is a QA test key. QA test key cannot be used in both FFS and factory copy default.
@retval TRUE - found the QA test certificate
@retval FALSE - did not found the QA test certificate
**/
BOOLEAN
CheckCertificate (
VOID
)
{
EFI_STATUS Status;
UINT8 *FileBuffer;
UINTN FileSize;
UINT8 Digest[SHA256_DIGEST_SIZE];
EFI_SIGNATURE_LIST *SignatureList;
EFI_SIGNATURE_DATA *SignatureData;
UINTN Offset;
if (CheckCertFromFactoryCopy ()) {
return TRUE;
}
//
// Check the certificate from FFS
//
FileBuffer = NULL;
Status = GetSectionFromAnyFv (PcdGetPtr (PcdSecureFlashCertificateFile), EFI_SECTION_RAW, 0, (VOID **)&FileBuffer, &FileSize);
if (FileBuffer == NULL) {
return FALSE;
}
for (Offset = 0; Offset + sizeof (EFI_SIGNATURE_LIST) < FileSize; Offset += SignatureList->SignatureListSize) {
SignatureList = (EFI_SIGNATURE_LIST *) (FileBuffer + Offset);
SignatureData = (EFI_SIGNATURE_DATA *) ((UINT8 *)SignatureList + sizeof (EFI_SIGNATURE_LIST));
if (SignatureList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST)) {
break;
}
if ((SignatureList->SignatureSize - sizeof (EFI_GUID)) != SIZE_OF_QA_TEST_KEY) {
continue;
}
Status = CalculateHash (SignatureData->SignatureData, SIZE_OF_QA_TEST_KEY, Digest);
if (CompareMem (Digest, mQACertificateHashData, SHA256_DIGEST_SIZE) == 0) {
FreePool (FileBuffer);
return TRUE;
}
}
FreePool (FileBuffer);
return FALSE;
}
/**
Check if BDS hot key is detected or not.
@retval TRUE - BDS hot key is detected
@retval FALSE - BDS hot key is not detected yet.
**/
STATIC
BOOLEAN
OemGraphicsIsHotKeyDetected (
VOID
)
{
EFI_STATUS Status;
H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA *BdsDisplayStringBeforeData;
Status = gBS->LocateProtocol (&gH2OBdsCpDisplayStringBeforeGuid, NULL, (VOID **) &BdsDisplayStringBeforeData);
if (!EFI_ERROR (Status)) {
return BdsDisplayStringBeforeData->AfterSelect;
}
return FALSE;
}
/**
Check if ESRT Firmware Guid is the default CRB firmware guid
@retval TRUE - ESRT Firmware Guid is the default CRB firmware guid
@retval FALSE - ESRT Firmware Guid is not the default CRB firmware guid
**/
BOOLEAN
IsEsrtCrbFirmwareGuid (
VOID
){
EFI_STATUS Status;
EFI_SYSTEM_RESOURCE_TABLE *Esrt;
UINT8 Index;
Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
if (EFI_ERROR(Status) || Esrt == NULL){
return FALSE;
}
for (Index = 0; Index < Esrt->FirmwareResourceCount; Index++) {
if (CompareGuid (&Esrt->FirmwareResources[Index].FirmwareClass, &gEsrtCrbFirmwareGuid)) {
return TRUE;
}
}
return FALSE;
}
/**
Check if need to replace logo image by warning image.
@retval TRUE Need to replace logo image by warning image.
@retval FALSE No need to replace logo image by warning image.
**/
BOOLEAN
IsReplacedByWarningLogo (
VOID
)
{
if (PcdGetBool(PcdH2OWarningLogoSupported) && (IsEsrtCrbFirmwareGuid () || CheckCertificate ())) {
return TRUE;
}
return FALSE;
}
/**
Check if the BGRT feature is enabled or not.
@retval TRUE BGRT feature is enabled.
@retval FALSE BGRT feature is disabled.
**/
STATIC
BOOLEAN
IsBgrtEnabled (
VOID
)
{
EFI_BOOT_LOGO_PROTOCOL *BootLogo;
EFI_STATUS Status;
Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
return (!EFI_ERROR (Status)) ? TRUE : FALSE;
}
/**
Get corresponding badging support format value.
@param[in] Format Logo file format
@return The corresponding badging support format value or unknown value if not found.
**/
STATIC
EFI_BADGING_SUPPORT_FORMAT
GetBadgingSupportFormat (
IN UINT8 Format
)
{
switch (Format) {
case H2O_FLASH_MAP_REGION_LOGO_FORMAT_BMP:
return EfiBadgingSupportFormatBMP;
case H2O_FLASH_MAP_REGION_LOGO_FORMAT_JPEG:
return EfiBadgingSupportFormatJPEG;
case H2O_FLASH_MAP_REGION_LOGO_FORMAT_GIF:
return EfiBadgingSupportFormatGIF;
case H2O_FLASH_MAP_REGION_LOGO_FORMAT_PNG:
default:
return EfiBadgingSupportFormatUnknown;
}
}
/**
Using the current display resolution and image size, calculate the image display coordinates.
@param[in] ImageWidth Image width
@param[in] ImageHeight Image height
@param[in] PosX The image position X.
@param[in] PosX The image position Y.
@param[in] OriginX Logo image original position X
@param[in] OriginY Logo image original position Y
@param[out] CoordinateX The image destination coordinate X.
@param[out] CoordinateY The image destination coordinate Y.
@retval EFI_SUCCESS Get image coordinate successfully.
@retval EFI_INVALID_PARAMETER OriginX or OriginY value is invalid.
@retval Other Failed to get GOP protocol instance
**/
STATIC
EFI_STATUS
GetLogoCoordinate (
IN UINTN ImageWidth,
IN UINTN ImageHeight,
IN INT16 PosX,
IN INT16 PosY,
IN UINT8 OriginX,
IN UINT8 OriginY,
OUT UINTN *CoordinateX,
OUT UINTN *CoordinateY
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
UINTN ResolutionX;
UINTN ResolutionY;
*CoordinateX = 0;
*CoordinateY = 0;
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
return Status;
}
ResolutionX = GraphicsOutput->Mode->Info->HorizontalResolution;
ResolutionY = GraphicsOutput->Mode->Info->VerticalResolution;
switch (OriginX) {
case H2O_FLASH_MAP_REGION_LOGO_ORIGIN_X_LEFT:
*CoordinateX = 0;
break;
case H2O_FLASH_MAP_REGION_LOGO_ORIGIN_X_RIGHT:
*CoordinateX = ResolutionX - ImageWidth;
break;
case H2O_FLASH_MAP_REGION_LOGO_ORIGIN_X_CENTER:
*CoordinateX = (ResolutionX - ImageWidth) / 2;
break;
default:
return EFI_INVALID_PARAMETER;
}
switch (OriginY) {
case H2O_FLASH_MAP_REGION_LOGO_ORIGIN_Y_TOP:
*CoordinateY = 0;
break;
case H2O_FLASH_MAP_REGION_LOGO_ORIGIN_Y_BOTTOM:
*CoordinateY = ResolutionY - ImageHeight;
break;
case H2O_FLASH_MAP_REGION_LOGO_ORIGIN_Y_CENTER:
*CoordinateY = (ResolutionY - ImageHeight) / 2;
break;
default:
return EFI_INVALID_PARAMETER;
}
*CoordinateX = *CoordinateX + (UINTN) PosX;
*CoordinateY = *CoordinateY + (UINTN) PosY;
return EFI_SUCCESS;
}
/**
Add logo info into list.
@param[in] ImageData Pointer to the logo image
@param[in] ImageSize Logo image size
@param[in] PosX Logo image position X
@param[in] PosY Logo image position Y
@param[in] OriginX Logo image original position X
@param[in] OriginY Logo image original position Y
@param[in] Format Logo file format
@param[in] Priority Specifies the relative order of display for logos.
@param[in, out] InfoList Double pointer to the logo info list
@param[in, out] InfoCount Pointer to the logo info count
@retval EFI_SUCCESS Add logo info into list successfully.
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory for logo info.
@retval Other Failed to decode image or get coordinate position.
**/
STATIC
EFI_STATUS
AddLogoInfo (
IN UINT8 *ImageData,
IN UINTN ImageSize,
IN INT16 PosX,
IN INT16 PosY,
IN UINT8 OriginX,
IN UINT8 OriginY,
IN UINT8 Format,
IN INT8 Priority,
IN OUT LOGO_INFO_DATA **InfoList,
IN OUT UINTN *InfoCount
)
{
EFI_STATUS Status;
UINT8 *Blt;
UINTN ImageWidth;
UINTN ImageHeight;
UINTN DestinationX;
UINTN DestinationY;
UINTN Count;
LOGO_INFO_DATA *NewInfoList;
UINTN Index;
Blt = NULL;
Status = BgrtDecodeImageToBlt (
ImageData,
ImageSize,
GetBadgingSupportFormat (Format),
&Blt,
&ImageWidth,
&ImageHeight
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = GetLogoCoordinate (
ImageWidth,
ImageHeight,
PosX,
PosY,
OriginX,
OriginY,
&DestinationX,
&DestinationY
);
if (EFI_ERROR (Status)) {
FreePool (Blt);
return Status;
}
Count = *InfoCount;
NewInfoList = ReallocatePool (
sizeof (LOGO_INFO_DATA) * Count,
sizeof (LOGO_INFO_DATA) * (Count + 1),
*InfoList
);
if (NewInfoList == NULL) {
FreePool (Blt);
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < Count; Index++) {
if (Priority > NewInfoList[Index].Priority) {
break;
}
}
CopyMem (&NewInfoList[Index + 1], &NewInfoList[Index], sizeof (LOGO_INFO_DATA) * (Count - Index));
NewInfoList[Index].Blt = Blt;
NewInfoList[Index].ImageWidth = ImageWidth;
NewInfoList[Index].ImageHeight = ImageHeight;
NewInfoList[Index].DestinationX = DestinationX;
NewInfoList[Index].DestinationY = DestinationY;
NewInfoList[Index].Priority = Priority;
*InfoList = NewInfoList;
*InfoCount = Count + 1;
return EFI_SUCCESS;
}
/**
Collect boot logo data.
@param[in] LogoRegionId Pointer to the count of logo info list.
@param[in] ImageData Pointer to the logo image.
@param[in] ImageSize Logo image size.
@param[in, out] InfoList Double pointer to the logo info list
@param[in, out] InfoCount Pointer to the logo info count
@param[in, out] ReplaceFirstLogo Decide to replace logo image by warning image or not.
**/
STATIC
VOID
CollectLogoData (
IN H2O_FLASH_MAP_REGION_LOGO_ID *LogoRegionId,
IN UINT8 *ImageData,
IN UINTN ImageSize,
IN OUT LOGO_INFO_DATA **InfoList,
IN OUT UINTN *InfoCount,
IN OUT BOOLEAN *ReplaceFirstLogo
)
{
EFI_STATUS Status;
UINT8 LogoId;
UINT8 OriginX;
UINT8 OriginY;
INT16 PosX;
INT16 PosY;
UINT8 Format;
UINT8 PosXUnit;
UINT8 PosYUnit;
INT8 Priority;
LogoId = LogoRegionId->Id;
PosX = LogoRegionId->PosX;
PosY = LogoRegionId->PosY;
PosXUnit = H2O_FLASH_MAP_REGION_LOGO_FLAGS_TO_POS_X_UNIT (LogoRegionId->Flags);
PosYUnit = H2O_FLASH_MAP_REGION_LOGO_FLAGS_TO_POS_Y_UNIT (LogoRegionId->Flags);
OriginX = H2O_FLASH_MAP_REGION_LOGO_FLAGS_TO_ORIGIN_X (LogoRegionId->Flags);
OriginY = H2O_FLASH_MAP_REGION_LOGO_FLAGS_TO_ORIGIN_Y (LogoRegionId->Flags);
Format = H2O_FLASH_MAP_REGION_LOGO_FLAGS_TO_FORMAT (LogoRegionId->Flags);
Priority = LogoRegionId->Priority;
if (FeaturePcdGet (PcdH2OBdsCpLogoDisplayUpdateSupported)) {
H2O_BDS_CP_LOGO_DISPLAY_UPDATE_DATA LogoDisplayUpdateData;
LogoDisplayUpdateData.Size = sizeof (H2O_BDS_CP_LOGO_DISPLAY_UPDATE_DATA);
LogoDisplayUpdateData.Status = H2O_CP_TASK_NORMAL;
LogoDisplayUpdateData.Id = LogoId;
LogoDisplayUpdateData.PosX = PosX;
LogoDisplayUpdateData.PosY = PosY;
LogoDisplayUpdateData.PosXUnit = PosXUnit;
LogoDisplayUpdateData.PosYUnit = PosYUnit;
LogoDisplayUpdateData.OriginX = OriginX;
LogoDisplayUpdateData.OriginY = OriginY;
LogoDisplayUpdateData.Format = Format;
LogoDisplayUpdateData.Priority = Priority;
LogoDisplayUpdateData.ImageData = ImageData;
LogoDisplayUpdateData.ImageSize = (UINT32) ImageSize;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpLogoDisplayUpdateGuid));
H2OCpTrigger (&gH2OBdsCpLogoDisplayUpdateGuid, &LogoDisplayUpdateData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", LogoDisplayUpdateData.Status));
if (LogoDisplayUpdateData.Status == H2O_CP_TASK_SKIP) {
return;
}
if (LogoDisplayUpdateData.Status == H2O_CP_TASK_UPDATE) {
LogoId = LogoDisplayUpdateData.Id;
PosX = LogoDisplayUpdateData.PosX;
PosY = LogoDisplayUpdateData.PosY;
PosXUnit = LogoDisplayUpdateData.PosXUnit;
PosYUnit = LogoDisplayUpdateData.PosYUnit;
OriginX = LogoDisplayUpdateData.OriginX;
OriginY = LogoDisplayUpdateData.OriginY;
Format = LogoDisplayUpdateData.Format;
Priority = LogoDisplayUpdateData.Priority;
ImageData = LogoDisplayUpdateData.ImageData;
ImageSize = LogoDisplayUpdateData.ImageSize;
}
}
if (LogoId != H2O_FLASH_MAP_REGION_LOGO_ID_BOOT) {
return;
}
Status = CoordinateLogoPosXY (PosXUnit, PosYUnit, &PosX, &PosY);
if (EFI_ERROR(Status)) {
return;
}
if (*ReplaceFirstLogo) {
*ReplaceFirstLogo = FALSE;
//
// Get warning logo from FV.
//
Status = GetSectionFromAnyFv ((EFI_GUID *) PcdGetPtr (PcdWarningLogoFile), EFI_SECTION_RAW, 0, (VOID **)&ImageData, &ImageSize);
if (!EFI_ERROR(Status)) {
Format = H2O_FLASH_MAP_REGION_LOGO_FORMAT_JPEG;
}
}
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcUpdateLogo \n"));
Status = OemSvcUpdateLogo (
&LogoId,
&PosX,
&PosY,
&OriginX,
&OriginY,
&Format,
&ImageData,
(UINT32 *) &ImageSize
);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcUpdateLogo Status: %r\n", Status));
if (Status == EFI_SUCCESS || LogoId != H2O_FLASH_MAP_REGION_LOGO_ID_BOOT) {
return ;
}
AddLogoInfo (
ImageData,
ImageSize,
PosX,
PosY,
OriginX,
OriginY,
Format,
Priority,
InfoList,
InfoCount
);
return;
}
/**
Enumerate all logo images from FDM.
@param[out] LogoInfoList Double pointer to the logo info list
@param[out] LogoInfoCount Pointer to the count of logo info list
@retval EFI_SUCCESS Enumerate all logo images from FDM successfully.
@retval EFI_NOT_FOUND No available logo in FDM.
@retval Other Failed to get logo region type from FDM.
**/
STATIC
EFI_STATUS
EnumerateAllBootLogoFromFdm (
OUT LOGO_INFO_DATA **LogoInfoList,
OUT UINTN *LogoInfoCount
)
{
EFI_STATUS Status;
H2O_FLASH_MAP_REGION_LOGO_ID *LogoRegionId;
UINT8 LogoRegionCount;
H2O_BOARD_ID BoardId[2];
UINT8 LogoIndex;
UINT8 RegionId[FDM_ENTRY_REGION_ID_SIZE];
UINT64 RegionOffset;
UINT64 RegionSize;
UINT32 RegionAttr;
UINT8 OriginX;
UINT8 OriginY;
UINT8 Format;
UINT32 Index;
INT16 PosX;
INT16 PosY;
UINT8 *ImageData;
UINTN ImageSize;
BOOLEAN ReplaceFirstLogo;
LOGO_INFO_DATA *InfoList;
UINTN InfoCount;
UINT8 DeviceEntryCount;
H2O_FLASH_DEVICE_MAP_ENTRY *DeviceMapEntries;
Status = FdmGetNCount (&gH2OFlashMapRegionLogoGuid, &LogoRegionCount);
if (EFI_ERROR (Status)) {
return Status;
}
BoardId[0] = PcdGet64(PcdH2OBoardId);
BoardId[1] = 0;
InfoList = NULL;
DeviceMapEntries = NULL;
InfoCount = 0;
DeviceEntryCount = 0;
ReplaceFirstLogo = (BOOLEAN) (IsBgrtEnabled() && IsReplacedByWarningLogo());
if (BoardId[0] <= MAX_UINT8) {
//
// Get all logo images by enumerating flash device map.
//
for (LogoIndex = 1; LogoIndex <= LogoRegionCount; LogoIndex++) {
Status = FdmGetNAt (&gH2OFlashMapRegionLogoGuid, LogoIndex, RegionId, &RegionOffset, &RegionSize, &RegionAttr);
if (EFI_ERROR (Status)) {
continue;
}
LogoRegionId = (H2O_FLASH_MAP_REGION_LOGO_ID *) RegionId;
for (Index = 0; Index < SUPPORT_BOARD_COUNT; Index++) {
if (LogoRegionId->Boards[Index] == H2O_FLASH_MAP_REGION_LOGO_BOARDS_END) {
Index = SUPPORT_BOARD_COUNT;
break;
}
if (LogoRegionId->Boards[Index] == 0 ||
LogoRegionId->Boards[Index] == (UINT8)BoardId[0]) {
break;
}
}
if (Index == SUPPORT_BOARD_COUNT) {
continue;
}
ImageData = ((UINT8 *)(UINTN) FdmGetBaseAddr()) + RegionOffset;
ImageSize = (UINTN) RegionSize;
CollectLogoData (
LogoRegionId,
ImageData,
ImageSize,
&InfoList,
&InfoCount,
&ReplaceFirstLogo
);
}
} else {
//
// Find the matched entries.
//
for (Index = 0; Index < sizeof (BoardId) / sizeof(H2O_BOARD_ID); Index++) {
Status = FindRegionsByBoardId (BoardId[Index], &gH2OFlashMapRegionLogoGuid, &DeviceMapEntries, &DeviceEntryCount);
if (EFI_ERROR(Status)) {
continue;
}
//
// Get logo data.
//
for (LogoIndex = 0; LogoIndex < DeviceEntryCount; LogoIndex++) {
LogoRegionId = (H2O_FLASH_MAP_REGION_LOGO_ID *)((DeviceMapEntries[LogoIndex]).RegionId);
ImageData = ((UINT8 *)(UINTN) FdmGetBaseAddr()) + ((DeviceMapEntries[LogoIndex]).RegionOffset);
ImageSize = (UINTN) ((DeviceMapEntries[LogoIndex]).RegionSize);
CollectLogoData (
LogoRegionId,
ImageData,
ImageSize,
&InfoList,
&InfoCount,
&ReplaceFirstLogo
);
}
}
}
//
// Find all boot logos from OemSvcGetLogo()
//
Index = 0;
while (TRUE) {
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcGetLogo \n"));
Status = OemSvcGetLogo (
H2O_FLASH_MAP_REGION_LOGO_ID_BOOT,
Index,
&PosX,
&PosY,
&OriginX,
&OriginY,
&Format,
&ImageData,
(UINT32 *) &ImageSize
);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcGetLogo Status: %r\n", Status));
if (Status == EFI_UNSUPPORTED) {
break;
}
Index++;
if (Status == EFI_SUCCESS) {
continue;
}
if (Status != EFI_MEDIA_CHANGED) {
break;
}
AddLogoInfo (
ImageData,
ImageSize,
PosX,
PosY,
OriginX,
OriginY,
Format,
LOWEST_LOGO_PRIORITY,
&InfoList,
&InfoCount
);
}
//
// Free collected entries memory.
//
if (DeviceMapEntries != NULL) {
FreePool((DeviceMapEntries));
}
if (InfoCount == 0) {
return EFI_NOT_FOUND;
}
*LogoInfoList = InfoList;
*LogoInfoCount = InfoCount;
return EFI_SUCCESS;
}
/**
Get logo image from FDM.
@param[out] BltBuffer Pointer to the blt buffer of logo image
@param[out] DestinationX The image destination coordinate X.
@param[out] DestinationY The image destination coordinate Y.
@param[out] Width The image width size by pixel.
@param[out] Height The image height size by pixel.
@retval EFI_SUCCESS Get logo image from FDM successfully.
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory for BLT buffer.
@retval Other Failed to get logo info from FDM, failed to locate GOP protocol, or
blt function return fail.
**/
EFI_STATUS
GetLogoImageFromFdm (
OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
OUT UINTN *DestinationX,
OUT UINTN *DestinationY,
OUT UINTN *Width,
OUT UINTN *Height
)
{
EFI_STATUS Status;
LOGO_INFO_DATA *LogoInfoList;
UINTN LogoInfoCount;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewBltBuffer;
UINTN Index;
UINTN StartX;
UINTN StartY;
UINTN EndX;
UINTN EndY;
UINTN ImageWidth;
UINTN ImageHeight;
UINTN DestX;
UINTN DestY;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
UINTN Line;
LogoInfoList = NULL;
LogoInfoCount = 0;
Status = EnumerateAllBootLogoFromFdm (&LogoInfoList, &LogoInfoCount);
if (EFI_ERROR(Status)) {
return Status;
}
if (LogoInfoCount == 1) {
*DestinationX = LogoInfoList[0].DestinationX;
*DestinationY = LogoInfoList[0].DestinationY;
*Width = LogoInfoList[0].ImageWidth;
*Height = LogoInfoList[0].ImageHeight;
*BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) LogoInfoList[0].Blt;
LogoInfoList[0].Blt = NULL;
goto Done;
}
//
// Merge multiple logo images into BLT buffer
//
StartX = (UINTN) -1;
StartY = (UINTN) -1;
EndX = 0;
EndY = 0;
for (Index = 0; Index < LogoInfoCount; Index++) {
StartX = MIN (LogoInfoList[Index].DestinationX, StartX);
StartY = MIN (LogoInfoList[Index].DestinationY, StartY);
EndX = MAX ((LogoInfoList[Index].DestinationX + LogoInfoList[Index].ImageWidth) , EndX);
EndY = MAX ((LogoInfoList[Index].DestinationY + LogoInfoList[Index].ImageHeight), EndY);
}
DestX = StartX;
DestY = StartY;
ImageWidth = EndX - StartX;
ImageHeight = EndY - StartY;
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR(Status)) {
goto Done;
}
NewBltBuffer = AllocateZeroPool ((ImageWidth * ImageHeight) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
if (NewBltBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
Status = GraphicsOutput->Blt (
GraphicsOutput,
NewBltBuffer,
EfiBltVideoToBltBuffer,
DestX,
DestY,
0,
0,
ImageWidth,
ImageHeight,
ImageWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
if (EFI_ERROR(Status)) {
goto Done;
}
for (Index = 0; Index < LogoInfoCount; Index++) {
StartX = LogoInfoList[Index].DestinationX - DestX;
StartY = LogoInfoList[Index].DestinationY - DestY;
for (Line = 0; Line < LogoInfoList[Index].ImageHeight; Line++) {
CopyMem (
NewBltBuffer + (ImageWidth * (StartY + Line) + StartX),
LogoInfoList[Index].Blt + LogoInfoList[Index].ImageWidth * Line * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
LogoInfoList[Index].ImageWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
}
}
*BltBuffer = NewBltBuffer;
*DestinationX = DestX;
*DestinationY = DestY;
*Width = ImageWidth;
*Height = ImageHeight;
Done:
if (LogoInfoList != NULL) {
for (Index = 0; Index < LogoInfoCount; Index++) {
if (LogoInfoList[Index].Blt != NULL) {
FreePool (LogoInfoList[Index].Blt);
}
}
FreePool (LogoInfoList);
}
return Status;
}
VOID
BgrtGetLogoCoordinate (
IN UINTN ResolutionX,
IN UINTN ResolutionY,
IN UINTN ImageWidth,
IN UINTN ImageHeight,
OUT UINTN *CoordinateX,
OUT UINTN *CoordinateY
)
{
if (CoordinateX == NULL || CoordinateY == NULL) {
return;
}
//
// According to BGRT requirement, the logo must place at 38.2% from top of screen
// and the width/height should be less than 40% of screen.
//
if ((ImageWidth >= ((ResolutionX * 40) / 100)) || (ImageHeight >= ((ResolutionY * 40) / 100))) {
DEBUG ((EFI_D_ERROR, "Warning! The logo location did not meet BGRT requirement.\n"));
} //
// Current setting: Image on the middle of the screen, and 38.2% from top.
//
*CoordinateX = (UINTN)(ResolutionX - ImageWidth) / 2;
*CoordinateY = (UINTN)((ResolutionY * 382 / 1000) - (ImageHeight / 2));
}
/**
According to current resolution a image size to get the image destination coordinate.
@param[in] ImageWidth The image width size by pixel.
@param[in] ImageHeight The image height size by pixel.
@param[out] CoordinateX The image destination coordinate X.
@param[out] CoordinateY The image destination coordinate Y.
@retval EFI_SUCCESS Get image coordinate successfully.
@retval EFI_NOT_FOUND Cannot find gEfiGraphicsOutputProtocolGuid protocol.
**/
STATIC
EFI_STATUS
InternalBgrtGetLogoCoordinate (
IN UINTN ImageWidth,
IN UINTN ImageHeight,
OUT UINTN *CoordinateX,
OUT UINTN *CoordinateY
)
{
EFI_STATUS Status;
UINTN ResolutionX;
UINTN ResolutionY;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
return Status;
}
ResolutionX = GraphicsOutput->Mode->Info->HorizontalResolution;
ResolutionY = GraphicsOutput->Mode->Info->VerticalResolution;
BgrtGetLogoCoordinate (
GraphicsOutput->Mode->Info->HorizontalResolution,
GraphicsOutput->Mode->Info->VerticalResolution,
ImageWidth,
ImageHeight,
CoordinateX,
CoordinateY
);
return EFI_SUCCESS;
}
VOID
EFIAPI
BgrtClearOemStringReadyToBootEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
UINTN StringCount;
UINTN Index;
EFI_STATUS Status;
UINTN LocX;
UINTN LocY;
EFI_UGA_PIXEL Foreground;
EFI_UGA_PIXEL Background;
CHAR16 *StringData;
UINTN MinLocY;
UINTN MaxLocY;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Blt;
BOOLEAN Found;
MinLocY = 0xFFFFFFFF;
MaxLocY = 0;
Found = FALSE;
gBS->CloseEvent (Event);
Status = gBS->LocateProtocol (&gEfiOEMBadgingSupportProtocolGuid, NULL, (VOID **)&Badging);
if (EFI_ERROR (Status)) {
return;
}
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
return;
}
Badging->GetStringCount (Badging, &StringCount);
if (StringCount) {
for (Index = 0; Index < StringCount; Index++) {
if (Badging->GetOemString (Badging, Index, FALSE, 0, &StringData, &LocX, &LocY, &Foreground, &Background)) {
Found = TRUE;
FreePool (StringData);
if (LocX == (UINTN) (-1) || LocY == (UINTN) (-1)) {
continue;
}
if (MinLocY > LocY) {
MinLocY = LocY;
}
if (LocY > MaxLocY) {
MaxLocY = LocY;
}
}
}
if (!Found) {
return;
}
SetMem (&Blt, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x00);
//
// First clear string which position is defined by OEM, then clear auto place strings.
//
if (MinLocY != 0xFFFFFFFF) {
Status = GraphicsOutput->Blt (
GraphicsOutput,
&Blt,
EfiBltVideoFill,
0,
0,
(UINTN) 0,
(UINTN) MinLocY,
GraphicsOutput->Mode->Info->HorizontalResolution,
//
// GLYPH_HEIGHT is 19.
//
(MaxLocY - MinLocY + 20),
0
);
}
if (mAutoPlaceStrCount != 0 && mAutoPlaceStrDestY != (UINTN) (-1)) {
Status = GraphicsOutput->Blt (
GraphicsOutput,
&Blt,
EfiBltVideoFill,
0,
0,
(UINTN) 0,
(UINTN) mAutoPlaceStrDestY,
GraphicsOutput->Mode->Info->HorizontalResolution,
mAutoPlaceStrCount * EFI_GLYPH_HEIGHT,
0
);
mAutoPlaceStrCount = 0;
mAutoPlaceStrDestY = (UINTN) (-1);
}
}
return;
}
/**
Get BGRT image information from firmware volume.
@param[out] BltBuffer BGRT image blt.
@param[out] DestinationX The image destination coordinate X.
@param[out] DestinationY The image destination coordinate Y.
@param[out] Width The image width size by pixel.
@param[out] Height The image height size by pixel.
@retval EFI_SUCCESS Get BGRT image information successfully.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory for BLT buffer.
@retval EFI_NOT_FOUND Cannot find BGRT image.
@retval EFI_UNSUPPORTED Doesn't support output image coordinate.
**/
STATIC
EFI_STATUS
BgrtGetBootImageInfoFromFv (
OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
OUT UINTN *DestinationX,
OUT UINTN *DestinationY,
OUT UINTN *Width,
OUT UINTN *Height
)
{
EFI_STATUS Status;
UINT8 *ImageData;
UINTN ImageSize;
EFI_BADGING_SUPPORT_FORMAT BadgingImageFormat;
UINTN ImageWidth;
UINTN ImageHeight;
UINT8 *Blt;
if (BltBuffer == NULL || DestinationX == NULL || DestinationY == NULL ||
Width == NULL || Height == NULL) {
return EFI_INVALID_PARAMETER;
}
Blt = NULL;
if (PcdGetBool (PcdH2OBdsOemBadgingSupported)) {
Status = BgrtGetImageByBadging (&ImageData, &ImageSize, &BadgingImageFormat);
if (EFI_ERROR(Status)) {
return Status;
}
Status = BgrtDecodeImageToBlt (
ImageData,
ImageSize,
BadgingImageFormat,
&Blt,
&ImageWidth,
&ImageHeight
);
FreePool (ImageData);
if (EFI_ERROR(Status)) {
return Status;
}
Status = InternalBgrtGetLogoCoordinate (ImageWidth, ImageHeight, DestinationX, DestinationY);
if (EFI_ERROR (Status)) {
return Status;
}
} else {
Status = GetLogoImageFromFdm ((EFI_GRAPHICS_OUTPUT_BLT_PIXEL **) &Blt, DestinationX, DestinationY, &ImageWidth, &ImageHeight);
if (EFI_ERROR (Status)) {
return Status;
}
}
if (((*(INTN*)DestinationX) < 0) || ((*(INTN*)DestinationY) < 0)) {
return EFI_UNSUPPORTED;
}
*BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*) Blt;
*Width = ImageWidth;
*Height = ImageHeight;
return Status;
}
/**
Get BGRT image information from input image
@param[in] Image Input EFI_IMAGE_INPUT instance.
@param[out] BltBuffer BGRT image blt.
@param[out] DestinationX The image destination coordinate X.
@param[out] DestinationY The image destination coordinate Y.
@param[out] Width The image width size by pixel.
@param[out] Height The image height size by pixel.
@retval EFI_SUCCESS Get BGRT image information successfully.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory for BLT buffer.
@retval EFI_UNSUPPORTED Doesn't support output image coordinate.
**/
STATIC
EFI_STATUS
BgrtGetBootImageInfoFromImageBuffer (
IN EFI_IMAGE_INPUT *Image,
OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
OUT UINTN *DestinationX,
OUT UINTN *DestinationY,
OUT UINTN *Width,
OUT UINTN *Height
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
UINTN BltBufferSize;
if (Image == NULL || Image->Bitmap == NULL || Image->Width == 0 || Image->Height == 0 ||
BltBuffer == NULL || DestinationX == NULL || DestinationY == NULL || Width == NULL || Height == NULL) {
return EFI_INVALID_PARAMETER;
}
BltBufferSize = (UINTN)Image->Width * Image->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
Blt = AllocatePool (BltBufferSize);
if (Blt == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (Blt, Image->Bitmap, BltBufferSize);
Status = InternalBgrtGetLogoCoordinate ((UINTN) Image->Width, (UINTN) Image->Height, DestinationX, DestinationY);
if (EFI_ERROR (Status)) {
return Status;
}
if (((*(INTN*) DestinationX) < 0) || ((*(INTN*) DestinationY) < 0)) {
return EFI_UNSUPPORTED;
}
*BltBuffer = Blt;
*Width = (UINTN) Image->Width;
*Height = (UINTN) Image->Height;
return Status;
}
/**
Get BGRT image information
@param[out] BltBuffer BGRT image blt.
@param[out] DestinationX The image destination coordinate X.
@param[out] DestinationY The image destination coordinate Y.
@param[out] Width The image width size by pixel.
@param[out] Height The image height size by pixel.
@retval EFI_SUCCESS Get BGRT image information successfully.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory for BLT buffer.
@retval EFI_NOT_FOUND Cannot find BGRT image.
@retval EFI_UNSUPPORTED Doesn't support output image coordinate.
**/
EFI_STATUS
BgrtGetBootImageInfo (
OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
OUT UINTN *DestinationX,
OUT UINTN *DestinationY,
OUT UINTN *Width,
OUT UINTN *Height
)
{
EFI_STATUS Status;
H2O_BDS_CP_DISPLAY_BEFORE_DATA *BdsDisplayBeforData;
Status = gBS->LocateProtocol (
&gH2OBdsCpDisplayBeforeGuid,
NULL,
(VOID **) &BdsDisplayBeforData
);
if (BdsDisplayBeforData != NULL && (BdsDisplayBeforData->Features & H2O_BDS_CP_DISPLAY_BGRT) != 0 &&
BdsDisplayBeforData->Image != NULL) {
Status = BgrtGetBootImageInfoFromImageBuffer (
BdsDisplayBeforData->Image,
BltBuffer,
DestinationX,
DestinationY,
Width,
Height
);
} else {
Status = BgrtGetBootImageInfoFromFv (
BltBuffer,
DestinationX,
DestinationY,
Width,
Height
);
}
return Status;
}
EFI_STATUS
EFIAPI
BgrtEnableQuietBoot (
EFI_BOOT_LOGO_PROTOCOL *SetBootLogo
)
{
EFI_STATUS Status;
EFI_EVENT ReadyToBootEvent;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
UINTN DestinationX;
UINTN DestinationY;
UINTN Width;
UINTN Height;
EFI_STATUS ShowStringStatus;
H2O_BDS_CP_DISPLAY_BEFORE_DATA *BdsDisplayBeforData;
BltBuffer = NULL;
DestinationX = 0;
DestinationY = 0;
Width = 0;
Height = 0;
Status = gBS->LocateProtocol (
&gH2OBdsCpDisplayBeforeGuid,
NULL,
(VOID **) &BdsDisplayBeforData
);
if (!EFI_ERROR (Status) && BdsDisplayBeforData->Status == H2O_BDS_TASK_SKIP) {
return EFI_SUCCESS;
}
if (SetBootLogo == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// The procedure of BgrtEnableQuietBoot:
//
// 1. Get Boot image by OemBadgingSupport with Type == EfiBadgingSupportImageBoot.
// 2. Update Boot image to BGRT table.
// 3. Show logo. (According to the bgrt spec, the background always black)
// 4. Show OEM String.
// 5. Clear OEM String by ReadyToBoot Event.
//
Status = BgrtGetBootImageInfo (
&BltBuffer,
&DestinationX,
&DestinationY,
&Width,
&Height
);
if (EFI_ERROR(Status)) {
return Status;
}
//
// BIOS show logo.
//
Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **)&ConsoleControl);
if (!EFI_ERROR (Status)) {
//
// switch to the Graphical mode.
//
ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenGraphics);
} else {
gST->ConOut->ClearScreen (gST->ConOut);
}
//
// Erase Cursor from screen
//
gST->ConOut->EnableCursor (gST->ConOut, FALSE);
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR(Status)) {
return Status;
}
Status = GraphicsOutput->Blt (
GraphicsOutput,
BltBuffer,
EfiBltBufferToVideo,
0,
0,
DestinationX,
DestinationY,
Width,
Height,
Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
ASSERT_EFI_ERROR (Status);
Status = SetBootLogo->SetBootLogo (
SetBootLogo,
BltBuffer,
DestinationX,
DestinationY,
Width,
Height
);
ASSERT_EFI_ERROR (Status);
//
// Y vaule of auto place OEM badging string starts at y value of image bottom plus 2 glyph heigh.
//
mAutoPlaceStrDestY = DestinationY + Height + 2 * EFI_GLYPH_HEIGHT;
//
// show OemString.
//
Status = gBS->LocateProtocol (&gEfiOEMBadgingSupportProtocolGuid, NULL, (VOID **)&Badging);
if (EFI_ERROR(Status)) {
return Status;
}
ShowStringStatus = ShowOemString (Badging, OemGraphicsIsHotKeyDetected (), 0);
if (EFI_ERROR (ShowStringStatus)) {
if (BltBuffer != NULL) {
FreePool (BltBuffer);
}
return Status;
}
Status = EfiCreateEventReadyToBootEx (
TPL_CALLBACK,
BgrtClearOemStringReadyToBootEvent,
NULL,
&ReadyToBootEvent
);
if (EFI_ERROR (Status)) {
gBS->CloseEvent (ReadyToBootEvent);
}
if (BltBuffer != NULL) {
FreePool (BltBuffer);
}
return Status;
}
EFI_STATUS
LockKeyboards (
IN CHAR16 *Password
)
{
EFI_STATUS Status;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **)&ConsoleControl);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Status = ConsoleControl->LockStdIn (ConsoleControl, Password);
return Status;
}
STATIC
EFI_STATUS
DiaplayMessage(
IN UINTN PosX,
IN UINTN PosY,
IN EFI_UGA_PIXEL ForegroundRGB,
IN EFI_UGA_PIXEL BackgroundRGB,
IN CHAR16 *TmpStr
)
{
EFI_STATUS Status;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
UINT32 SizeOfX;
UINT32 SizeOfY;
UINT32 ColorDepth;
UINT32 RefreshRate;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
UgaDraw = NULL;
GraphicsOutput = NULL;
CopyMem (&Foreground, &ForegroundRGB, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
CopyMem (&Background, &BackgroundRGB, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
GraphicsOutput = NULL;
Status = gBS->HandleProtocol (
gST->ConsoleOutHandle,
&gEfiUgaDrawProtocolGuid,
(VOID **)&UgaDraw
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
}
if (GraphicsOutput == NULL && UgaDraw == NULL) {
return EFI_UNSUPPORTED;
}
if (GraphicsOutput != NULL) {
SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
} else {
Status = UgaDraw->GetMode (
UgaDraw,
&SizeOfX,
&SizeOfY,
&ColorDepth,
&RefreshRate
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
}
//
// If X or Y value of OEM badging string is -1, system will auto place this string.
//
if ((PosX == (UINTN) (-1) || PosY == (UINTN) (-1))) {
if (mAutoPlaceStrDestY == (UINTN) (-1)) {
return EFI_UNSUPPORTED;
}
PosX = (SizeOfX - StrLen (TmpStr) * EFI_GLYPH_WIDTH) / 2;
PosY = mAutoPlaceStrDestY + mAutoPlaceStrCount * EFI_GLYPH_HEIGHT;
mAutoPlaceStrCount++;
}
if (PosX > SizeOfX || PosY > SizeOfY) {
ASSERT (0);
return EFI_UNSUPPORTED;
}
if (*TmpStr != CHAR_NULL) {
PrintXY (
PosX,
PosY,
&Foreground,
&Background,
TmpStr
);
}
return EFI_SUCCESS;
}
/**
This function uses to check GOP hardware device is whether ready.
@retval TRUE GOP hardware device is ready.
@retval FALSE GOP hardware device isn't ready.
**/
BOOLEAN
IsGopReady (
VOID
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
return FALSE;
}
Status = GraphicsOutput->QueryMode (
GraphicsOutput,
GraphicsOutput->Mode->Mode,
&SizeOfInfo,
&Info
);
if (!EFI_ERROR (Status)) {
FreePool (Info);
return TRUE;
}
return FALSE;
}
/**
Internal function to remove all of previous installed checkpoint and then
use previous installed checkpoint data to install checkpoint again.
@param[in] Checkpoint The number ID of checkpoint.
@retval EFI_SUCCESS Reinstall checkpoint successfully.
@retval EFI_NOT_FOUND The checkpoint hasn't been triggered.
**/
STATIC
EFI_STATUS
RemovePreviousInstalledCp (
IN EFI_GUID *CheckPoint
)
{
EFI_STATUS Status;
UINTN NoHandles;
EFI_HANDLE *Buffer;
UINTN Index;
VOID *Interface;
Status = gBS->LocateHandleBuffer (
ByProtocol,
CheckPoint,
NULL,
&NoHandles,
&Buffer
);
if (EFI_ERROR (Status) || NoHandles == 0) {
return EFI_SUCCESS;
}
for (Index = 0; Index < NoHandles; Index++) {
Status = gBS->HandleProtocol (
Buffer[Index],
CheckPoint,
(VOID **) &Interface
);
ASSERT (!EFI_ERROR (Status));
Status = gBS->UninstallProtocolInterface (
Buffer[Index],
CheckPoint,
Interface
);
FreePool (Interface);
}
FreePool (Buffer);
return Status;
}
/**
Internal function to initalize H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA data.
@param[in] Badging Input EFI_OEM_BADGING_SUPPORT_PROTOCOL interface.
@param[in] AfterSelect Boolean value for hotkey is pressed (true) or not(false).
@param[in] SelectedStringNum Specific string token number to display.
@param[out] CpData A Pointer to H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA instance to initialized.
@retval EFI_SUCCESS Init H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA data successfully.
@retval EFI_INVALID_PARAMETER CpData is NULL.
@retval EFI_OUT_OF_RESOURCES Allocate memory for H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA interface failed.
**/
STATIC
EFI_STATUS
InitBeforeDisplayStringData (
IN EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging,
IN BOOLEAN AfterSelect,
IN UINT8 SelectedStringNum,
OUT H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA **CpData
)
{
H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA *BdsDisplayStringBeforeData;
if (CpData == NULL) {
return EFI_INVALID_PARAMETER;
}
BdsDisplayStringBeforeData = AllocateZeroPool (sizeof (H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA));
if (BdsDisplayStringBeforeData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (BdsDisplayStringBeforeData, sizeof (H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA));
BdsDisplayStringBeforeData->Size = sizeof (H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA);
BdsDisplayStringBeforeData->Status = H2O_BDS_TASK_NORMAL;
BdsDisplayStringBeforeData->Badging = Badging;
BdsDisplayStringBeforeData->AfterSelect = AfterSelect;
BdsDisplayStringBeforeData->SelectedStringNum = SelectedStringNum;
*CpData = BdsDisplayStringBeforeData;
return EFI_SUCCESS;
}
/**
Initalize H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA
data and trigger gH2OBdsCpDisplayStringBeforeGuid checkpoint.
@retval EFI_SUCCESS Trigger gH2OBdsCpDisplayStringBeforeGuid checkpoint successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
@return Other Other error occurred while triggering gH2OBdsCpDisplayStringBeforeGuid
checkpoint.
**/
EFI_STATUS
TriggerCpDisplayStringBefore (
IN EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging,
IN BOOLEAN AfterSelect,
IN UINT8 SelectedStringNum
)
{
EFI_STATUS Status;
H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA *BdsDisplayStringBeforeData;
EFI_HANDLE Handle;
RemovePreviousInstalledCp (&gH2OBdsCpDisplayStringBeforeGuid);
Status = InitBeforeDisplayStringData (Badging, AfterSelect, SelectedStringNum, &BdsDisplayStringBeforeData);
if (Status != EFI_SUCCESS) {
return Status;
}
//
// Install checpoint data to protocol for later usage.
//
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
(EFI_GUID *) &gH2OBdsCpDisplayStringBeforeGuid,
EFI_NATIVE_INTERFACE,
(VOID *) BdsDisplayStringBeforeData
);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpDisplayStringBeforeGuid));
H2OCpTrigger (&gH2OBdsCpDisplayStringBeforeGuid, BdsDisplayStringBeforeData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsDisplayStringBeforeData->Status));
return EFI_SUCCESS;
}
EFI_STATUS
ShowOemString (
IN EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging,
IN BOOLEAN AfterSelect,
IN UINT8 SelectedStringNum
)
{
EFI_STATUS Status;
UINTN LocX;
UINTN LocY;
EFI_UGA_PIXEL Foreground;
EFI_UGA_PIXEL Background;
CHAR16 *StringData;
UINTN StringCount;
UINTN Index;
H2O_BDS_CP_DISPLAY_STRING_BEFORE_DATA *BdsDisplayStringBeforeData;
if (!IsGopReady ()) {
return EFI_NOT_STARTED;
}
if (FeaturePcdGet (PcdH2OBdsCpDisplayStringBeforeSupported)) {
TriggerCpDisplayStringBefore (Badging, AfterSelect, SelectedStringNum);
Status = gBS->LocateProtocol (
&gH2OBdsCpDisplayStringBeforeGuid,
NULL,
(VOID **) &BdsDisplayStringBeforeData
);
if (!EFI_ERROR (Status) && BdsDisplayStringBeforeData->Status == H2O_BDS_TASK_SKIP) {
return Status;
}
}
LocX = 0;
LocY = 0;
StringCount = 0;
Index = 0;
Status = EFI_SUCCESS;
if (FeaturePcdGet (PcdDynamicHotKeySupported)) {
DYNAMIC_HOTKEY_PROTOCOL *DynamicHotKey;
DynamicHotKey = NULL;
Status = gBS->LocateProtocol (&gDynamicHotKeyProtocolGuid, NULL, (VOID **)&DynamicHotKey);
if (!EFI_ERROR (Status)) {
//
// Get POST string count
//
Status = DynamicHotKey->GetDynamicStringCount (DynamicHotKey, AfterSelect, &StringCount);
if (!EFI_ERROR (Status)) {
for (Index = 0 ; Index < StringCount ; Index++) {
//
// Get POST string
//
Status = DynamicHotKey->GetDynamicString (DynamicHotKey, Index, AfterSelect, &StringData, &LocX, &LocY);
if (!EFI_ERROR (Status)) {
//
// Get POST string foreground and background color
//
DynamicHotKey->GetDynamicStringColor (Index, AfterSelect, &Foreground, &Background);
DynamicHotKey->AdjustStringPosition (DynamicHotKey, FALSE, TRUE, mAutoPlaceStrDestY, StringData, &LocX, &LocY);
DiaplayMessage (LocX, LocY, Foreground, Background, StringData);
FreePool (StringData);
}
}
DynamicHotKey->AdjustStringPosition (DynamicHotKey, TRUE, TRUE, 0, NULL, NULL, NULL);
}
}
} else {
ZeroMem (&Foreground, sizeof (EFI_UGA_PIXEL));
Status = Badging->GetStringCount(Badging, &StringCount);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
mAutoPlaceStrCount = 0;
Status = EFI_UNSUPPORTED;
for ( Index = 0 ; Index < StringCount ; Index++ ) {
if (Badging->GetOemString(Badging, Index, AfterSelect, SelectedStringNum, &StringData, &LocX, &LocY, &Foreground, &Background) ) {
if (TextOnlyConsole ()) {
DisplayMessageToConsoleRedirection (StringData);
}
DiaplayMessage (
LocX,
LocY,
Foreground,
Background,
StringData
);
FreePool (StringData);
Status = EFI_SUCCESS;
}
}
}
return Status;
}
STATIC
EFI_STATUS
SetTextModeBySimpleTextOut (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut,
IN UINT32 NewColumns,
IN UINT32 NewRows
)
{
EFI_STATUS Status;
UINTN Index;
UINTN Columns;
UINTN Rows;
Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &Columns, &Rows);
if (EFI_ERROR (Status)) {
return Status;
}
if (Columns == NewColumns && Rows == NewRows) {
return EFI_SUCCESS;
}
for (Index = 0; Index < (UINTN)(SimpleTextOut->Mode->MaxMode); Index++) {
Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &Columns, &Rows);
if (!EFI_ERROR (Status) && Columns == NewColumns && Rows == NewRows) {
return SimpleTextOut->SetMode (SimpleTextOut, Index);
}
}
DEBUG ((DEBUG_INFO, "Warning! No corresponding resolution for text mode\n"));
return EFI_UNSUPPORTED;
}
VOID
SetModeByGraphicOutput (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN UINT32 SizeOfX,
IN UINT32 SizeOfY
)
{
UINT32 Index;
UINT32 OriginalMode;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
UINT8 *EFIBdaVGAMode;
UINT8 *BdaVGAMode;
EFI_STATUS Status;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
EFIBdaVGAMode = (UINT8 *)(UINTN)EFI_CURRENT_VGA_MODE_ADDRESS;
BdaVGAMode = (UINT8 *)(UINTN)CURRENT_VGA_MODE_ADDRESS;
OriginalMode = GraphicsOutput->Mode->Mode;
GraphicsOutput->QueryMode (GraphicsOutput, OriginalMode, &SizeOfInfo, &Info);
if (Info->HorizontalResolution != SizeOfX || Info->VerticalResolution != SizeOfY || !IsModeSync ()) {
Status = EFI_SUCCESS;
for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {
GraphicsOutput->QueryMode (GraphicsOutput, Index, &SizeOfInfo, &Info);
if (SizeOfX == Info->HorizontalResolution &&
SizeOfY == Info->VerticalResolution) {
Status = GraphicsOutput->SetMode (GraphicsOutput, Index);
FreePool (Info);
break;
}
FreePool (Info);
Info = NULL;
}
//
// Cannot find suitable GOP mode, set mode with default resolution.
//
if (EFI_ERROR (Status) || (Index == GraphicsOutput->Mode->MaxMode)) {
for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {
GraphicsOutput->QueryMode (GraphicsOutput, Index, &SizeOfInfo, &Info);
if (Info->HorizontalResolution == PcdGet32 (PcdDefaultHorizontalResolution) &&
Info->VerticalResolution == PcdGet32 (PcdDefaultVerticalResolution)) {
Status = GraphicsOutput->SetMode (GraphicsOutput, Index);
FreePool (Info);
Info = NULL;
break;
}
FreePool (Info);
Info = NULL;
}
}
if (EFI_ERROR (Status) || (Index == GraphicsOutput->Mode->MaxMode)) {
for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {
Status = GraphicsOutput->QueryMode (GraphicsOutput, Index, &SizeOfInfo, &Info);
if (Info->HorizontalResolution == 640 &&
Info->VerticalResolution == 480) {
Status = GraphicsOutput->SetMode (GraphicsOutput, Index);
break;
}
}
}
ASSERT_EFI_ERROR (Status);
} else {
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
if (!EFI_ERROR (Status)) {
if (*EFIBdaVGAMode != *BdaVGAMode) {
GraphicsOutput->SetMode (GraphicsOutput, OriginalMode);
}
}
}
}
EFI_STATUS
OnEndOfDisableQuietBoot (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_HANDLE *HandleBuffer;
UINTN NumberOfHandles;
UINTN Index;
VOID *Interface;
//
// To prevent from memory leak, uninstall other gEndOfDisableQuietBootGuid.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEndOfDisableQuietBootGuid,
NULL,
&NumberOfHandles,
&HandleBuffer
);
if (!EFI_ERROR (Status)) {
for (Index = 0; Index < NumberOfHandles; Index++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEndOfDisableQuietBootGuid,
(VOID **) &Interface
);
Status = gBS->UninstallProtocolInterface (
HandleBuffer[Index],
&gEndOfDisableQuietBootGuid,
Interface
);
}
FreePool (HandleBuffer);
}
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&gEndOfDisableQuietBootGuid,
EFI_NATIVE_INTERFACE,
NULL
);
return EFI_SUCCESS;
}
/**
Consume by Bgrt driver to get the logo infomation.
In some platform won't called EnableQuietBoot to update the Bgrt logo info,
if the logo info won't update when ReadyToBoot event trigger, the Bgrt driver will
get the logo info automatically by this function.
@retval EFI_SUCCESS Get boot logo info success.
**/
EFI_STATUS
LogoLibSetBootLogo (
VOID
)
{
EFI_STATUS Status;
EFI_BOOT_LOGO_PROTOCOL *BootLogoProtocol;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer = NULL;
UINTN DestinationX = 0;
UINTN DestinationY = 0;
UINTN Width = 0;
UINTN Height = 0;
Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **)&BootLogoProtocol);
if (EFI_ERROR(Status)) {
return Status;
}
Status = BgrtGetBootImageInfo (
&BltBuffer,
&DestinationX,
&DestinationY,
&Width,
&Height
);
if (!EFI_ERROR(Status)) {
Status = BootLogoProtocol->SetBootLogo (
BootLogoProtocol,
BltBuffer,
DestinationX,
DestinationY,
Width,
Height
);
if (BltBuffer != NULL) {
FreePool (BltBuffer);
}
}
return Status;
}
/**
Internal function to check whether the logo image is in H2O_BDS_CP_DISPLAY_BEFORE_DATA
logo member.
@retval TRUE Logo image is in H2O_BDS_CP_DISPLAY_BEFORE_DATA logo member.
@retval FALSE Logo image isn't in H2O_BDS_CP_DISPLAY_BEFORE_DATA logo member.
**/
BOOLEAN
IsLogoInDisplayBeforeProtocol (
VOID
)
{
H2O_BDS_CP_DISPLAY_BEFORE_DATA *BdsDisplayBeforData;
EFI_STATUS Status;
Status = gBS->LocateProtocol (
&gH2OBdsCpDisplayBeforeGuid,
NULL,
(VOID **) &BdsDisplayBeforData
);
if (EFI_ERROR (Status)) {
return FALSE;
}
if ((BdsDisplayBeforData->Features & H2O_BDS_CP_DISPLAY_LOGO) == 0 || BdsDisplayBeforData->Image == NULL) {
return FALSE;
}
return TRUE;
}
/**
Internal function to set default OEM string location.
@retval EFI_SUCCESS Set OEM string location successfully.
@return Other Any error occurred while setting OEM string location.
**/
EFI_STATUS
SetOemStringLocation (
VOID
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
UINT32 SizeOfX;
UINT32 SizeOfY;
UINT32 ColorDepth;
UINT32 RefreshRate;
UgaDraw = NULL;
GraphicsOutput = NULL;
SizeOfY = (UINT32) (-1);
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
}
if (GraphicsOutput != NULL) {
SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
} else if (UgaDraw != NULL) {
Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
}
if (!EFI_ERROR (Status)) {
mAutoPlaceStrDestY = SizeOfY / 2;
}
return Status;
}
/**
Use SystemTable Conout to stop video based Simple Text Out consoles from going
to the video device. Put up LogoFile on every video device that is a console.
@param[in] LogoFile File name of logo to display on the center of the screen.
@retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
@retval EFI_UNSUPPORTED Logo not found
**/
EFI_STATUS
EnableQuietBoot (
IN EFI_GUID *LogoFile
)
{
EFI_STATUS Status;
EFI_OEM_BADGING_SUPPORT_PROTOCOL *Badging;
UINT32 SizeOfX;
UINT32 SizeOfY;
INTN DestX;
INTN DestY;
UINT8 *ImageData;
UINTN ImageSize;
UINTN BltSize;
UINT32 Instance;
EFI_BADGING_SUPPORT_FORMAT Format;
EFI_BADGING_SUPPORT_DISPLAY_ATTRIBUTE Attribute;
UINTN CoordinateX;
UINTN CoordinateY;
UINTN Height;
UINTN Width;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
UINT32 ColorDepth;
UINT32 RefreshRate;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_BADGING_SUPPORT_IMAGE_TYPE Type;
EFI_BADGING_SUPPORT_DISPLAY_ATTRIBUTE BadgeAttribute;
UINTN BadgeCoordinateX;
UINTN BadgeCoordinateY;
BOOLEAN OverrideBadgeLocation;
EFI_JPEG_DECODER_PROTOCOL *JpegDecoder;
EFI_PCX_DECODER_PROTOCOL *PcxDecoder;
EFI_JPEG_DECODER_STATUS DecoderStatus;
JPG_BADGE_COMMENT *pJpegBadgeComment;
UINTN Index;
UINTN LocX;
UINTN LocY;
UINT8 *VideoBuffer;
TGA_FORMAT TgaFormate;
EFI_TGA_DECODER_PROTOCOL *TgaDecoder;
BOOLEAN HasAlphaChannel;
EFI_GIF_DECODER_PROTOCOL *GifDecoder;
ANIMATION *Animation;
ANIMATION_REFRESH_ENTRY AnimationRefreshEntry;
EFI_BOOT_LOGO_PROTOCOL *SetBootLogo;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
EFI_CONSOLE_CONTROL_SCREEN_MODE ScreenMode;
H2O_BDS_CP_DISPLAY_BEFORE_DATA *BdsDisplayBeforData;
EFI_BMP_DECODER_PROTOCOL *BmpDecoder;
EFI_PNG_DECODER_PROTOCOL *PngDecoder;
Status = gBS->LocateProtocol (
&gH2OBdsCpDisplayBeforeGuid,
NULL,
(VOID **) &BdsDisplayBeforData
);
if (!EFI_ERROR (Status) && BdsDisplayBeforData->Status == H2O_BDS_TASK_SKIP) {
SetOemStringLocation ();
return EFI_SUCCESS;
}
SetBootLogo = NULL;
Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **)&SetBootLogo);
if (((BdsDisplayBeforData != NULL && (BdsDisplayBeforData->Features & H2O_BDS_CP_DISPLAY_BGRT) != 0) || BdsDisplayBeforData == NULL)
&& !EFI_ERROR(Status)) {
//
// Bgrt feature supported, it has the different showing logo policy.
//
Status = BgrtEnableQuietBoot (SetBootLogo);
if (!EFI_ERROR(Status)) {
return Status;
}
}
UgaDraw = NULL;
ColorDepth = 0;
RefreshRate = 0;
//
// Try to open GOP first
//
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
GraphicsOutput = NULL;
//
// Open GOP failed, try to open UGA
//
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
}
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Badging = NULL;
Status = gBS->LocateProtocol (&gEfiOEMBadgingSupportProtocolGuid, NULL, (VOID **)&Badging);
JpegDecoder = NULL;
Status = gBS->LocateProtocol (&gEfiJpegDecoderProtocolGuid, NULL, (VOID **)&JpegDecoder);
PcxDecoder = NULL;
Status = gBS->LocateProtocol (&gEfiPcxDecoderProtocolGuid, NULL, (VOID **)&PcxDecoder);
TgaDecoder = NULL;
Status = gBS->LocateProtocol (&gEfiTgaDecoderProtocolGuid, NULL, (VOID **)&TgaDecoder);
GifDecoder = NULL;
Status = gBS->LocateProtocol (&gEfiGifDecoderProtocolGuid, NULL, (VOID **)&GifDecoder);
BmpDecoder = NULL;
Status = gBS->LocateProtocol (&gEfiBmpDecoderProtocolGuid, NULL, (VOID **) &BmpDecoder);
PngDecoder = NULL;
Status = gBS->LocateProtocol (&gEfiPngDecoderProtocolGuid, NULL, (VOID **)&PngDecoder);
Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **)&ConsoleControl);
if (!EFI_ERROR (Status)) {
ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenGraphics);
} else {
ConsoleControl = NULL;
gST->ConOut->ClearScreen (gST->ConOut);
}
//
// Erase Cursor from screen
//
gST->ConOut->EnableCursor (gST->ConOut, FALSE);
if (GraphicsOutput != NULL) {
SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
} else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
} else {
return EFI_UNSUPPORTED;
}
//
// Initialize the Badge location and attributes
//
BadgeAttribute = EfiBadgingSupportDisplayAttributeCustomized;
BadgeCoordinateX = 0;
BadgeCoordinateY = 0;
OverrideBadgeLocation = FALSE;
Height = 0;
Width = 0;
//
// Set the request for the first image of type Logo
//
Instance = 0;
Type = EfiBadgingSupportImageLogo;
Format = EfiBadgingSupportFormatBMP;
while (1) {
ImageData = NULL;
ImageSize = 0;
TgaFormate = UnsupportedTgaFormat;
HasAlphaChannel = FALSE;
Animation = NULL;
if (IsLogoInDisplayBeforeProtocol ()) {
if (BdsDisplayBeforData == NULL || BdsDisplayBeforData->Image == NULL) {
return EFI_UNSUPPORTED;
}
CoordinateX = 0;
CoordinateY = 0;
Attribute = EfiBadgingSupportDisplayAttributeCenter;
Height = BdsDisplayBeforData->Image->Height;
Width = BdsDisplayBeforData->Image->Width;
Blt = BdsDisplayBeforData->Image->Bitmap;
BltSize = Height * Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
} else if (!PcdGetBool (PcdH2OBdsOemBadgingSupported)) {
Attribute = EfiBadgingSupportDisplayAttributeLeftTop;
Status = GetLogoImageFromFdm (&Blt, &CoordinateX, &CoordinateY, &Width, &Height);
if (EFI_ERROR (Status)) {
Blt = NULL;
BltSize = 0;
CoordinateX = 0;
CoordinateY = 0;
} else {
BltSize = Height * Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
}
} else {
if (Badging != NULL) {
Status = Badging->GetImage (
Badging,
&Instance,
&Type,
&Format,
&ImageData,
&ImageSize,
&Attribute,
&CoordinateX,
&CoordinateY
);
if (EFI_ERROR (Status)) {
//
// After the final logo, reset the instance counter and switch to type Badge
// After the final badge exit the function
//
if (Type == EfiBadgingSupportImageLogo) {
Type = EfiBadgingSupportImageBadge;
Instance = 0;
continue;
}
return Status;
}
switch (Type) {
case EfiBadgingSupportImageLogo:
switch (Format) {
case EfiBadgingSupportFormatBMP:
//
// Upon finding the BMP Logo, save the Badge location from the Reserved values
// in the BMP Header
//
BadgeCoordinateX = ((BMP_IMAGE_HEADER *)ImageData)->Reserved[0];
BadgeCoordinateY = ((BMP_IMAGE_HEADER *)ImageData)->Reserved[1];
OverrideBadgeLocation = TRUE;
break;
case EfiBadgingSupportFormatTGA:
//
// Upon finding the TGA Logo, save the Badge location from the XOrigin
// and YOrigin valuesin the TGA Header
//
BadgeCoordinateX = ((TGA_IMAGE_HEADER *)ImageData)->XOrigin;
BadgeCoordinateY = ((TGA_IMAGE_HEADER *)ImageData)->YOrigin;
OverrideBadgeLocation = TRUE;
break;
case EfiBadgingSupportFormatJPEG:
//
// Upon finding the JPG Logo, save the Badge location from the $LOC Comment
// in the JPG stream
//
for (Index = 0; Index < ImageSize; Index++) {
if (*((UINT8 *)(ImageData + Index)) == 0xFF &&
*((UINT8 *)(ImageData + Index + 1)) == 0xFE) {
pJpegBadgeComment = (JPG_BADGE_COMMENT *)((UINT8 *)(ImageData + Index));
if (pJpegBadgeComment->Signature == BADGE_SIGNATURE) {
BadgeCoordinateX = pJpegBadgeComment->BadgeXLocation;
BadgeCoordinateY = pJpegBadgeComment->BadgeYLocation;
OverrideBadgeLocation = TRUE;
break;
}
}
}
break;
case EfiBadgingSupportFormatPCX:
case EfiBadgingSupportFormatGIF:
case EfiBadgingSupportFormatPNG:
//
// Not Support override badging location right now.
//
break;
default:
FreePool (ImageData);
continue;
}
break;
case EfiBadgingSupportImageBadge:
if (OverrideBadgeLocation) {
//
// It needn't override attribute. If override this, all of the EfiBadgingSupportImageBadge type
// pictures will be displayed in the same location (base on BadgeAttribute setting.
//
CoordinateX = BadgeCoordinateX;
CoordinateY = BadgeCoordinateY;
}
break;
default:
return EFI_INVALID_PARAMETER;
}
} else {
Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
CoordinateX = 0;
CoordinateY = 0;
Attribute = EfiBadgingSupportDisplayAttributeCenter;
}
Blt = NULL;
BltSize = 0;
switch (Format) {
case EfiBadgingSupportFormatBMP:
if (BmpDecoder == NULL) {
Status = EFI_UNSUPPORTED;
break;
}
Status = BmpDecoder->DecodeImage (
BmpDecoder,
ImageData,
ImageSize,
(UINT8 **) &Blt,
&BltSize,
&Height,
&Width
);
break;
case EfiBadgingSupportFormatTGA:
if (TgaDecoder == NULL) {
Status = EFI_UNSUPPORTED;
break;
}
Status = TgaDecoder->DecodeImage (
TgaDecoder,
ImageData,
ImageSize,
(UINT8 **)&Blt,
&BltSize,
&Height,
&Width,
&TgaFormate,
&HasAlphaChannel
);
break;
case EfiBadgingSupportFormatJPEG:
if (JpegDecoder == NULL) {
Status = EFI_UNSUPPORTED;
break;
}
Status = JpegDecoder->DecodeImage (
JpegDecoder,
ImageData,
ImageSize,
(UINT8 **)&Blt,
&BltSize,
&Height,
&Width,
&DecoderStatus
);
break;
case EfiBadgingSupportFormatPCX:
if (PcxDecoder == NULL) {
Status = EFI_UNSUPPORTED;
break;
}
Status = PcxDecoder->DecodeImage (
PcxDecoder,
ImageData,
ImageSize,
(UINT8 **)&Blt,
&BltSize,
&Height,
&Width
);
break;
case EfiBadgingSupportFormatPNG:
if (PngDecoder == NULL) {
Status = EFI_UNSUPPORTED;
break;
}
Status = PngDecoder->DecodeImage (
PngDecoder,
ImageData,
ImageSize,
(UINT8 **) &Blt,
&BltSize,
&Height,
&Width
);
break;
case EfiBadgingSupportFormatGIF:
if (GifDecoder == NULL) {
Status = EFI_UNSUPPORTED;
break;
}
Status = GifDecoder->CreateAnimationFromMem (
GifDecoder,
ImageData,
ImageSize,
NULL,
&Animation
);
if (!EFI_ERROR (Status)) {
Width = Animation->Width;
Height = Animation->Height;
}
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
if (EFI_ERROR (Status)) {
FreePool (ImageData);
if (Badging == NULL) {
return Status;
} else {
continue;
}
}
}
//
// Determine and change the video resolution based on the logo
//
if ((Type == EfiBadgingSupportImageLogo) && (Badging != NULL)) {
if (Badging->OemVideoModeScrStrXY (Badging, OemSupportedVideoMode, (UINT32)Width, (UINT32)Height, &LocX, &LocY)) {
SizeOfX = (UINT32)Width;
SizeOfY = (UINT32)Height;
if (GraphicsOutput != NULL) {
//
// BUGBUG: sync resolution between SimpleTextOut and GraphicsOutput, but it may not find the corresponding text mode and make set mode failed.
//
SetTextModeBySimpleTextOut (gST->ConOut, SizeOfX / EFI_GLYPH_WIDTH, SizeOfY / EFI_GLYPH_HEIGHT);
SetModeByGraphicOutput (GraphicsOutput, SizeOfX, SizeOfY);
} else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
Status = UgaDraw->SetMode (UgaDraw, SizeOfX, SizeOfY, ColorDepth, RefreshRate);
if (EFI_ERROR (Status)) {
if (ImageData != NULL) {
FreePool (ImageData);
}
return EFI_UNSUPPORTED;
}
}
}
}
switch (Attribute) {
case EfiBadgingSupportDisplayAttributeLeftTop:
DestX = CoordinateX;
DestY = CoordinateY;
break;
case EfiBadgingSupportDisplayAttributeCenterTop:
DestX = (SizeOfX - Width) / 2;
DestY = CoordinateY;
break;
case EfiBadgingSupportDisplayAttributeRightTop:
DestX = (SizeOfX - Width - CoordinateX);
DestY = CoordinateY;;
break;
case EfiBadgingSupportDisplayAttributeCenterRight:
DestX = (SizeOfX - Width - CoordinateX);
DestY = (SizeOfY - Height) / 2;
break;
case EfiBadgingSupportDisplayAttributeRightBottom:
DestX = (SizeOfX - Width - CoordinateX);
DestY = (SizeOfY - Height - CoordinateY);
break;
case EfiBadgingSupportDisplayAttributeCenterBottom:
DestX = (SizeOfX - Width) / 2;
DestY = (SizeOfY - Height - CoordinateY);
break;
case EfiBadgingSupportDisplayAttributeLeftBottom:
DestX = CoordinateX;
DestY = (SizeOfY - Height - CoordinateY);
break;
case EfiBadgingSupportDisplayAttributeCenterLeft:
DestX = CoordinateX;
DestY = (SizeOfY - Height) / 2;
break;
case EfiBadgingSupportDisplayAttributeCenter:
DestX = (SizeOfX - Width) / 2;
DestY = (SizeOfY - Height) / 2;
break;
default:
DestX = CoordinateX;
DestY = CoordinateY;
break;
}
if ((DestX >= 0) && (DestY >= 0)) {
if (GraphicsOutput != NULL) {
if (Format == EfiBadgingSupportFormatGIF && GifDecoder != NULL && Animation != NULL) {
AnimationRefreshEntry.Animation = Animation;
AnimationRefreshEntry.Data = NULL;
AnimationRefreshEntry.X = DestX;
AnimationRefreshEntry.Y = DestY;
AnimationRefreshEntry.BltWidth = SizeOfX;
AnimationRefreshEntry.BltHeight = SizeOfY;
AnimationRefreshEntry.Current = NULL;
AnimationRefreshEntry.RecordTick = 0;
AnimationRefreshEntry.AutoLoop = FALSE;
AnimationRefreshEntry.Status = ANIM_STATUS_PLAY;
//
// Only one picture, don't play animation
//
if (Animation->Frames != NULL && Animation->Frames->Next == NULL) {
Status = GifDecoder->NextAnimationFrame (
GifDecoder,
&AnimationRefreshEntry,
GraphicsOutput
);
} else {
while (1) {
if (ConsoleControl != NULL) {
ConsoleControl->GetMode (ConsoleControl, &ScreenMode, NULL, NULL);
if (ScreenMode == EfiConsoleControlScreenText) {
break;
}
}
Status = GifDecoder->RefreshAnimation (
GifDecoder,
&AnimationRefreshEntry,
GraphicsOutput,
0
);
if (EFI_ERROR (Status)) {
break;
}
//
// wait 0.001 second
//
gBS->Stall (1000);
};
}
GifDecoder->DestroyAnimation (GifDecoder, Animation);
} else {
if (Format == EfiBadgingSupportFormatTGA && Blt != NULL && TgaDecoder != NULL) {
if (HasAlphaChannel) {
VideoBuffer = AllocatePool (BltSize);
Status = GraphicsOutput->Blt (
GraphicsOutput,
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) VideoBuffer,
EfiBltVideoToBltBuffer,
(UINTN) DestX,
(UINTN) DestY,
0,
0,
Width,
Height,
Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
Status = TgaDecoder->CalculateBltImage (
TgaDecoder,
(UINT8 *) Blt,
BltSize,
VideoBuffer,
BltSize,
TgaFormate
);
FreePool (Blt);
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) VideoBuffer;
}
}
if (Blt != NULL) {
Status = GraphicsOutput->Blt (
GraphicsOutput,
Blt,
EfiBltBufferToVideo,
0,
0,
(UINTN) DestX,
(UINTN) DestY,
Width,
Height,
Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
}
}
} else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
if (Format == EfiBadgingSupportFormatTGA && Blt != NULL && TgaDecoder != NULL) {
if (HasAlphaChannel) {
VideoBuffer = AllocatePool (BltSize);
Status = UgaDraw->Blt (
UgaDraw,
(EFI_UGA_PIXEL *) VideoBuffer,
EfiBltVideoToBltBuffer,
(UINTN) DestX,
(UINTN) DestY,
0,
0,
Width,
Height,
Width * sizeof (EFI_UGA_PIXEL)
);
Status = TgaDecoder->CalculateBltImage (
TgaDecoder,
(UINT8 *) Blt,
BltSize,
VideoBuffer,
BltSize,
TgaFormate
);
FreePool (Blt);
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) VideoBuffer;
}
}
if (Blt != NULL) {
Status = UgaDraw->Blt (
UgaDraw,
(EFI_UGA_PIXEL *) Blt,
EfiUgaBltBufferToVideo,
0,
0,
(UINTN) DestX,
(UINTN) DestY,
Width,
Height,
Width * sizeof (EFI_UGA_PIXEL)
);
}
} else {
Status = EFI_UNSUPPORTED;
}
}
//
//Display Oem String Message
//
if ((Type == EfiBadgingSupportImageLogo) && (Badging != NULL)) {
mAutoPlaceStrDestY = SizeOfY / 2;
ShowOemString(Badging, OemGraphicsIsHotKeyDetected (), 0);
}
if (ImageData != NULL) {
FreePool (ImageData);
}
if (Blt != NULL) {
FreePool (Blt);
}
if (Badging == NULL || IsLogoInDisplayBeforeProtocol () || !PcdGetBool (PcdH2OBdsOemBadgingSupported)) {
break;
}
}
return Status;
}
/**
Use SystemTable Conout to turn on video based Simple Text Out consoles. The
Simple Text Out screens will now be synced up with all non video output devices
@retval EFI_SUCCESS UGA devices are back in text mode and synced up.
**/
EFI_STATUS
DisableQuietBoot (
VOID
)
{
EFI_STATUS Status;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
UINTN MaxMode;
UINT32 ModeNumber;
UINT32 ScuResolutionX;
UINT32 ScuResolutionY;
UINTN Columns;
UINTN Rows;
UgaDraw = NULL;
GraphicsOutput = NULL;
Status = GetBootGop (&GraphicsOutput);
if (EFI_ERROR (Status)) {
GraphicsOutput = NULL;
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **)&UgaDraw);
if (EFI_ERROR (Status)) {
OnEndOfDisableQuietBoot ();
return EFI_UNSUPPORTED;
}
}
ConsoleControl = NULL;
Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **)&ConsoleControl);
if (!EFI_ERROR (Status)) {
Status = ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenText);
}
Status = GetPreferredResolution (
gST->ConsoleOutHandle,
&ScuResolutionX,
&ScuResolutionY,
NULL,
NULL,
NULL
);
MaxMode = gST->ConOut->Mode->MaxMode;
ModeNumber = (UINT32) MaxMode;
if (!EFI_ERROR (Status)) {
for (ModeNumber = 2; ModeNumber < MaxMode; ModeNumber++) {
//
// Based on scu resoltuion, find the text mode that enables full screen text view.
//
gST->ConOut->QueryMode (gST->ConOut, ModeNumber, &Columns, &Rows);
if ((ScuResolutionX / EFI_GLYPH_WIDTH == Columns) &&
(ScuResolutionY / EFI_GLYPH_HEIGHT == Rows) ) {
Status = gST->ConOut->SetMode (gST->ConOut, ModeNumber);
break;
}
}
}
//
// When one video care with two display output, and plug-in two display,
// the GOP.SetMode function maybe fail
//
if (EFI_ERROR (Status)) {
for (ModeNumber = 0; ModeNumber < MaxMode; ModeNumber++) {
gST->ConOut->QueryMode (gST->ConOut, ModeNumber, &Columns, &Rows);
if ((PcdGet32 (PcdDefaultHorizontalResolution) / EFI_GLYPH_WIDTH == Columns) &&
(PcdGet32 (PcdDefaultVerticalResolution) / EFI_GLYPH_HEIGHT == Rows)) {
Status = gST->ConOut->SetMode (gST->ConOut, ModeNumber);
break;
}
}
}
if (EFI_ERROR (Status) || ModeNumber == MaxMode) {
gST->ConOut->SetMode (gST->ConOut, 0);
}
if (ConsoleControl == NULL) {
gST->ConOut->ClearScreen (gST->ConOut);
}
//
// Enable Cursor on Screen
//
gST->ConOut->EnableCursor (gST->ConOut, TRUE);
OnEndOfDisableQuietBoot ();
return Status;
}
/*++
Routine Description:
Retrieve native resolution of a panel by reading its Edid information.
Arguments:
*EdidDiscovered - A pointer to Edid discovered protocol
*ResolutionX - A pointer to native horizontal resolution of a panel.
*ResolutionY - A pointer to native vertical resolution of a panel.
Returns:
EFI_SUCCESS - The function runs correctly.
EFI_INVALID_PARAMETER - Invalid parameter.
-*/
EFI_STATUS
GetResolutionByEdid (
IN EFI_EDID_DISCOVERED_PROTOCOL *EdidDiscovered,
OUT UINT32 *ResolutionX,
OUT UINT32 *ResolutionY
)
{
UINT8 TempBufferH;
UINT8 TempBufferL;
UINT32 NativeResolutionX;
UINT32 NativeResolutionY;
VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;
ASSERT (EdidDiscovered != NULL);
ASSERT (ResolutionX != NULL);
ASSERT (ResolutionY != NULL);
if ((EdidDiscovered == NULL) || (ResolutionX == NULL) || (ResolutionY == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (EdidDiscovered->Edid == NULL) {
return EFI_UNSUPPORTED;
}
EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidDiscovered->Edid;
TempBufferH = EdidDataBlock->DetailedTimingDescriptions[4];
TempBufferL = EdidDataBlock->DetailedTimingDescriptions[2];
NativeResolutionX = ((((TempBufferH>>4)&0x0F) * 256) + TempBufferL) & 0x0FFF;
TempBufferH = EdidDataBlock->DetailedTimingDescriptions[7];
TempBufferL = EdidDataBlock->DetailedTimingDescriptions[5];
NativeResolutionY = ((((TempBufferH>>4)&0x0F) * 256) + TempBufferL) & 0x0FFF;
*ResolutionX = NativeResolutionX;
*ResolutionY = NativeResolutionY;
return EFI_SUCCESS;
}
BOOLEAN
IsModeSync (
VOID
)
{
EFI_GRAPHICS_OUTPUT_PROTOCOL *ConOutGraphicsOutput;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_HANDLE *HandleBuffer;
UINTN NumberOfHandles;
UINTN Index;
EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
EFI_STATUS Status;
BOOLEAN SyncStatus;
SyncStatus = TRUE;
Status = GetBootGop (&ConOutGraphicsOutput);
if (EFI_ERROR (Status)) {
return SyncStatus;
}
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiGraphicsOutputProtocolGuid,
NULL,
&NumberOfHandles,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return SyncStatus;
}
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;
}
if (ConOutGraphicsOutput->Mode->Info->HorizontalResolution !=
GraphicsOutput->Mode->Info->HorizontalResolution ||
ConOutGraphicsOutput->Mode->Info->VerticalResolution!=
GraphicsOutput->Mode->Info->VerticalResolution) {
SyncStatus = FALSE;
}
}
FreePool (HandleBuffer);
return SyncStatus;
}
/**
Calculate GCD(Greatest Common Divisor) value
@param[in] A First value
@param[in] B Second value
@return UINT32 The GCD value
**/
UINT32
CalculateGcd (
UINT32 A,
UINT32 B
)
{
UINT32 Temp;
while (B != 0) {
Temp = A % B;
A = B;
B = Temp;
}
return A;
}
/**
Search current specific mode supported the user defined resolution
for the Graphics Console device based on Graphics Output Protocol.
@param[in] GraphicsOutput Graphics Output Protocol instance pointer.
@param[in] HorizontalResolution User defined horizontal resolution
@param[in] VerticalResolution User defined vertical resolution.
@param[out] GopModeNum Current specific mode to be check.
@param[out] ResolutionX Preffered resoltion X
@param[out] ResolutionY Preffered resoltion Y
@retval EFI_SUCCESS The mode is supported.
@retval EFI_NOT_FOUND The specific mode is out of range of graphics
device supported.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
EFI_STATUS
FindNearestGopMode (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN UINT32 HorizontalResolution,
IN UINT32 VerticalResolution,
OUT UINT32 *GopModeNum,
OUT UINT32 *ResolutionX,
OUT UINT32 *ResolutionY
)
{
EFI_STATUS Status;
UINT32 SelResolutionX;
UINT32 SelResolutionY;
UINT32 SelModeNum;
UINT32 ModeNum;
UINT32 MaxMode;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
UINT32 RatioX;
UINT32 RatioY;
UINT32 GcdValue;
UINTN Count;
ASSERT (GraphicsOutput != NULL);
ASSERT (GopModeNum != NULL);
ASSERT (ResolutionX != NULL);
ASSERT (ResolutionY != NULL);
if ((GraphicsOutput == NULL) ||
(GopModeNum == NULL) ||
(ResolutionX == NULL) ||
(ResolutionY == NULL)) {
return EFI_INVALID_PARAMETER;
}
ASSERT (HorizontalResolution != 0 || VerticalResolution != 0);
if (GraphicsOutput == NULL ||
HorizontalResolution == 0 ||
VerticalResolution == 0) {
return EFI_INVALID_PARAMETER;
}
MaxMode = GraphicsOutput->Mode->MaxMode;
GcdValue = CalculateGcd (HorizontalResolution, VerticalResolution);
RatioX = HorizontalResolution / GcdValue;
RatioY = VerticalResolution / GcdValue;
//
// count == 0, search same aspect ratio
// count == 1, search all aspect ratio
//
for (Count = 0; Count < 2; Count++) {
SelModeNum = MaxMode;
SelResolutionX = (UINT32)-1;
SelResolutionY = (UINT32)-1;
for (ModeNum = 0; ModeNum < MaxMode; ModeNum++) {
Info = NULL;
Status = GraphicsOutput->QueryMode (
GraphicsOutput,
ModeNum,
&SizeOfInfo,
&Info
);
if (EFI_ERROR (Status) ||
Info->HorizontalResolution < HorizontalResolution ||
Info->VerticalResolution < VerticalResolution) {
FreePool (Info);
continue;
}
if (Count == 0 &&
((Info->HorizontalResolution / GcdValue != RatioX) ||
(Info->VerticalResolution / GcdValue != RatioY))) {
FreePool (Info);
continue;
}
if ((Info->HorizontalResolution < SelResolutionX) ||
((Info->HorizontalResolution == SelResolutionX) &&
(Info->VerticalResolution <= SelResolutionY))) {
SelModeNum = ModeNum;
SelResolutionX = Info->HorizontalResolution;
SelResolutionY = Info->VerticalResolution;
FreePool (Info);
}
}
if (SelModeNum != MaxMode) {
*GopModeNum = SelModeNum;
*ResolutionX = SelResolutionX;
*ResolutionY = SelResolutionY;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Check if the current specific mode supported the user defined resolution
for the Graphics Console device based on Graphics Output Protocol.
If yes, set the graphic devcice's current mode to this specific mode.
@param GraphicsOutput Graphics Output Protocol instance pointer.
@param HorizontalResolution User defined horizontal resolution
@param VerticalResolution User defined vertical resolution.
@param CurrentModeNumber Current specific mode to be check.
@retval EFI_SUCCESS The mode is supported.
@retval EFI_UNSUPPORTED The specific mode is out of range of graphics
device supported.
@retval other The specific mode does not support user defined
resolution or failed to set the current mode to the
specific mode on graphics device.
**/
EFI_STATUS
CheckModeSupported (
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN UINT32 HorizontalResolution,
IN UINT32 VerticalResolution,
OUT UINT32 *CurrentModeNumber
)
{
UINT32 ModeNumber;
EFI_STATUS Status;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
UINT32 MaxMode;
ASSERT (CurrentModeNumber != NULL);
if (CurrentModeNumber == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
MaxMode = GraphicsOutput->Mode->MaxMode;
for (ModeNumber = 0; ModeNumber < MaxMode; ModeNumber++) {
Info = NULL;
Status = GraphicsOutput->QueryMode (
GraphicsOutput,
ModeNumber,
&SizeOfInfo,
&Info
);
if (!EFI_ERROR (Status)) {
if ((Info->HorizontalResolution == HorizontalResolution) &&
(Info->VerticalResolution == VerticalResolution)) {
FreePool (Info);
break;
}
FreePool (Info);
}
}
if (ModeNumber == MaxMode) {
return EFI_UNSUPPORTED;
}
*CurrentModeNumber = ModeNumber;
return Status;
}
/*++
Get GOP resolution by specific priority.
1. Input preferred resolution.
2. Nearest resolution of PCD default resolution
3. Resolution of GOP mode 0
@param[in] GraphicsOutput Instance of console out handle
@param[in] PreferredResolutionX Preferred resolution X
@param[in] PreferredResolutionY Preferred resolution Y
@param[out] ResultResolutionX Pointer to result resolution X
@param[out] ResultResolutionY Pointer to result resolution Y
@param[out] ResultModeNum Pointer to result GOP mode
@retval EFI_SUCCESS Get GOP resolution successfully.
@retval EFI_INVALID_PARAMETER Input parameter is NULL.
@retval EFI_NOT_FOUND Failed to get a valid GOP resolution.
**/
STATIC
EFI_STATUS
GetResolution (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN UINT32 PreferredResolutionX,
IN UINT32 PreferredResolutionY,
OUT UINT32 *ResultResolutionX,
OUT UINT32 *ResultResolutionY,
OUT UINT32 *ResultModeNum OPTIONAL
)
{
EFI_STATUS Status;
UINT32 ResolutionX;
UINT32 ResolutionY;
UINT32 ModeNum;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
if (GraphicsOutput == NULL || ResultResolutionX == NULL || ResultResolutionY == NULL) {
return EFI_INVALID_PARAMETER;
}
ResolutionX = 0;
ResolutionY = 0;
ModeNum = 0;
if (PreferredResolutionX != 0 && PreferredResolutionY != 0) {
Status = CheckModeSupported (
GraphicsOutput,
PreferredResolutionX,
PreferredResolutionY,
&ModeNum
);
if (!EFI_ERROR (Status)) {
ResolutionX = PreferredResolutionX;
ResolutionY = PreferredResolutionY;
goto Done;
}
}
Status = FindNearestGopMode (
GraphicsOutput,
PcdGet32 (PcdDefaultHorizontalResolution),
PcdGet32 (PcdDefaultVerticalResolution),
&ModeNum,
&ResolutionX,
&ResolutionY
);
if (!EFI_ERROR (Status)) {
goto Done;
}
ModeNum = 0;
Status = GraphicsOutput->QueryMode (
GraphicsOutput,
ModeNum,
&SizeOfInfo,
&Info
);
if (!EFI_ERROR (Status)) {
ResolutionX = Info->HorizontalResolution;
ResolutionY = Info->VerticalResolution;
FreePool (Info);
goto Done;
}
return EFI_NOT_FOUND;
Done:
*ResultResolutionX = ResolutionX;
*ResultResolutionY = ResolutionY;
if (ResultModeNum != NULL) {
*ResultModeNum = ModeNum;
}
return EFI_SUCCESS;
}
/*++
Retrieve preferred resolution of a GOP.
@param[in] GraphicsOutput Instance of console out handle
@param[out] ScuResolutionX X axis of text (SCU) resoliton
@param[out] ScuResolutionY Y axis of text (SCU) resoliton
@param[out] GraphicsResoltionX X axis of graphics resoliton
@param[out] GraphicsResoltionY Y axis of graphics resoliton
@retval EFI_SUCCESS Function complete successfully.
**/
EFI_STATUS
GetPreferredResolution (
IN EFI_HANDLE ConOutHandle,
OUT UINT32 *ScuResolutionX OPTIONAL,
OUT UINT32 *ScuResolutionY OPTIONAL,
OUT UINT32 *GraphicsGopModeNumber OPTIONAL,
OUT UINT32 *GraphicsResoltionX OPTIONAL,
OUT UINT32 *GraphicsResoltionY OPTIONAL
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_EDID_DISCOVERED_PROTOCOL *EdidDiscovered;
OEM_LOGO_RESOLUTION_DEFINITION *OemLogoResolution;
OEM_LOGO_RESOLUTION_DEFINITION *OemLogoResolutionPtr;
UINT32 NativeResolutionX;
UINT32 NativeResolutionY;
UINT32 ModeNumber;
ASSERT (ConOutHandle != NULL);
if (ConOutHandle == NULL ||
((ScuResolutionX != NULL && ScuResolutionY == NULL) ||
(ScuResolutionX == NULL && ScuResolutionY != NULL)) ||
((GraphicsResoltionX != NULL && GraphicsResoltionY == NULL) ||
(GraphicsResoltionX == NULL && GraphicsResoltionY != NULL))) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->HandleProtocol (
ConOutHandle,
&gEfiGraphicsOutputProtocolGuid,
(VOID **)&GraphicsOutput
);
if (EFI_ERROR (Status)) {
return Status;
}
OemLogoResolution = AllocateCopyPool (PcdGetSize (PcdDefaultLogoResolution), PcdGetPtr (PcdDefaultLogoResolution));
if (OemLogoResolution == NULL) {
return EFI_OUT_OF_RESOURCES;
}
OemLogoResolutionPtr = OemLogoResolution;
//
// According to Window 8 logo requirement (System.Client.Firmware.UEFI.GOP)
// If Edid mode is not supported, UEFI must select an alternate mode that matches
// the same aspect ratio as the native resolution of the display.
// If the display device does not provide an EDID, UEFI must set a mode of
// 1024 x 768
//
Status = gBS->HandleProtocol (
ConOutHandle,
&gEfiEdidDiscoveredProtocolGuid,
(VOID **)&EdidDiscovered
);
if (!EFI_ERROR (Status)) {
Status = GetResolutionByEdid (EdidDiscovered, &NativeResolutionX, &NativeResolutionY);
if (!EFI_ERROR (Status)) {
Status = FindNearestGopMode (
GraphicsOutput,
NativeResolutionX,
NativeResolutionY,
&ModeNumber,
&NativeResolutionX,
&NativeResolutionY
);
if (!EFI_ERROR (Status)) {
OemLogoResolutionPtr->LogoResolutionX = NativeResolutionX;
OemLogoResolutionPtr->LogoResolutionY = NativeResolutionY;
}
}
}
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcLogoResolution \n"));
Status = OemSvcLogoResolution (&OemLogoResolutionPtr);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcLogoResolution Status: %r\n", Status));
Status = EFI_SUCCESS;
if (GraphicsResoltionX != NULL && GraphicsResoltionY != NULL) {
Status = GetResolution (
GraphicsOutput,
(OemLogoResolutionPtr == NULL) ? 0 : OemLogoResolutionPtr->LogoResolutionX,
(OemLogoResolutionPtr == NULL) ? 0 : OemLogoResolutionPtr->LogoResolutionY,
GraphicsResoltionX,
GraphicsResoltionY,
GraphicsGopModeNumber
);
if (EFI_ERROR (Status)) {
goto Done;
}
}
if (ScuResolutionX != NULL && ScuResolutionY != NULL) {
Status = GetResolution (
GraphicsOutput,
(OemLogoResolutionPtr == NULL) ? 0 : OemLogoResolutionPtr->ScuResolutionX,
(OemLogoResolutionPtr == NULL) ? 0 : OemLogoResolutionPtr->ScuResolutionY,
ScuResolutionX,
ScuResolutionY,
NULL
);
if (EFI_ERROR (Status)) {
goto Done;
}
}
Done:
FreePool (OemLogoResolution);
return Status;
}
BOOLEAN
TextOnlyConsole (
VOID
)
{
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_DEVICE_PATH_PROTOCOL *NextDevPathInstance;
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
BOOLEAN FoundTextBasedCon;
UINTN Size;
//
//init local
//
RemainingDevicePath = NULL;
Gop = NULL;
FoundTextBasedCon = FALSE;
NextDevPathInstance = NULL;
RemainingDevicePath = OemGraphicsGetAllActiveConOutDevPath ();
do {
//
//find all output console handles
//
NextDevPathInstance = OemGraphicsGetNextDevicePathInstance (&RemainingDevicePath, &Size);
if (NextDevPathInstance != NULL) {
gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &NextDevPathInstance, &Handle);
Status = gBS->HandleProtocol (
Handle,
&gEfiGraphicsOutputProtocolGuid,
(VOID*)&Gop
);
if (EFI_ERROR (Status)) {
//
//found text-based console
//
FoundTextBasedCon = TRUE;
break;
}
}
} while (RemainingDevicePath != NULL);
return FoundTextBasedCon;
}
VOID
DisplayMessageToConsoleRedirection (
IN CHAR16 *LogoStr
)
{
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_DEVICE_PATH_PROTOCOL *NextDevPathInstance;
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
BOOLEAN FoundTextBasedCon;
UINTN Size;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOutProto;
//
//init local
//
RemainingDevicePath = NULL;
Gop = NULL;
FoundTextBasedCon = FALSE;
NextDevPathInstance = NULL;
RemainingDevicePath = OemGraphicsGetAllActiveConOutDevPath ();
do {
//
//find all output console handles
//
NextDevPathInstance = OemGraphicsGetNextDevicePathInstance (&RemainingDevicePath, &Size);
if (NextDevPathInstance != NULL) {
gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &NextDevPathInstance, &Handle);
Status = gBS->HandleProtocol (
Handle,
&gEfiGraphicsOutputProtocolGuid,
(VOID*)&Gop
);
if (EFI_ERROR (Status)) {
//
//found text-based console
//
Status = gBS->HandleProtocol (
Handle,
&gEfiSimpleTextOutProtocolGuid,
(VOID*) &TextOutProto
);
if (!EFI_ERROR (Status)) {
TextOutProto->SetCursorPosition (TextOutProto, 0, 0);
TextOutProto->OutputString (TextOutProto, LogoStr);
}
}
}
} while (RemainingDevicePath != NULL);
}
VOID *
OemGraphicsGetAllActiveConOutDevPath (
VOID
)
{
UINTN NoHandles;
EFI_HANDLE *HandleBuf;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
EFI_DEVICE_PATH_PROTOCOL *ConsoleDevPath;
EFI_DEVICE_PATH_PROTOCOL *TempDevPath;
EFI_STATUS Status;
UINT8 Index;
//
//init local
//
NoHandles = 0;
HandleBuf = NULL;
DevPath = NULL;
ConsoleDevPath = NULL;
TempDevPath = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiConsoleOutDeviceGuid,
NULL,
&NoHandles,
&HandleBuf
);
if (EFI_ERROR (Status)) {
return NULL;
}
for (Index = 0; Index < NoHandles; Index++) {
Status = gBS->HandleProtocol (
HandleBuf [Index],
&gEfiDevicePathProtocolGuid,
(VOID **)&DevPath
);
if (EFI_ERROR (Status) || (DevPath == NULL)) {
continue;
}
TempDevPath = ConsoleDevPath;
ConsoleDevPath = AppendDevicePathInstance (ConsoleDevPath, DevPath);
if (TempDevPath != NULL) {
FreePool (TempDevPath);
}
}
FreePool (HandleBuf);
return ConsoleDevPath;
}
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
OemGraphicsGetNextDevicePathInstance (
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
OUT UINTN *Size
)
/*++
Routine Description:
Function retrieves the next device path instance from a device path data structure.
Arguments:
DevicePath - A pointer to a device path data structure.
Size - A pointer to the size of a device path instance in bytes.
Returns:
This function returns a pointer to the current device path instance.
In addition, it returns the size in bytes of the current device path instance in Size,
and a pointer to the next device path instance in DevicePath.
If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.
--*/
{
EFI_DEVICE_PATH_PROTOCOL *DevPath;
EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
UINT8 Temp;
ASSERT (Size != NULL);
if (Size == NULL) {
return NULL;
}
if (DevicePath == NULL || *DevicePath == NULL) {
*Size = 0;
return NULL;
}
if (!OemGraphicsIsDevicePathValid (*DevicePath, 0)) {
return NULL;
}
//
// Find the end of the device path instance
//
DevPath = *DevicePath;
while (!OemGraphicsIsDevicePathEndType (DevPath)) {
DevPath = OemGraphicsNextDevicePathNode (DevPath);
}
//
// Compute the size of the device path instance
//
*Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
//
// Make a copy and return the device path instance
//
Temp = DevPath->SubType;
DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
ReturnValue = OemGraphicsDuplicateDevicePath (*DevicePath);
DevPath->SubType = Temp;
//
// If DevPath is the end of an entire device path, then another instance
// does not follow, so *DevicePath is set to NULL.
//
if (OemGraphicsDevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
*DevicePath = NULL;
} else {
*DevicePath = OemGraphicsNextDevicePathNode (DevPath);
}
return ReturnValue;
}
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
OemGraphicsDuplicateDevicePath (
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
/*++
Routine Description:
Duplicate a device path structure.
Arguments:
DevicePath - The device path to duplicated.
Returns:
The duplicated device path.
--*/
{
UINTN Size;
//
// Compute the size
//
Size = OemGraphicsGetDevicePathSize (DevicePath);
if (Size == 0) {
return NULL;
}
//
// Allocate space for duplicate device path
//
return AllocateCopyPool (Size, DevicePath);
}
UINTN
EFIAPI
OemGraphicsGetDevicePathSize (
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
/*++
Routine Description:
Calculate the space size of a device path.
Arguments:
DevicePath - A specified device path
Returns:
The size.
--*/
{
CONST EFI_DEVICE_PATH_PROTOCOL *Start;
if (DevicePath == NULL) {
return 0;
}
if (!OemGraphicsIsDevicePathValid (DevicePath, 0)) {
return 0;
}
//
// Search for the end of the device path structure
//
Start = DevicePath;
while (!OemGraphicsIsDevicePathEnd (DevicePath)) {
DevicePath = OemGraphicsNextDevicePathNode (DevicePath);
}
//
// Compute the size and add back in the size of the end device path structure
//
return ((UINTN) DevicePath - (UINTN) Start) + OemGraphicsDevicePathNodeLength (DevicePath);
}
BOOLEAN
EFIAPI
OemGraphicsIsDevicePathValid (
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN UINTN MaxSize
)
{
UINTN Count;
UINTN Size;
UINTN NodeLength;
ASSERT (DevicePath != NULL);
if (DevicePath == NULL) {
return FALSE;
}
for (Count = 0, Size = 0; !OemGraphicsIsDevicePathEnd (DevicePath); DevicePath = OemGraphicsNextDevicePathNode (DevicePath)) {
NodeLength = OemGraphicsDevicePathNodeLength (DevicePath);
if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
return FALSE;
}
if (MaxSize > 0) {
Size += NodeLength;
if (Size + END_DEVICE_PATH_LENGTH > MaxSize) {
return FALSE;
}
}
if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
Count++;
if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
return FALSE;
}
}
}
//
// Only return TRUE when the End Device Path node is valid.
//
return (BOOLEAN) (OemGraphicsDevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
}
BOOLEAN
EFIAPI
OemGraphicsIsDevicePathEndType (
IN CONST VOID *Node
)
{
ASSERT (Node != NULL);
if (Node == NULL) {
return FALSE;
}
return (BOOLEAN) (OemGraphicsDevicePathType (Node) == END_DEVICE_PATH_TYPE);
}
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
OemGraphicsNextDevicePathNode (
IN CONST VOID *Node
)
{
ASSERT (Node != NULL);
return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + OemGraphicsDevicePathNodeLength(Node));
}
UINT8
EFIAPI
OemGraphicsDevicePathSubType (
IN CONST VOID *Node
)
{
ASSERT (Node != NULL);
if (Node == NULL) {
return 0;
}
return ((EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;
}
BOOLEAN
EFIAPI
OemGraphicsIsDevicePathEnd (
IN CONST VOID *Node
)
{
ASSERT (Node != NULL);
if (Node == NULL) {
return FALSE;
}
return (BOOLEAN) (OemGraphicsIsDevicePathEndType (Node) && OemGraphicsDevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
}
UINTN
EFIAPI
OemGraphicsDevicePathNodeLength (
IN CONST VOID *Node
)
{
UINTN Length;
ASSERT (Node != NULL);
Length = ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
ASSERT (Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL));
return Length;
}
UINT8
EFIAPI
OemGraphicsDevicePathType (
IN CONST VOID *Node
)
{
ASSERT (Node != NULL);
if (Node == NULL) {
return 0;
}
return ((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
}