alder_lake_bios/Insyde/InsydeModulePkg/Library/DxeImageVerificationLib/UnsignedFvRegion.c

234 lines
7.4 KiB
C

/** @file
Helper functions for Unsigned FV Region feature
;******************************************************************************
;* Copyright (c) 2013 - 2016, 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 <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Ppi/FirmwareAuthentication.h>
#include <Library/MemoryAllocationLib.h>
#include <Guid/FirmwareFileSystem2.h>
#include "UnsignedFvRegion.h"
/**
Retrieve firmware(BIOS) infomation from the Image.
Search BIOS address from FirmwareAddress.
@param [in, out] FirmwareAddress the image address
@param [in] FirmwareSize the size of the image
@param [out] FirmwareOffset the offset of the BIOS address from the image
@retval EFI_SUCCESS found the BIOS address
@retval EFI_NOT_FOUND did not find one
**/
EFI_STATUS
RetrieveFirmware (
IN OUT UINT8 **FirmwareAddress,
IN UINTN FirmwareSize,
OUT UINTN *FirmwareOffset
)
{
UINTN Index;
UINT8 *BiosImgAddress;
ISFLASH_DATA_REGION_HEADER *BiosDataRegion;
//
// Search the location of the BIOS image.
//
BiosImgAddress = *FirmwareAddress;
for (Index = 0; Index < FirmwareSize; Index++) {
if (CompareMem (BiosImgAddress + Index, ISFLASH_BIOS_IMAGE_TAG_HALF_1, ISFLASH_HALF_TAG_SIZE) == 0){
if (CompareMem (BiosImgAddress + Index+ISFLASH_HALF_TAG_SIZE, ISFLASH_BIOS_IMAGE_TAG_HALF_2, ISFLASH_HALF_TAG_SIZE) == 0){
BiosDataRegion = (ISFLASH_DATA_REGION_HEADER *)(BiosImgAddress + Index);
*FirmwareOffset = Index + sizeof (ISFLASH_DATA_REGION_HEADER);
*FirmwareAddress = *FirmwareAddress + *FirmwareOffset;
break;
}
}
}
if (Index >= (FirmwareSize - ISFLASH_TAG_SIZE)) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
BOOLEAN
VerifyHeaderChecksum (
IN EFI_FFS_FILE_HEADER *FfsHeader
)
{
UINT8 HeaderChecksum;
if (IS_FFS_FILE2 (FfsHeader)) {
HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
} else {
HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
}
HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
if (HeaderChecksum == 0) {
return TRUE;
} else {
return FALSE;
}
}
/**
Backup the data of the unsigned FV region.
This function allocates a buffer to save the data.
@param [in] ImageAddress the image address
@param [in] ImageSize the size of the image
@param [out] SkipRegionOffset the offset of the unsigned FV region from the image
@param [out] SkipRegionSize the size of the unsigned FV region
@param [out] SkipRegionDataBuffer the pointer of the backup buffer
@retval EFI_SUCCESS backup succuessfully
@retval EFI_NOT_FOUND cannot find the unsigned FV region
@retval EFI_BUFFER_TOO_SMALL cannot allocate enough memory to use
**/
EFI_STATUS
BackupSkipRegion (
IN UINT8 *ImageAddress,
IN UINTN ImageSize,
OUT UINTN *SkipRegionOffset,
OUT UINTN *SkipRegionSize,
OUT UINT8 **SkipRegionDataBuffer
)
{
EFI_STATUS Status;
UINTN Index;
UINTN Index2;
UINT8 *BiosImgAddress;
UINTN BiosImgOffset;
EFI_FIRMWARE_VOLUME_HEADER *FvHeaderPtr;
EFI_FFS_FILE_HEADER *FileHeaderPtr;
UINT32 FileLength;
BOOLEAN FileGuidFound;
UINT8 *SkipRegionAddress;
FvHeaderPtr = NULL;
FileHeaderPtr = NULL;
BiosImgOffset = 0;
FileLength = 0;
FileGuidFound = FALSE;
BiosImgAddress = ImageAddress;
Status = RetrieveFirmware (&BiosImgAddress, ImageSize, &BiosImgOffset);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Find the skip region from the image, preserve it before modifying it.
//
for (Index = 0; Index < (ImageSize - BiosImgOffset); Index += ALIGHMENT_SIZE) {
FvHeaderPtr = (EFI_FIRMWARE_VOLUME_HEADER *)(BiosImgAddress + Index);
if ((FvHeaderPtr->Signature == EFI_FVH_SIGNATURE) &&
(CompareGuid (&FvHeaderPtr->FileSystemGuid, &gEfiFirmwareFileSystem2Guid))) {
Index2 = 0;
while (Index2 < FvHeaderPtr->FvLength) {
FileHeaderPtr = (EFI_FFS_FILE_HEADER *)(BiosImgAddress + Index + FvHeaderPtr->HeaderLength + Index2);
if (!VerifyHeaderChecksum (FileHeaderPtr)) {
break;
}
if (CompareGuid (PcdGetPtr (PcdUnsignedFvKeyFile), &FileHeaderPtr->Name) == TRUE) {
FileGuidFound = TRUE;
break;
} else {
if (IS_FFS_FILE2 (FileHeaderPtr)) {
FileLength = FFS_FILE2_SIZE (FileHeaderPtr);
} else {
FileLength = FFS_FILE_SIZE (FileHeaderPtr);
}
FileLength = ALIGN_VALUE (FileLength, 8);
Index2 += FileLength;
}
}
}
if (FileGuidFound) {
break;
}
}
if (!FileGuidFound) {
return EFI_NOT_FOUND;
}
SkipRegionAddress = (UINT8 *)FvHeaderPtr;
*SkipRegionOffset = Index;
*SkipRegionSize = (UINTN)(FvHeaderPtr->FvLength);
*SkipRegionDataBuffer = AllocatePool (*SkipRegionSize);
if (*SkipRegionDataBuffer == NULL) {
return EFI_BUFFER_TOO_SMALL;
}
CopyMem (*SkipRegionDataBuffer, SkipRegionAddress, *SkipRegionSize);
SetMem (SkipRegionAddress, *SkipRegionSize, 0xFF);
return EFI_SUCCESS;
}
/**
Restore the data of the unsigned FV region.
@param [in] ImageAddress the image address
@param [in] ImageSize the size of the image
@param [in] SkipRegionOffset the offset of the unsigned FV region from the image
@param [in] SkipRegionSize the size of the unsigned FV region
@param [in] SkipRegionDataBuffer the pointer of the backup buffer
@retval EFI_SUCCESS backup succuessfully
@retval EFI_NOT_FOUND cannot find the BIOS address from the image
**/
EFI_STATUS
RestoreSkipRegion (
IN UINT8 *ImageAddress,
IN UINTN ImageSize,
IN UINTN SkipRegionOffset,
IN UINTN SkipRegionSize,
IN UINT8 *SkipRegionDataBuffer
)
{
EFI_STATUS Status;
UINTN BiosImgOffset;
UINT8 *BiosImgAddress;
BiosImgOffset = 0;
BiosImgAddress = ImageAddress;
if ((ImageAddress != NULL) && (SkipRegionDataBuffer != NULL)) {
Status = RetrieveFirmware (&BiosImgAddress, ImageSize, &BiosImgOffset);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
CopyMem (BiosImgAddress + SkipRegionOffset, SkipRegionDataBuffer, SkipRegionSize);
FreePool (SkipRegionDataBuffer);
}
return EFI_SUCCESS;
}