mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-31 01:24:12 +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>
1776 lines
36 KiB
C
1776 lines
36 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
|
|
//
|
|
|
|
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 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 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 (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;
|
|
}
|
|
|
|
|
|
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 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 =
|
|
FvBufBtCalculateChecksum16 (
|
|
(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 (CommonLibBinderBtCompareGuid (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
|
|
FvBufBtCalculateSum16 (
|
|
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
|
|
FvBufBtCalculateChecksum16 (
|
|
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 - FvBufBtCalculateSum16 (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));
|
|
}
|
|
|
|
|