mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
BaseTools has been duplicating and adapting code that is defined in MdePkg and MdeModulePkg. This leads to desync issues where the same symbols may be backed by different functions with slightly different semantics and also fixes that apply only to BaseTools or only to MdePkg and MdeModulePkg. To address these issues, update BaseTools/Source/C to utilize the code from MdePkg and MdeModulePkg. Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
1519 lines
35 KiB
C
1519 lines
35 KiB
C
/** @file
|
|
EFI Firmware Volume routines which work on a Fv image in buffers.
|
|
|
|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
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
|
|
FvBufBtCalculateChecksum16 (
|
|
IN UINT16 *Buffer,
|
|
IN UINTN Size
|
|
);
|
|
|
|
STATIC
|
|
UINT8
|
|
FvBufCalculateChecksum8 (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Size
|
|
);
|
|
|
|
//
|
|
// Procedures start
|
|
//
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param SourceFv Address of the Fv in memory, this firmware volume will
|
|
be modified, if SourceFfsFile exists
|
|
@param SourceFfsFile Input FFS file to replace
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
**/
|
|
EFI_STATUS
|
|
FvBufRemoveFileNew (
|
|
IN OUT VOID *Fv,
|
|
IN EFI_GUID *Name
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param SourceFv Address of the Fv in memory, this firmware volume will
|
|
be modified, if SourceFfsFile exists
|
|
@param SourceFfsFile Input FFS file to replace
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
**/
|
|
EFI_STATUS
|
|
FvBufRemoveFile (
|
|
IN OUT VOID *Fv,
|
|
IN EFI_GUID *Name
|
|
)
|
|
{
|
|
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 (CommonLibBinderBtCompareGuid (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;
|
|
}
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param SourceFfsFile Input FFS file to update the checksum for
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
**/
|
|
EFI_STATUS
|
|
FvBufChecksumFile (
|
|
IN OUT VOID *FfsFile
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param SourceFv Address of the Fv in memory, this firmware volume will
|
|
be modified, if SourceFfsFile exists
|
|
@param SourceFfsFile Input FFS file to replace
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
**/
|
|
EFI_STATUS
|
|
FvBufChecksumHeader (
|
|
IN OUT VOID *Fv
|
|
)
|
|
{
|
|
EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
|
|
|
|
FvHeader->Checksum = 0;
|
|
FvHeader->Checksum =
|
|
FvBufBtCalculateChecksum16 (
|
|
(UINT16*) FvHeader,
|
|
FvHeader->HeaderLength / sizeof (UINT16)
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param SourceFv - Address of the Fv in memory
|
|
@param DestinationFv - Output for destination Fv
|
|
DestinationFv == NULL - invalid parameter
|
|
*DestinationFv == NULL - memory will be allocated
|
|
*DestinationFv != NULL - this address will be the destination
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufDuplicate (
|
|
IN VOID *SourceFv,
|
|
IN OUT VOID **DestinationFv
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@param Fv Source and destination firmware volume.
|
|
Note: The original firmware volume buffer is freed!
|
|
|
|
@param Size The minimum size that the firmware volume is to be extended by.
|
|
The FV may be extended more than this size.
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufExtend (
|
|
IN VOID **Fv,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
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;
|
|
|
|
}
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param Fv Address of the Fv in memory
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufClearAllFiles (
|
|
IN OUT VOID *Fv
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Clears out all files from the Fv buffer in memory
|
|
|
|
@param Fv Address of the Fv in memory
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufGetSize (
|
|
IN VOID *Fv,
|
|
OUT UINTN *Size
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Adds a new FFS file
|
|
|
|
@param Fv Address of the Fv in memory
|
|
@param File FFS file to add to Fv
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufAddFile (
|
|
IN OUT VOID *Fv,
|
|
IN VOID *File
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Adds a new FFS file. Extends the firmware volume if needed.
|
|
|
|
@param Fv Source and destination firmware volume.
|
|
Note: If the FV is extended, then the original firmware volume
|
|
buffer is freed!
|
|
|
|
@param Size The minimum size that the firmware volume is to be extended by.
|
|
The FV may be extended more than this size.
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufAddFileWithExtend (
|
|
IN OUT VOID **Fv,
|
|
IN VOID *File
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Adds a new FFS VFT (Volume Top File) file. In other words, adds the
|
|
file to the end of the firmware volume.
|
|
|
|
@param Fv Address of the Fv in memory
|
|
@param File FFS file to add to Fv
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufAddVtfFile (
|
|
IN OUT VOID *Fv,
|
|
IN VOID *File
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Expands the 3 byte size commonly used in Firmware Volume data structures
|
|
|
|
@param Size Address of the 3 byte array representing the size
|
|
|
|
@return UINT32
|
|
**/
|
|
VOID
|
|
FvBufCompact3ByteSize (
|
|
OUT VOID* SizeDest,
|
|
IN UINT32 Size
|
|
)
|
|
{
|
|
((UINT8*)SizeDest)[0] = (UINT8)Size;
|
|
((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8);
|
|
((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16);
|
|
}
|
|
|
|
/**
|
|
Get the FFS file size.
|
|
|
|
@param Ffs Pointer to FFS header
|
|
|
|
@return UINT32
|
|
**/
|
|
UINT32
|
|
FvBufGetFfsFileSize (
|
|
IN EFI_FFS_FILE_HEADER *Ffs
|
|
)
|
|
{
|
|
if (Ffs == NULL) {
|
|
return 0;
|
|
}
|
|
if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) {
|
|
return (UINT32) ((EFI_FFS_FILE_HEADER2 *)Ffs)->ExtendedSize;
|
|
}
|
|
return FvBufExpand3ByteSize(Ffs->Size);
|
|
}
|
|
|
|
/**
|
|
Get the FFS header size.
|
|
|
|
@param Ffs Pointer to FFS header
|
|
|
|
@return UINT32
|
|
**/
|
|
UINT32
|
|
FvBufGetFfsHeaderSize (
|
|
IN EFI_FFS_FILE_HEADER *Ffs
|
|
)
|
|
{
|
|
if (Ffs == NULL) {
|
|
return 0;
|
|
}
|
|
if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) {
|
|
return sizeof(EFI_FFS_FILE_HEADER2);
|
|
}
|
|
return sizeof(EFI_FFS_FILE_HEADER);
|
|
}
|
|
|
|
/**
|
|
Expands the 3 byte size commonly used in Firmware Volume data structures
|
|
|
|
@param Size Address of the 3 byte array representing the size
|
|
|
|
@return UINT32
|
|
**/
|
|
UINT32
|
|
FvBufExpand3ByteSize (
|
|
IN VOID* Size
|
|
)
|
|
{
|
|
return (((UINT8*)Size)[2] << 16) +
|
|
(((UINT8*)Size)[1] << 8) +
|
|
((UINT8*)Size)[0];
|
|
}
|
|
|
|
/**
|
|
Iterates through the files contained within the firmware volume
|
|
|
|
@param Fv Address of the Fv in memory
|
|
@param 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.
|
|
@param File Output file pointer
|
|
File == NULL - invalid parameter
|
|
otherwise - *File will be update to the location of the file
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufFindNextFile (
|
|
IN VOID *Fv,
|
|
IN OUT UINTN *Key,
|
|
OUT VOID **File
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Searches the Fv for a file by its name
|
|
|
|
@param Fv Address of the Fv in memory
|
|
@param Name Guid filename to search for in the firmware volume
|
|
@param 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
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufFindFileByName (
|
|
IN VOID *Fv,
|
|
IN EFI_GUID *Name,
|
|
OUT VOID **File
|
|
)
|
|
{
|
|
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 (CommonLibBinderBtCompareGuid (Name, &NextFile->Name)) {
|
|
if (File != NULL) {
|
|
*File = NextFile;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Searches the Fv for a file by its type
|
|
|
|
@param Fv Address of the Fv in memory
|
|
@param Type FFS FILE type to search for
|
|
@param 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
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufFindFileByType (
|
|
IN VOID *Fv,
|
|
IN EFI_FV_FILETYPE Type,
|
|
OUT VOID **File
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@param FfsFile Address of the FFS file in memory
|
|
@param RawData Pointer to the raw data within the file
|
|
(This is NOT allocated. It is within the file.)
|
|
@param RawDataSize Size of the raw data within the file
|
|
|
|
@return EFI_STATUS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufGetFileRawData (
|
|
IN VOID* FfsFile,
|
|
OUT VOID** RawData,
|
|
OUT UINTN* RawDataSize
|
|
)
|
|
{
|
|
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;
|
|
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@param RawData Pointer to the raw data to be packed
|
|
@param RawDataSize Size of the raw data to be packed
|
|
@param FfsFile Address of the packaged FFS file.
|
|
Note: The called must deallocate this memory!
|
|
|
|
@return EFI_STATUS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufPackageFreeformRawFile (
|
|
IN EFI_GUID* Filename,
|
|
IN VOID* RawData,
|
|
IN UINTN RawDataSize,
|
|
OUT VOID** FfsFile
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Iterates through the sections contained within a given array of sections
|
|
|
|
@param SectionsStart Address of the start of the FFS sections array
|
|
@param TotalSectionsSize Total size of all the sections
|
|
@param 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.
|
|
@param Section Output section pointer
|
|
(Section == NULL) -> invalid parameter
|
|
otherwise -> *Section will be update to the location of the file
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufFindNextSection (
|
|
IN VOID *SectionsStart,
|
|
IN UINTN TotalSectionsSize,
|
|
IN OUT UINTN *Key,
|
|
OUT VOID **Section
|
|
)
|
|
{
|
|
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;
|
|
|
|
}
|
|
|
|
/**
|
|
Searches the FFS file and counts the number of sections found.
|
|
The sections are NOT recursed.
|
|
|
|
@param FfsFile Address of the FFS file in memory
|
|
@param Count The location to store the section count in
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufCountSections (
|
|
IN VOID* FfsFile,
|
|
IN UINTN* Count
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Searches the FFS file for a section by its type
|
|
|
|
@param FfsFile Address of the FFS file in memory
|
|
@param Type FFS FILE section type to search for
|
|
@param 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
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufFindSectionByType (
|
|
IN VOID *FfsFile,
|
|
IN UINT8 Type,
|
|
OUT VOID **Section
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@param Fv Firmware volume.
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
FvBufShrinkWrap (
|
|
IN VOID *Fv
|
|
)
|
|
{
|
|
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;
|
|
|
|
}
|
|
|
|
/**
|
|
Searches the FFS file for a section by its type
|
|
|
|
@param Fv Address of the Fv in memory
|
|
@param 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.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_NOT_FOUND
|
|
@retval EFI_VOLUME_CORRUPTED
|
|
**/
|
|
EFI_STATUS
|
|
FvBufUnifyBlockSizes (
|
|
IN OUT VOID *Fv,
|
|
IN UINTN BlockSize
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
This function calculates the UINT16 sum for the requested region.
|
|
|
|
@param Buffer Pointer to buffer containing byte data of component.
|
|
@param Size Size of the buffer
|
|
|
|
@return The 16 bit checksum
|
|
**/
|
|
STATIC
|
|
UINT16
|
|
FvBufBtCalculateSum16 (
|
|
IN UINT16 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
This function calculates the value needed for a valid UINT16 checksum
|
|
|
|
@param Buffer Pointer to buffer containing byte data of component.
|
|
@param Size Size of the buffer
|
|
|
|
@return The 16 bit checksum value needed.
|
|
**/
|
|
STATIC
|
|
UINT16
|
|
FvBufBtCalculateChecksum16 (
|
|
IN UINT16 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
return (UINT16)(0x10000 - FvBufBtCalculateSum16 (Buffer, Size));
|
|
}
|
|
|
|
/**
|
|
This function calculates the UINT8 sum for the requested region.
|
|
|
|
@param Buffer Pointer to buffer containing byte data of component.
|
|
@param Size Size of the buffer
|
|
|
|
@return The 8 bit checksum value needed.
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
FvBufCalculateSum8 (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
This function calculates the value needed for a valid UINT8 checksum
|
|
|
|
@param Buffer Pointer to buffer containing byte data of component.
|
|
@param Size Size of the buffer
|
|
|
|
@return The 8 bit checksum value needed.
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
FvBufCalculateChecksum8 (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size));
|
|
}
|
|
|
|
|