alder_lake_bios/Board/Oem/L05AlderLakeHXMultiBoardPkg/Library/DxeOemSvcKernelLib/OemSvcChangeDefaultLogoImage.c

630 lines
20 KiB
C

/** @file
Provide OEM to customize changing default logo image. .
;******************************************************************************
;* Copyright (c) 2013, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Library/DxeOemSvcKernelLib.h>
//_Start_L05_FEATURE_
#include <Library/UefiBootServicesTableLib.h> // gBS
#include <Library/UefiRuntimeServicesTableLib.h> // gRT
#include <Library/BaseMemoryLib.h> // CompareMem
#include <Library/MemoryAllocationLib.h> // AllocateZeroPool
#ifdef L05_CUSTOMIZE_MULTI_LOGO_SUPPORT
#include <FlashRegionLayout.h>
#include <Library/FlashRegionLib.h>
#include <Guid/L05CustomizeMultiLogo.h>
//#include <Protocol/JpegDecoder.h>
#include <Protocol/TgaDecoder.h>
#endif
#ifdef L05_BIOS_POST_LOGO_DIY_SUPPORT
#include <Guid/L05EspCustomizePostLogoInfoVariable.h> // L05_BIOS_LOGO_DIY_ESP_FILE_NAME_VARIABLE_NAME
#include <Guid/L05EspCustomizePostLogoVcmVariable.h> // L05_BIOS_LOGO_DIY_VERSION_CRC_CONTROL_VARIABLE_NAME
#include <Guid/Gpt.h> // gEfiPartTypeSystemPartGuid
#include <Library/FileHandleLib.h> // FileHandleGetSize () & FileHandleRead ()
#include <Library/BaseLib.h> // StrSize ()
#include <Library/PrintLib.h> // UnicodeSPrint ()
#include <Protocol/SimpleFileSystem.h> // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
#endif
//_End_L05_FEATURE_
//_Start_L05_CUSTOMIZE_MULTI_LOGO_
#ifdef L05_CUSTOMIZE_MULTI_LOGO_SUPPORT
//
// Define TGA image type, refer from InsydeModulePkg/Universal/Console/TgaDecoderDxe/TgaDecoder.h
//
#define UNCOMPRESSED_TRUE_COLOR_IMAGE 0x02
#define RUN_LENGTH_ENCODED_TRUE_COLOR_IMAGE 0x0A
/**
Check the Image Data is a valid JPEG Image
Refer from InitJfifData() in InsydeModulePkg/Universal/Console/JpegDecoderDxe/JfifDecode.c
@param ImageData The Point to the Image Data
@retval TRUE The Image Data is a valid JPEG Image
@retval FALSE the Image Data is not a valid JPEG Image
**/
BOOLEAN
IsValidJpegImageFile (
IN UINT8 *ImageData
)
{
if (ImageData[0] != 0xFF || ImageData[1] != 0xd8) { // JPEG_SOI = 0xd8
return FALSE;
}
return TRUE;
}
/**
Check the Image Data is a valid TGA Image
Refer from TgaDecoderDecodeImage() in InsydeModulePkg/Universal/Console/TgaDecoderDxe/TgaDecoder.c
@param TgaHeader The Point to the Image Data
@retval TRUE The Image Data is a valid TGA Image
@retval FALSE the Image Data is not a valid TGA Image
**/
BOOLEAN
IsValidTgaImageFile (
IN TGA_IMAGE_HEADER *TgaHeader
)
{
//
// Only support true-color image, and to comply with TGA 1.0, we don't check
// TGA signature TRUEVISION-XFILE
//
if (TgaHeader->DataTypeCode != UNCOMPRESSED_TRUE_COLOR_IMAGE &&
TgaHeader->DataTypeCode != RUN_LENGTH_ENCODED_TRUE_COLOR_IMAGE) {
return FALSE;
}
if (TgaHeader->ColorMapType != 0 && TgaHeader->ColorMapType != 1) {
return FALSE;
}
//
// Check the true-color TGA format and only support TARGA16, TARGA24 and TARGA32 format
//
if (TgaHeader->BitsPerPixel != 16 && TgaHeader->BitsPerPixel != 24 && TgaHeader->BitsPerPixel != 32) {
return FALSE;
}
return TRUE;
}
/**
Check the Image Data is a valid GIF Image
Refer from GifDecoderGetLogicalScreen() in InsydeModulePkg/Universal/Console/GifDecoderDxe/Gif.c
@param GifHeader The Point to the Image Data
@retval TRUE The Image Data is a valid GIF Image
@retval FALSE the Image Data is not a valid GIF Image
**/
BOOLEAN
IsValidGifImageFile (
IN VOID *GifHeader
)
{
if (CompareMem (GifHeader, "GIF87a", 6) != 0 &&
CompareMem (GifHeader, "GIF89a", 6) != 0) {
return FALSE;
}
return TRUE;
}
/**
Customize Multi Logo.
Search logo in PcdFlashFvL05CustomizeLogoBase region during every Normal POST.
Support image format: jpeg, jpg, tga, gif
@param[in, out] Logo On Input with Logo pointing to deafult OEM Logo Data.
On Ouput, OEM replaces the content of OEM Logo data that Logo points to.
@param[in, out] ImageData On Input with ImageData pointing to deafult image data.
On Output with ImageData pointing to new image data found in ROM
@param[in, out] ImageSize On Input with ImageSize pointing to deafult image size.
On Output with ImageSize pointing to new image size.
@retval EFI_UNSUPPORTED Returns unsupported by default.
@retval EFI_MEDIA_CHANGED The value of IN OUT parameter is changed.
@retval Others Base on OEM design.
**/
EFI_STATUS
CustomizeMultiLogo (
IN OUT EFI_OEM_BADGING_LOGO_DATA *Logo,
IN OUT UINT8 **ImageData,
UINTN *ImageSize
)
{
EFI_STATUS Status;
UINT8 *Buffer;
UINT32 MaxImageSize;
L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *RegionHeader;
L05_LOGO_RESOLUTION_INFO CustomizeLogoInfo = {0};
UINTN BufferSize;
//
// Get Logo customization Imagedata from Rom
//
Buffer = (UINT8 *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionCustomizeMultiLogoGuid, 1);
//
// Max Image Size = Total Logo Region Size - Header Size + One Byte Size(First Byte of image data)
//
MaxImageSize = (UINT32) FdmGetNAtSize (&gL05H2OFlashMapRegionCustomizeMultiLogoGuid, 1);
BufferSize = sizeof (L05_LOGO_RESOLUTION_INFO);
Status = gRT->GetVariable (
L05_CUSTOM_MULTI_LOGO_VARIABLE_NAME,
&gL05CustomizeMultiLogoGuid,
NULL,
&BufferSize,
&CustomizeLogoInfo
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Find matched logo by searching screen resolution
//
do {
RegionHeader = (L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer;
if (CompareMem (&(RegionHeader->Guid), &gL05CustomizeMultiLogoGuid, sizeof (EFI_GUID)) == 0 &&
RegionHeader->Signature == L05_CUSTOM_MULTI_LOGO_SIGNATURE &&
RegionHeader->SupportedResolutionX == CustomizeLogoInfo.ResolutionX &&
RegionHeader->SupportedResolutionY == CustomizeLogoInfo.ResolutionY &&
RegionHeader->ImageSize != 0) {
break;
} else {
//
// Move point to next Logo
//
Buffer += sizeof (L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER) - sizeof (UINT8) + RegionHeader->ImageSize;
if (CompareMem (&(RegionHeader->Guid), &gL05CustomizeMultiLogoGuid, sizeof (EFI_GUID)) != 0) {
//
// No matched Customize Logo
//
return EFI_UNSUPPORTED;
}
}
} while (TRUE);
//
// Check the Image Format is valid
//
if (((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageFormat == 0x01 && // EfiBadgingSupportFormatJPEG
IsValidJpegImageFile ((UINT8 *) ((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageData)) {
Logo->Format = 0x01; // EfiBadgingSupportFormatJPEG
} else if (((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageFormat == 0x05 && // EfiBadgingSupportFormatTGA
IsValidTgaImageFile ((TGA_IMAGE_HEADER *) ((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageData)) {
Logo->Format = 0x05; // EfiBadgingSupportFormatTGA
} else if (((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageFormat == 0x03 && // EfiBadgingSupportFormatGIF
IsValidGifImageFile ((VOID *) ((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageData)) {
Logo->Format = 0x03; // EfiBadgingSupportFormatGIF
} else {
//
// No matched Customize Logo
//
return EFI_UNSUPPORTED;
}
//
// Change the Imagedata Path and Size
//
*ImageSize = (UINTN) (((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageSize & (UINT32) (-1));
*ImageData = ((L05_CUSTOM_MULTI_LOGO_FLASH_REGION_HEADER *) Buffer)->ImageData;
return EFI_SUCCESS;
}
#endif
//_End_L05_CUSTOMIZE_MULTI_LOGO_
#ifdef L05_BIOS_POST_LOGO_DIY_SUPPORT
/**
Wrap original EFI_FILE_PROTOCOL->Close call in order to decrease code length
(with setting back This to NULL).
@param[in, out] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to close.
**/
VOID
SafeFileClose (
IN OUT EFI_FILE_PROTOCOL **This
)
{
EFI_STATUS Status;
if (This != NULL && *This != NULL) {
Status = (*This)->Close (*This);
if (!EFI_ERROR (Status)) {
*This = NULL;
}
}
}
/**
File System read data from ESP.
@param[in] FullFileNameBuffer A pointer to the full file name for open the file form ESP.
@param[out] FileData A pointer to the file data form ESP.
@param[out] FileSize A pointer to the data size form ESP.
@retval EFI_SUCCESS Get the file from ESP complete.
@retval Others ESP not have the file.
**/
EFI_STATUS
FsReadDataFromEsp (
IN CHAR16 *FullFileNameBuffer,
OUT VOID **FileData,
OUT UINTN *FileSize
)
{
EFI_STATUS Status;
UINTN Index;
UINTN HandleArrayCount;
EFI_HANDLE *HandleArray;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
EFI_FILE *Root;
EFI_FILE *FileHandle;
UINT64 TempFileSize;
HandleArrayCount = 0;
HandleArray = NULL;
SimpleFileSystem = NULL;
Root = NULL;
FileHandle = NULL;
TempFileSize = 0;
//
// [2.2 Display Logo Picture during POST]
// BIOS need to read logo picture from ESP in BIOS POST.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiPartTypeSystemPartGuid,
NULL,
&HandleArrayCount,
&HandleArray
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Scan each system partition.
//
for (Index = 0; Index < HandleArrayCount; Index++) {
Status = gBS->HandleProtocol (HandleArray[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **) &SimpleFileSystem);
if (EFI_ERROR (Status)) {
continue;
}
//
// Open root of volume.
//
Status = SimpleFileSystem->OpenVolume (SimpleFileSystem, &Root);
if (EFI_ERROR (Status)) {
continue;
}
//
// Open the full file name file on ESP.
//
Status = Root->Open (Root, &FileHandle, FullFileNameBuffer, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR (Status)) {
SafeFileClose (&Root);
continue;
}
Status = FileHandleGetSize (FileHandle, (UINT64 *) &TempFileSize);
if (EFI_ERROR (Status)) {
break;
}
*FileSize = (UINTN) TempFileSize;
*FileData = AllocateZeroPool (*FileSize);
if (*FileData == NULL) {
break;
}
Status = FileHandleRead (FileHandle, FileSize, *FileData);
if (EFI_ERROR (Status)) {
break;
}
//
// Get the file success!!
//
break;
}
SafeFileClose (&FileHandle);
SafeFileClose (&Root);
return Status;
}
/**
Verify CRC32 of customize POST logo in ESP.
Calculate CRC32 of customize POST logo by first 512 bytes to validate the CRC field of the variable "LBLDVCC".
@param[in] FileData A pointer to the file data form ESP.
@retval EFI_SUCCESS Logo from Esp is already verify by LogoDIY tool.
@retval EFI_UNSUPPORTED Logo from Esp is not verify by LogoDIY tool.
**/
EFI_STATUS
VerifyLogoCrc32 (
IN VOID *FileData
)
{
EFI_STATUS Status;
LENOVO_ESP_CUSTOMIZE_POST_LOGO_INFO L05EspCustomizePostLogoInfo;
LENOVO_ESP_CUSTOMIZE_POST_LOGO_VCM L05EspCustomizePostLogoVcm;
UINTN VariableDataSize;
UINT32 Crc32;
Crc32 = 0;
ZeroMem (&L05EspCustomizePostLogoInfo, sizeof (LENOVO_ESP_CUSTOMIZE_POST_LOGO_INFO));
ZeroMem (&L05EspCustomizePostLogoVcm, sizeof (LENOVO_ESP_CUSTOMIZE_POST_LOGO_VCM));
VariableDataSize = sizeof (LENOVO_ESP_CUSTOMIZE_POST_LOGO_INFO);
Status = gRT->GetVariable (
L05_BIOS_LOGO_DIY_ESP_VARIABLE_NAME,
&gEfiL05EspCustomizePostLogoInfoVariableGuid,
NULL,
&VariableDataSize,
&L05EspCustomizePostLogoInfo
);
if (EFI_ERROR (Status)) {
return Status;
}
VariableDataSize = sizeof (LENOVO_ESP_CUSTOMIZE_POST_LOGO_VCM);
Status = gRT->GetVariable (
L05_BIOS_LOGO_DIY_VERSION_CRC_CONTROL_VARIABLE_NAME,
&gEfiL05EspCustomizePostLogoVcmVariableGuid,
NULL,
&VariableDataSize,
&L05EspCustomizePostLogoVcm
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// [Lenovo BIOS POST Logo DIY Version v2.0]
// 2.4 Version and CRC control (new added for v2.0)
// To prevent abuse of non-lenovo tools, BIOS set variable LBLDVC by default,
// and validate the CRC field when LBLDESP.LogoDiySupport enabled.
//
gBS->CalculateCrc32 (FileData, L05_CUSTOMIZE_POST_LOGO_CRC32_CALCULATE_NUM, &Crc32);
if (L05EspCustomizePostLogoVcm.CRC32 == Crc32) {
return Status;
}
//
// [Lenovo BIOS POST Logo DIY Version v2.0]
// 2.4 Version and CRC control (new added for v2.0)
// If validate fail, BIOS should treat Logo DIY feature as disabled.
//
L05EspCustomizePostLogoInfo.LogoDiySupport = 0x00; // FALSE: Function disabled (BIOS will display default logo)
Status = gRT->SetVariable (
L05_BIOS_LOGO_DIY_ESP_VARIABLE_NAME,
&gEfiL05EspCustomizePostLogoInfoVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof (LENOVO_ESP_CUSTOMIZE_POST_LOGO_INFO),
&L05EspCustomizePostLogoInfo
);
return EFI_CRC_ERROR;
}
/**
Get L05 logo from ESP to replace deafult logo image.
@param[in, out] Logo On Input with Logo pointing to deafult OEM Logo Data.
On Ouput, OEM replaces the content of OEM Logo data that Logo points to.
@param[in, out] ImageData On Input with ImageData pointing to deafult image data.
On Output with ImageData pointing to new image data found in ROM
@param[in, out] ImageSize On Input with ImageSize pointing to deafult image size.
On Output with ImageSize pointing to new image size.
@retval EFI_SUCCESS Get L05 logo from ESP complete.
@retval Others ESP not have L05 logo.
**/
EFI_STATUS
GetLogoFromEsp (
IN OUT EFI_OEM_BADGING_LOGO_DATA *Logo,
IN OUT UINT8 **ImageData,
UINTN *ImageSize
)
{
/*++
Todo:
Add project specific code in here.
--*/
EFI_STATUS Status;
L05_BIOS_LOGO_DIY_ESP_FILE_NAME_DATA *CustomizePostLogoFileNameData;
UINTN VariableDataSize;
CHAR16 *FullFileNameBuffer;
UINTN FullFileNameBufferSize;
VOID *FileData;
UINTN FileSize;
CustomizePostLogoFileNameData = NULL;
VariableDataSize = 0;
FullFileNameBuffer = NULL;
FullFileNameBufferSize = 0;
FileData = NULL;
FileSize = 0;
if (!PcdGetBool (PcdL05CustomizeLogoFromEspFlag)) {
return EFI_UNSUPPORTED;
}
Status = gRT->GetVariable (
L05_BIOS_LOGO_DIY_ESP_FILE_NAME_VARIABLE_NAME,
&gEfiL05EspCustomizePostLogoInfoVariableGuid,
NULL,
&VariableDataSize,
CustomizePostLogoFileNameData
);
if (Status != EFI_BUFFER_TOO_SMALL) {
return Status;
}
CustomizePostLogoFileNameData = AllocateZeroPool (VariableDataSize);
if (CustomizePostLogoFileNameData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gRT->GetVariable (
L05_BIOS_LOGO_DIY_ESP_FILE_NAME_VARIABLE_NAME,
&gEfiL05EspCustomizePostLogoInfoVariableGuid,
NULL,
&VariableDataSize,
CustomizePostLogoFileNameData
);
if (EFI_ERROR (Status)) {
gBS->FreePool (CustomizePostLogoFileNameData);
return Status;
}
FullFileNameBufferSize = StrSize (CustomizePostLogoFileNameData->FileName) + StrSize (L05_BIOS_LOGO_DIY_ESP_FOLDER_PATH);
FullFileNameBuffer = AllocateZeroPool (FullFileNameBufferSize);
if (FullFileNameBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UnicodeSPrint (
FullFileNameBuffer,
FullFileNameBufferSize,
L"%s%s",
L05_BIOS_LOGO_DIY_ESP_FOLDER_PATH,
CustomizePostLogoFileNameData->FileName
);
//
// Read data from ESP by File System.
//
Status = FsReadDataFromEsp (FullFileNameBuffer, &FileData, &FileSize);
//
// Verify Esp Logo Data by Crc32
//
Status = VerifyLogoCrc32 (FileData);
if (!EFI_ERROR (Status)) {
//
// Change the Imagedata Data, Size and Format.
//
*ImageSize = FileSize;
*ImageData = (UINT8 *) FileData;
Logo->Format = CustomizePostLogoFileNameData->Format;
}
gBS->FreePool (CustomizePostLogoFileNameData);
gBS->FreePool (FullFileNameBuffer);
return Status;
}
#endif
/**
Get OEM customization logo image.
Customization changing logo image provides OEM to replace deafult logo image.
@param[in, out] Logo On Input with Logo pointing to deafult OEM Logo Data.
On Ouput, OEM replaces the content of OEM Logo data that Logo points to.
@param[in, out] ImageData On Input with ImageData pointing to deafult image data.
On Output with ImageData pointing to new image data found in ROM
@param[in, out] ImageSize On Input with ImageSize pointing to deafult image size.
On Output with ImageSize pointing to new image size.
@retval EFI_UNSUPPORTED Returns unsupported by default.
@retval EFI_MEDIA_CHANGED The value of IN OUT parameter is changed.
@retval Others Base on OEM design.
**/
EFI_STATUS
OemSvcChangeDefaultLogoImage (
IN OUT EFI_OEM_BADGING_LOGO_DATA *Logo,
IN OUT UINT8 **ImageData,
UINTN *ImageSize
)
{
/*++
Todo:
Add project specific code in here.
--*/
//_Start_L05_LOGO_
EFI_STATUS Status;
Status = EFI_UNSUPPORTED;
#ifdef L05_BIOS_POST_LOGO_DIY_SUPPORT
Status = GetLogoFromEsp (Logo, ImageData, ImageSize);
if (!EFI_ERROR (Status)) {
return EFI_MEDIA_CHANGED;
}
#endif
#ifdef L05_CUSTOMIZE_MULTI_LOGO_SUPPORT
Status = CustomizeMultiLogo (Logo, ImageData, ImageSize);
if (!EFI_ERROR (Status)) {
return EFI_MEDIA_CHANGED;
}
#endif
//_End_L05_LOGO_
return EFI_UNSUPPORTED;
}