/** @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 //_Start_L05_FEATURE_ #include // gBS #include // gRT #include // CompareMem #include // AllocateZeroPool #ifdef L05_CUSTOMIZE_MULTI_LOGO_SUPPORT #include #include #include //#include #include #endif #ifdef L05_BIOS_POST_LOGO_DIY_SUPPORT #include // L05_BIOS_LOGO_DIY_ESP_FILE_NAME_VARIABLE_NAME #include // L05_BIOS_LOGO_DIY_VERSION_CRC_CONTROL_VARIABLE_NAME #include // gEfiPartTypeSystemPartGuid #include // FileHandleGetSize () & FileHandleRead () #include // StrSize () #include // UnicodeSPrint () #include // 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; }