From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Source/C/Common/FirmwareVolumeBuffer.c | 1775 ++++++++++++++++++++ 1 file changed, 1775 insertions(+) create mode 100644 roms/edk2/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c (limited to 'roms/edk2/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c') diff --git a/roms/edk2/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c b/roms/edk2/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c new file mode 100644 index 000000000..70741c8af --- /dev/null +++ b/roms/edk2/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c @@ -0,0 +1,1775 @@ +/** @file +EFI Firmware Volume routines which work on a Fv image in buffers. + +Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FirmwareVolumeBufferLib.h" +#include "BinderFuncs.h" + +// +// Local macros +// +#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \ + ( \ + (BOOLEAN) ( \ + (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \ + ) \ + ) + + +// +// Local prototypes +// + +STATIC +UINT32 +FvBufGetSecHdrLen( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + if (SectionHeader == NULL) { + return 0; + } + if (FvBufExpand3ByteSize(SectionHeader->Size) == 0xffffff) { + return sizeof(EFI_COMMON_SECTION_HEADER2); + } + return sizeof(EFI_COMMON_SECTION_HEADER); +} + +STATIC +UINT32 +FvBufGetSecFileLen ( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + UINT32 Length; + if (SectionHeader == NULL) { + return 0; + } + Length = FvBufExpand3ByteSize(SectionHeader->Size); + if (Length == 0xffffff) { + Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize; + } + return Length; +} + +// +// Local prototypes +// + +STATIC +UINT16 +FvBufCalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ); + +STATIC +UINT8 +FvBufCalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ); + +// +// Procedures start +// + +EFI_STATUS +FvBufRemoveFileNew ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + SourceFv - Address of the Fv in memory, this firmware volume volume will + be modified, if SourceFfsFile exists + SourceFfsFile - Input FFS file to replace + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* FileToRm; + UINTN FileToRmLength; + + Status = FvBufFindFileByName( + Fv, + Name, + (VOID **)&FileToRm + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FileToRmLength = FvBufGetFfsFileSize (FileToRm); + + CommonLibBinderSetMem ( + FileToRm, + FileToRmLength, + (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) + ? 0xFF : 0 + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufRemoveFile ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + SourceFv - Address of the Fv in memory, this firmware volume volume will + be modified, if SourceFfsFile exists + SourceFfsFile - Input FFS file to replace + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *NextFile; + EFI_FIRMWARE_VOLUME_HEADER *TempFv; + UINTN FileKey; + UINTN FvLength; + + Status = FvBufFindFileByName( + Fv, + Name, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufGetSize (Fv, &FvLength); + if (EFI_ERROR (Status)) { + return Status; + } + + TempFv = NULL; + Status = FvBufDuplicate (Fv, (VOID **)&TempFv); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufClearAllFiles (TempFv); + if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + + // TempFv has been allocated. It must now be freed + // before returning. + + FileKey = 0; + while (TRUE) { + + Status = FvBufFindNextFile (Fv, &FileKey, (VOID **)&NextFile); + if (Status == EFI_NOT_FOUND) { + break; + } else if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + + if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) { + continue; + } + else { + Status = FvBufAddFile (TempFv, NextFile); + if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + } + } + + CommonLibBinderCopyMem (Fv, TempFv, FvLength); + CommonLibBinderFree (TempFv); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufChecksumFile ( + IN OUT VOID *FfsFile + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + SourceFfsFile - Input FFS file to update the checksum for + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile; + EFI_FFS_FILE_STATE StateBackup; + UINT32 FileSize; + + FileSize = FvBufGetFfsFileSize (File); + + // + // Fill in checksums and state, they must be 0 for checksumming. + // + File->IntegrityCheck.Checksum.Header = 0; + File->IntegrityCheck.Checksum.File = 0; + StateBackup = File->State; + File->State = 0; + + File->IntegrityCheck.Checksum.Header = + FvBufCalculateChecksum8 ( + (UINT8 *) File, + FvBufGetFfsHeaderSize (File) + ); + + if (File->Attributes & FFS_ATTRIB_CHECKSUM) { + File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 ( + (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)), + FileSize - FvBufGetFfsHeaderSize (File) + ); + } else { + File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + File->State = StateBackup; + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufChecksumHeader ( + IN OUT VOID *Fv + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + SourceFv - Address of the Fv in memory, this firmware volume volume will + be modified, if SourceFfsFile exists + SourceFfsFile - Input FFS file to replace + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + FvHeader->Checksum = 0; + FvHeader->Checksum = + FvBufCalculateChecksum16 ( + (UINT16*) FvHeader, + FvHeader->HeaderLength / sizeof (UINT16) + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufDuplicate ( + IN VOID *SourceFv, + IN OUT VOID **DestinationFv + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + SourceFv - Address of the Fv in memory + DestinationFv - Output for destination Fv + DestinationFv == NULL - invalid parameter + *DestinationFv == NULL - memory will be allocated + *DestinationFv != NULL - this address will be the destination + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + UINTN size; + + if (DestinationFv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (SourceFv, &size); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*DestinationFv == NULL) { + *DestinationFv = CommonLibBinderAllocate (size); + if (*DestinationFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + CommonLibBinderCopyMem (*DestinationFv, SourceFv, size); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufExtend ( + IN VOID **Fv, + IN UINTN Size + ) +/*++ + +Routine Description: + + Extends a firmware volume by the given number of bytes. + + BUGBUG: Does not handle the case where the firmware volume has a + VTF (Volume Top File). The VTF will not be moved to the + end of the extended FV. + +Arguments: + + Fv - Source and destination firmware volume. + Note: The original firmware volume buffer is freed! + + Size - The minimum size that the firmware volume is to be extended by. + The FV may be extended more than this size. + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + UINTN OldSize; + UINTN NewSize; + UINTN BlockCount; + VOID* NewFv; + + EFI_FIRMWARE_VOLUME_HEADER* hdr; + EFI_FV_BLOCK_MAP_ENTRY* blk; + + Status = FvBufGetSize (*Fv, &OldSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Locate the block map in the fv header + // + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv; + blk = hdr->BlockMap; + + // + // Calculate the number of blocks needed to achieve the requested + // size extension + // + BlockCount = ((Size + (blk->Length - 1)) / blk->Length); + + // + // Calculate the new size from the number of blocks that will be added + // + NewSize = OldSize + (BlockCount * blk->Length); + + NewFv = CommonLibBinderAllocate (NewSize); + if (NewFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the old data + // + CommonLibBinderCopyMem (NewFv, *Fv, OldSize); + + // + // Free the old fv buffer + // + CommonLibBinderFree (*Fv); + + // + // Locate the block map in the new fv header + // + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv; + hdr->FvLength = NewSize; + blk = hdr->BlockMap; + + // + // Update the block map for the new fv + // + blk->NumBlocks += (UINT32)BlockCount; + + // + // Update the FV header checksum + // + FvBufChecksumHeader (NewFv); + + // + // Clear out the new area of the FV + // + CommonLibBinderSetMem ( + (UINT8*)NewFv + OldSize, + (NewSize - OldSize), + (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0 + ); + + // + // Set output with new fv that was created + // + *Fv = NewFv; + + return EFI_SUCCESS; + +} + + +EFI_STATUS +FvBufClearAllFiles ( + IN OUT VOID *Fv + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + Fv - Address of the Fv in memory + +Returns: + + EFI_SUCCESS + +--*/ + +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_STATUS Status; + UINTN size = 0; + + Status = FvBufGetSize (Fv, &size); + if (EFI_ERROR (Status)) { + return Status; + } + + CommonLibBinderSetMem( + (UINT8*)hdr + hdr->HeaderLength, + size - hdr->HeaderLength, + (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0 + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufGetSize ( + IN VOID *Fv, + OUT UINTN *Size + ) +/*++ + +Routine Description: + + Clears out all files from the Fv buffer in memory + +Arguments: + + Fv - Address of the Fv in memory + +Returns: + + EFI_SUCCESS + +--*/ + +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap; + + *Size = 0; + + while (blk->Length != 0 || blk->NumBlocks != 0) { + *Size = *Size + (blk->Length * blk->NumBlocks); + if (*Size >= 0x40000000) { + // If size is greater than 1GB, then assume it is corrupted + return EFI_VOLUME_CORRUPTED; + } + blk++; + } + + if (*Size == 0) { + // If size is 0, then assume the volume is corrupted + return EFI_VOLUME_CORRUPTED; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufAddFile ( + IN OUT VOID *Fv, + IN VOID *File + ) +/*++ + +Routine Description: + + Adds a new FFS file + +Arguments: + + Fv - Address of the Fv in memory + File - FFS file to add to Fv + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER *fhdr = NULL; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN offset; + UINTN fsize; + UINTN newSize; + UINTN clearLoop; + + EFI_STATUS Status; + UINTN fvSize; + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + FvbAttributes = hdr->Attributes; + newSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + + for( + offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8); + offset + newSize <= fvSize; + offset = (UINTN)ALIGN_POINTER (offset, 8) + ) { + + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset); + + if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) + ) { + // BUGBUG: Need to make sure that the new file does not already + // exist. + + fsize = FvBufGetFfsFileSize (fhdr); + if (fsize == 0 || (offset + fsize > fvSize)) { + return EFI_VOLUME_CORRUPTED; + } + + offset = offset + fsize; + continue; + } + + clearLoop = 0; + while ((clearLoop < newSize) && + (((UINT8*)fhdr)[clearLoop] == + (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0) + ) + ) { + clearLoop++; + } + + // + // We found a place in the FV which is empty and big enough for + // the new file + // + if (clearLoop >= newSize) { + break; + } + + offset = offset + 1; // Make some forward progress + } + + if (offset + newSize > fvSize) { + return EFI_OUT_OF_RESOURCES; + } + + CommonLibBinderCopyMem (fhdr, File, newSize); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufAddFileWithExtend ( + IN OUT VOID **Fv, + IN VOID *File + ) +/*++ + +Routine Description: + + Adds a new FFS file. Extends the firmware volume if needed. + +Arguments: + + Fv - Source and destination firmware volume. + Note: If the FV is extended, then the original firmware volume + buffer is freed! + + Size - The minimum size that the firmware volume is to be extended by. + The FV may be extended more than this size. + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* NewFile; + + NewFile = (EFI_FFS_FILE_HEADER*)File; + + // + // Try to add to the capsule volume + // + Status = FvBufAddFile (*Fv, NewFile); + if (Status == EFI_OUT_OF_RESOURCES) { + // + // Try to extend the capsule volume by the size of the file + // + Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size)); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now, try to add the file again + // + Status = FvBufAddFile (*Fv, NewFile); + } + + return Status; +} + + +EFI_STATUS +FvBufAddVtfFile ( + IN OUT VOID *Fv, + IN VOID *File + ) +/*++ + +Routine Description: + + Adds a new FFS VFT (Volume Top File) file. In other words, adds the + file to the end of the firmware volume. + +Arguments: + + Fv - Address of the Fv in memory + File - FFS file to add to Fv + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER* NewFile; + UINTN NewFileSize; + + UINT8 erasedUint8; + UINTN clearLoop; + + EFI_FFS_FILE_HEADER *LastFile; + UINTN LastFileSize; + + UINTN fvSize; + UINTN Key; + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0); + NewFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + + if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) { + return EFI_INVALID_PARAMETER; + } + + // + // Find the last file in the FV + // + Key = 0; + LastFile = NULL; + LastFileSize = 0; + do { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&LastFile); + LastFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + } while (!EFI_ERROR (Status)); + + // + // If no files were found, then we start at the beginning of the FV + // + if (LastFile == NULL) { + LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength); + } + + // + // We want to put the new file (VTF) at the end of the FV + // + NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize)); + + // + // Check to see if there is enough room for the VTF after the last file + // found in the FV + // + if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Loop to determine if the end of the FV is empty + // + clearLoop = 0; + while ((clearLoop < NewFileSize) && + (((UINT8*)NewFile)[clearLoop] == erasedUint8) + ) { + clearLoop++; + } + + // + // Check to see if there was not enough room for the file + // + if (clearLoop < NewFileSize) { + return EFI_OUT_OF_RESOURCES; + } + + CommonLibBinderCopyMem (NewFile, File, NewFileSize); + + return EFI_SUCCESS; +} + + +VOID +FvBufCompact3ByteSize ( + OUT VOID* SizeDest, + IN UINT32 Size + ) +/*++ + +Routine Description: + + Expands the 3 byte size commonly used in Firmware Volume data structures + +Arguments: + + Size - Address of the 3 byte array representing the size + +Returns: + + UINT32 + +--*/ +{ + ((UINT8*)SizeDest)[0] = (UINT8)Size; + ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8); + ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16); +} + +UINT32 +FvBufGetFfsFileSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ) +/*++ + +Routine Description: + + Get the FFS file size. + +Arguments: + + Ffs - Pointer to FFS header + +Returns: + + UINT32 + +--*/ +{ + if (Ffs == NULL) { + return 0; + } + if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) { + return (UINT32) ((EFI_FFS_FILE_HEADER2 *)Ffs)->ExtendedSize; + } + return FvBufExpand3ByteSize(Ffs->Size); +} + +UINT32 +FvBufGetFfsHeaderSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ) +/*++ + +Routine Description: + + Get the FFS header size. + +Arguments: + + Ffs - Pointer to FFS header + +Returns: + + UINT32 + +--*/ +{ + if (Ffs == NULL) { + return 0; + } + if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) { + return sizeof(EFI_FFS_FILE_HEADER2); + } + return sizeof(EFI_FFS_FILE_HEADER); +} + +UINT32 +FvBufExpand3ByteSize ( + IN VOID* Size + ) +/*++ + +Routine Description: + + Expands the 3 byte size commonly used in Firmware Volume data structures + +Arguments: + + Size - Address of the 3 byte array representing the size + +Returns: + + UINT32 + +--*/ +{ + return (((UINT8*)Size)[2] << 16) + + (((UINT8*)Size)[1] << 8) + + ((UINT8*)Size)[0]; +} + +EFI_STATUS +FvBufFindNextFile ( + IN VOID *Fv, + IN OUT UINTN *Key, + OUT VOID **File + ) +/*++ + +Routine Description: + + Iterates through the files contained within the firmware volume + +Arguments: + + Fv - Address of the Fv in memory + Key - Should be 0 to get the first file. After that, it should be + passed back in without modifying its contents to retrieve + subsequent files. + File - Output file pointer + File == NULL - invalid parameter + otherwise - *File will be update to the location of the file + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER *fhdr = NULL; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN fsize; + + EFI_STATUS Status; + UINTN fvSize; + + if (Fv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*Key == 0) { + *Key = hdr->HeaderLength; + } + + FvbAttributes = hdr->Attributes; + + for( + *Key = (UINTN)ALIGN_POINTER (*Key, 8); + (*Key + sizeof (*fhdr)) < fvSize; + *Key = (UINTN)ALIGN_POINTER (*Key, 8) + ) { + + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key); + fsize = FvBufGetFfsFileSize (fhdr); + + if (!EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_INVALID + ) + ) { + *Key = *Key + 1; // Make some forward progress + continue; + } else if( + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_MARKED_FOR_UPDATE + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DELETED + ) + ) { + *Key = *Key + fsize; + continue; + } else if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DATA_VALID + ) + ) { + *File = (UINT8*)hdr + *Key; + *Key = *Key + fsize; + return EFI_SUCCESS; + } + + *Key = *Key + 1; // Make some forward progress + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +FvBufFindFileByName ( + IN VOID *Fv, + IN EFI_GUID *Name, + OUT VOID **File + ) +/*++ + +Routine Description: + + Searches the Fv for a file by its name + +Arguments: + + Fv - Address of the Fv in memory + Name - Guid filename to search for in the firmware volume + File - Output file pointer + File == NULL - Only determine if the file exists, based on return + value from the function call. + otherwise - *File will be update to the location of the file + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_STATUS Status; + UINTN Key; + EFI_FFS_FILE_HEADER *NextFile; + + Key = 0; + while (TRUE) { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) { + if (File != NULL) { + *File = NextFile; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +FvBufFindFileByType ( + IN VOID *Fv, + IN EFI_FV_FILETYPE Type, + OUT VOID **File + ) +/*++ + +Routine Description: + + Searches the Fv for a file by its type + +Arguments: + + Fv - Address of the Fv in memory + Type - FFS FILE type to search for + File - Output file pointer + (File == NULL) -> Only determine if the file exists, based on return + value from the function call. + otherwise -> *File will be update to the location of the file + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_STATUS Status; + UINTN Key; + EFI_FFS_FILE_HEADER *NextFile; + + Key = 0; + while (TRUE) { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Type == NextFile->Type) { + if (File != NULL) { + *File = NextFile; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +FvBufGetFileRawData ( + IN VOID* FfsFile, + OUT VOID** RawData, + OUT UINTN* RawDataSize + ) +/*++ + +Routine Description: + + Searches the requested file for raw data. + + This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file, + or finds the EFI_SECTION_RAW section within the file and returns its data. + +Arguments: + + FfsFile - Address of the FFS file in memory + RawData - Pointer to the raw data within the file + (This is NOT allocated. It is within the file.) + RawDataSize - Size of the raw data within the file + +Returns: + + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* File; + EFI_RAW_SECTION* Section; + + File = (EFI_FFS_FILE_HEADER*)FfsFile; + + // + // Is the file type == EFI_FV_FILETYPE_RAW? + // + if (File->Type == EFI_FV_FILETYPE_RAW) { + // + // Raw filetypes don't have sections, so we just return the raw data + // + *RawData = (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)); + *RawDataSize = FvBufGetFfsFileSize (File) - FvBufGetFfsHeaderSize (File); + return EFI_SUCCESS; + } + + // + // Within the file, we now need to find the EFI_SECTION_RAW section. + // + Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, (VOID **)&Section); + if (EFI_ERROR (Status)) { + return Status; + } + + *RawData = (VOID*)((UINT8 *)Section + FvBufGetSecHdrLen(Section)); + *RawDataSize = + FvBufGetSecFileLen (Section) - FvBufGetSecHdrLen(Section); + + return EFI_SUCCESS; + +} + + +EFI_STATUS +FvBufPackageFreeformRawFile ( + IN EFI_GUID* Filename, + IN VOID* RawData, + IN UINTN RawDataSize, + OUT VOID** FfsFile + ) +/*++ + +Routine Description: + + Packages up a FFS file containing the input raw data. + + The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will + contain one EFI_FV_FILETYPE_RAW section. + +Arguments: + + RawData - Pointer to the raw data to be packed + RawDataSize - Size of the raw data to be packed + FfsFile - Address of the packaged FFS file. + Note: The called must deallocate this memory! + +Returns: + + EFI_STATUS + +--*/ +{ + EFI_FFS_FILE_HEADER* NewFile; + UINT32 NewFileSize; + EFI_RAW_SECTION* NewSection; + UINT32 NewSectionSize; + UINT32 FfsHdrLen; + UINT32 SecHdrLen; + + // + // The section size is the DataSize + the size of the section header + // + NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize; + SecHdrLen = sizeof (EFI_RAW_SECTION); + if (NewSectionSize >= MAX_SECTION_SIZE) { + NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION2) + (UINT32)RawDataSize; + SecHdrLen = sizeof (EFI_RAW_SECTION2); + } + + // + // The file size is the size of the file header + the section size + // + NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize; + FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER); + if (NewFileSize >= MAX_FFS_SIZE) { + NewFileSize = sizeof (EFI_FFS_FILE_HEADER2) + NewSectionSize; + FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER2); + } + + // + // Try to allocate a buffer to build the new FFS file in + // + NewFile = CommonLibBinderAllocate (NewFileSize); + if (NewFile == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CommonLibBinderSetMem (NewFile, NewFileSize, 0); + + // + // The NewSection follow right after the FFS file header + // + NewSection = (EFI_RAW_SECTION*)((UINT8*)NewFile + FfsHdrLen); + if (NewSectionSize >= MAX_SECTION_SIZE) { + FvBufCompact3ByteSize (NewSection->Size, 0xffffff); + ((EFI_RAW_SECTION2 *)NewSection)->ExtendedSize = NewSectionSize; + } else { + FvBufCompact3ByteSize (NewSection->Size, NewSectionSize); + } + NewSection->Type = EFI_SECTION_RAW; + + // + // Copy the actual file data into the buffer + // + CommonLibBinderCopyMem ((UINT8 *)NewSection + SecHdrLen, RawData, RawDataSize); + + // + // Initialize the FFS file header + // + CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID)); + NewFile->Attributes = 0; + if (NewFileSize >= MAX_FFS_SIZE) { + FvBufCompact3ByteSize (NewFile->Size, 0x0); + ((EFI_FFS_FILE_HEADER2 *)NewFile)->ExtendedSize = NewFileSize; + NewFile->Attributes |= FFS_ATTRIB_LARGE_FILE; + } else { + FvBufCompact3ByteSize (NewFile->Size, NewFileSize); + } + NewFile->Type = EFI_FV_FILETYPE_FREEFORM; + NewFile->IntegrityCheck.Checksum.Header = + FvBufCalculateChecksum8 ((UINT8*)NewFile, FfsHdrLen); + NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION | + EFI_FILE_HEADER_VALID | + EFI_FILE_DATA_VALID + ); + + *FfsFile = NewFile; + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvBufFindNextSection ( + IN VOID *SectionsStart, + IN UINTN TotalSectionsSize, + IN OUT UINTN *Key, + OUT VOID **Section + ) +/*++ + +Routine Description: + + Iterates through the sections contained within a given array of sections + +Arguments: + + SectionsStart - Address of the start of the FFS sections array + TotalSectionsSize - Total size of all the sections + Key - Should be 0 to get the first section. After that, it should be + passed back in without modifying its contents to retrieve + subsequent files. + Section - Output section pointer + (Section == NULL) -> invalid parameter + otherwise -> *Section will be update to the location of the file + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_COMMON_SECTION_HEADER *sectionHdr; + UINTN sectionSize; + + *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned + + if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) { + return EFI_NOT_FOUND; + } + + sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key); + sectionSize = FvBufGetSecFileLen (sectionHdr); + + if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) { + return EFI_NOT_FOUND; + } + + if ((*Key + sectionSize) > TotalSectionsSize) { + return EFI_NOT_FOUND; + } + + *Section = (UINT8*)sectionHdr; + *Key = *Key + sectionSize; + return EFI_SUCCESS; + +} + + +EFI_STATUS +FvBufCountSections ( + IN VOID* FfsFile, + IN UINTN* Count + ) +/*++ + +Routine Description: + + Searches the FFS file and counts the number of sections found. + The sections are NOT recursed. + +Arguments: + + FfsFile - Address of the FFS file in memory + Count - The location to store the section count in + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_STATUS Status; + UINTN Key; + VOID* SectionStart; + UINTN TotalSectionsSize; + EFI_COMMON_SECTION_HEADER* NextSection; + + SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile)); + TotalSectionsSize = + FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) - + FvBufGetFfsHeaderSize(FfsFile); + Key = 0; + *Count = 0; + while (TRUE) { + Status = FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&NextSection + ); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } else if (EFI_ERROR (Status)) { + return Status; + } + + // + // Increment the section counter + // + *Count += 1; + + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +FvBufFindSectionByType ( + IN VOID *FfsFile, + IN UINT8 Type, + OUT VOID **Section + ) +/*++ + +Routine Description: + + Searches the FFS file for a section by its type + +Arguments: + + FfsFile - Address of the FFS file in memory + Type - FFS FILE section type to search for + Section - Output section pointer + (Section == NULL) -> Only determine if the section exists, based on return + value from the function call. + otherwise -> *Section will be update to the location of the file + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_STATUS Status; + UINTN Key; + VOID* SectionStart; + UINTN TotalSectionsSize; + EFI_COMMON_SECTION_HEADER* NextSection; + + SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile)); + TotalSectionsSize = + FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) - + FvBufGetFfsHeaderSize(FfsFile); + Key = 0; + while (TRUE) { + Status = FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&NextSection + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Type == NextSection->Type) { + if (Section != NULL) { + *Section = NextSection; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +FvBufShrinkWrap ( + IN VOID *Fv + ) +/*++ + +Routine Description: + + Shrinks a firmware volume (in place) to provide a minimal FV. + + BUGBUG: Does not handle the case where the firmware volume has a + VTF (Volume Top File). The VTF will not be moved to the + end of the extended FV. + +Arguments: + + Fv - Firmware volume. + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + UINTN OldSize; + UINT32 BlockCount; + UINT32 NewBlockSize = 128; + UINTN Key; + EFI_FFS_FILE_HEADER* FileIt; + VOID* EndOfLastFile; + + EFI_FIRMWARE_VOLUME_HEADER* FvHdr; + + Status = FvBufGetSize (Fv, &OldSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufUnifyBlockSizes (Fv, NewBlockSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Locate the block map in the fv header + // + FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + // + // Find the end of the last file + // + Key = 0; + EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength; + while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, (VOID **)&FileIt))) { + EndOfLastFile = + (VOID*)((UINT8*)FileIt + FvBufGetFfsFileSize (FileIt)); + } + + // + // Set the BlockCount to have the minimal number of blocks for the Fv. + // + BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv); + BlockCount = BlockCount + NewBlockSize - 1; + BlockCount = BlockCount / NewBlockSize; + + // + // Adjust the block count to shrink the Fv in place. + // + FvHdr->BlockMap[0].NumBlocks = BlockCount; + FvHdr->FvLength = BlockCount * NewBlockSize; + + // + // Update the FV header checksum + // + FvBufChecksumHeader (Fv); + + return EFI_SUCCESS; + +} + + +EFI_STATUS +FvBufUnifyBlockSizes ( + IN OUT VOID *Fv, + IN UINTN BlockSize + ) +/*++ + +Routine Description: + + Searches the FFS file for a section by its type + +Arguments: + + Fv - Address of the Fv in memory + BlockSize - The size of the blocks to convert the Fv to. If the total size + of the Fv is not evenly divisible by this size, then + EFI_INVALID_PARAMETER will be returned. + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap; + UINT32 Size; + + Size = 0; + + // + // Scan through the block map list, performing error checking, and adding + // up the total Fv size. + // + while( blk->Length != 0 || + blk->NumBlocks != 0 + ) { + Size = Size + (blk->Length * blk->NumBlocks); + blk++; + if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) { + return EFI_VOLUME_CORRUPTED; + } + } + + // + // Make sure that the Fv size is a multiple of the new block size. + // + if ((Size % BlockSize) != 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Zero out the entire block map. + // + CommonLibBinderSetMem ( + &hdr->BlockMap, + (UINTN)blk - (UINTN)&hdr->BlockMap, + 0 + ); + + // + // Write out the single block map entry. + // + hdr->BlockMap[0].Length = (UINT32)BlockSize; + hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize; + + return EFI_SUCCESS; +} + +STATIC +UINT16 +FvBufCalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +/*++ + +Routine Description: + + This function calculates the UINT16 sum for the requested region. + +Arguments: + + Buffer Pointer to buffer containing byte data of component. + Size Size of the buffer + +Returns: + + The 16 bit checksum + +--*/ +{ + UINTN Index; + UINT16 Sum; + + Sum = 0; + + // + // Perform the word sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT16) (Sum + Buffer[Index]); + } + + return (UINT16) Sum; +} + + +STATIC +UINT16 +FvBufCalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +/*++ + +Routine Description:: + + This function calculates the value needed for a valid UINT16 checksum + +Arguments: + + Buffer Pointer to buffer containing byte data of component. + Size Size of the buffer + +Returns: + + The 16 bit checksum value needed. + +--*/ +{ + return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size)); +} + + +STATIC +UINT8 +FvBufCalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +/*++ + +Description: + + This function calculates the UINT8 sum for the requested region. + +Input: + + Buffer Pointer to buffer containing byte data of component. + Size Size of the buffer + +Return: + + The 8 bit checksum value needed. + +--*/ +{ + UINTN Index; + UINT8 Sum; + + Sum = 0; + + // + // Perform the byte sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT8) (Sum + Buffer[Index]); + } + + return Sum; +} + + +STATIC +UINT8 +FvBufCalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +/*++ + +Description: + + This function calculates the value needed for a valid UINT8 checksum + +Input: + + Buffer Pointer to buffer containing byte data of component. + Size Size of the buffer + +Return: + + The 8 bit checksum value needed. + +--*/ +{ + return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size)); +} + + -- cgit