mirror of https://github.com/acidanthera/audk.git
1033 lines
31 KiB
C
1033 lines
31 KiB
C
|
/** @file
|
||
|
Implements functions to pad firmware file.
|
||
|
|
||
|
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
|
||
|
|
||
|
This program and the accompanying materials
|
||
|
are licensed and made available under the terms and conditions
|
||
|
of the BSD License which accompanies this distribution. The
|
||
|
full text of the license may be found at
|
||
|
http://opensource.org/licenses/bsd-license.php
|
||
|
|
||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "FwVolDriver.h"
|
||
|
|
||
|
/**
|
||
|
Calculate the checksum for a PAD file.
|
||
|
|
||
|
@param PadFileHeader The Pad File to be caculeted the checksum.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
SetPadFileChecksum (
|
||
|
IN EFI_FFS_FILE_HEADER *PadFileHeader
|
||
|
)
|
||
|
{
|
||
|
UINT32 PadFileLength;
|
||
|
|
||
|
if ((PadFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
|
||
|
|
||
|
PadFileLength = *(UINT32 *) PadFileHeader->Size & 0x00FFFFFF;
|
||
|
|
||
|
//
|
||
|
// Calculate checksum of Pad File Data
|
||
|
//
|
||
|
PadFileHeader->IntegrityCheck.Checksum.File =
|
||
|
CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER), PadFileLength - sizeof (EFI_FFS_FILE_HEADER));
|
||
|
|
||
|
} else {
|
||
|
|
||
|
PadFileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
|
||
|
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Create a PAD File in the Free Space.
|
||
|
|
||
|
@param FvDevice Firmware Volume Device.
|
||
|
@param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.
|
||
|
@param Size Pad file Size, not include the header.
|
||
|
@param PadFileEntry The Ffs File Entry that points to this Pad File.
|
||
|
|
||
|
@retval EFI_SUCCESS Successfully create a PAD file.
|
||
|
@retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.
|
||
|
@retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.
|
||
|
@retval EFI_DEVICE_ERROR Free space is not erased.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
FvCreatePadFileInFreeSpace (
|
||
|
IN FV_DEVICE *FvDevice,
|
||
|
IN FREE_SPACE_ENTRY *FreeSpaceEntry,
|
||
|
IN UINTN Size,
|
||
|
OUT FFS_FILE_LIST_ENTRY **PadFileEntry
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_FFS_FILE_HEADER *PadFileHeader;
|
||
|
UINTN Offset;
|
||
|
UINTN NumBytesWritten;
|
||
|
UINTN StateOffset;
|
||
|
UINT8 *StartPos;
|
||
|
FFS_FILE_LIST_ENTRY *FfsFileEntry;
|
||
|
|
||
|
if (FreeSpaceEntry->Length < Size + sizeof (EFI_FFS_FILE_HEADER)) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if ((Size & 0x07) != 0) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
StartPos = FreeSpaceEntry->StartingAddress;
|
||
|
|
||
|
//
|
||
|
// First double check the space
|
||
|
//
|
||
|
if (!IsBufferErased (
|
||
|
FvDevice->ErasePolarity,
|
||
|
StartPos,
|
||
|
Size + sizeof (EFI_FFS_FILE_HEADER)
|
||
|
)) {
|
||
|
return EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos;
|
||
|
|
||
|
//
|
||
|
// Create File Step 1
|
||
|
//
|
||
|
SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;
|
||
|
|
||
|
NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
StateOffset,
|
||
|
&NumBytesWritten,
|
||
|
&PadFileHeader->State
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
|
||
|
return Status;
|
||
|
}
|
||
|
//
|
||
|
// Update Free Space Entry, since header is allocated
|
||
|
//
|
||
|
FreeSpaceEntry->Length -= sizeof (EFI_FFS_FILE_HEADER);
|
||
|
FreeSpaceEntry->StartingAddress += sizeof (EFI_FFS_FILE_HEADER);
|
||
|
|
||
|
//
|
||
|
// Fill File Name Guid, here we assign a NULL-GUID to Pad files
|
||
|
//
|
||
|
ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));
|
||
|
|
||
|
//
|
||
|
// Fill File Type, checksum(0), Attributes(0), Size
|
||
|
//
|
||
|
PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;
|
||
|
PadFileHeader->Attributes = 0;
|
||
|
*(UINT32 *) PadFileHeader->Size &= 0xFF000000;
|
||
|
*(UINT32 *) PadFileHeader->Size |= (Size + sizeof (EFI_FFS_FILE_HEADER));
|
||
|
|
||
|
SetHeaderChecksum (PadFileHeader);
|
||
|
SetPadFileChecksum (PadFileHeader);
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
|
||
|
NumBytesWritten = sizeof (EFI_FFS_FILE_HEADER);
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
Offset,
|
||
|
&NumBytesWritten,
|
||
|
(UINT8 *) PadFileHeader
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Step 2, then Mark header valid, since no data write,
|
||
|
// mark the data valid at the same time.
|
||
|
//
|
||
|
SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
|
||
|
SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;
|
||
|
|
||
|
NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
StateOffset,
|
||
|
&NumBytesWritten,
|
||
|
&PadFileHeader->State
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
|
||
|
SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
|
||
|
return Status;
|
||
|
}
|
||
|
//
|
||
|
// Update Free Space Entry, since header is allocated
|
||
|
//
|
||
|
FreeSpaceEntry->Length -= Size;
|
||
|
FreeSpaceEntry->StartingAddress += Size;
|
||
|
|
||
|
//
|
||
|
// If successfully, insert an FfsFileEntry at the end of ffs file list
|
||
|
//
|
||
|
FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
ASSERT (FfsFileEntry != NULL);
|
||
|
|
||
|
FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) StartPos;
|
||
|
InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
|
||
|
|
||
|
*PadFileEntry = FfsFileEntry;
|
||
|
FvDevice->CurrentFfsFile = FfsFileEntry;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Fill pad file header within firmware cache.
|
||
|
|
||
|
@param PadFileHeader The start of the Pad File Buffer.
|
||
|
@param PadFileLength The length of the pad file including the header.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
FvFillPadFile (
|
||
|
IN EFI_FFS_FILE_HEADER *PadFileHeader,
|
||
|
IN UINTN PadFileLength
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Fill File Name Guid, here we assign a NULL-GUID to Pad files
|
||
|
//
|
||
|
ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));
|
||
|
|
||
|
//
|
||
|
// Fill File Type, checksum(0), Attributes(0), Size
|
||
|
//
|
||
|
PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;
|
||
|
PadFileHeader->Attributes = 0;
|
||
|
*(UINT32 *) PadFileHeader->Size &= 0xFF000000;
|
||
|
*(UINT32 *) PadFileHeader->Size |= PadFileLength;
|
||
|
|
||
|
SetHeaderChecksum (PadFileHeader);
|
||
|
SetPadFileChecksum (PadFileHeader);
|
||
|
|
||
|
//
|
||
|
// Set File State to 0x00000111
|
||
|
//
|
||
|
SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
|
||
|
SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
|
||
|
SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Create entire FFS file.
|
||
|
|
||
|
@param FileHeader Starting Address of a Buffer that hold the FFS File image.
|
||
|
@param FfsFileBuffer The source buffer that contains the File Data.
|
||
|
@param BufferSize The length of FfsFileBuffer.
|
||
|
@param ActualFileSize Size of FFS file.
|
||
|
@param FileName The Guid of Ffs File.
|
||
|
@param FileType The type of the written Ffs File.
|
||
|
@param FileAttributes The attributes of the written Ffs File.
|
||
|
|
||
|
@retval EFI_INVALID_PARAMETER File type is not valid.
|
||
|
@retval EFI_SUCCESS FFS file is successfully created.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
FvFillFfsFile (
|
||
|
OUT EFI_FFS_FILE_HEADER *FileHeader,
|
||
|
IN UINT8 *FfsFileBuffer,
|
||
|
IN UINTN BufferSize,
|
||
|
IN UINTN ActualFileSize,
|
||
|
IN EFI_GUID *FileName,
|
||
|
IN EFI_FV_FILETYPE FileType,
|
||
|
IN EFI_FV_FILE_ATTRIBUTES FileAttributes
|
||
|
)
|
||
|
{
|
||
|
EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
|
||
|
EFI_FFS_FILE_HEADER *TmpFileHeader;
|
||
|
|
||
|
//
|
||
|
// File Type value 0x0E~0xE0 are reserved
|
||
|
//
|
||
|
if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
TmpFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
|
||
|
//
|
||
|
// First fill all fields ready in FfsFileBuffer
|
||
|
//
|
||
|
CopyGuid (&TmpFileHeader->Name, FileName);
|
||
|
TmpFileHeader->Type = FileType;
|
||
|
|
||
|
//
|
||
|
// Convert the FileAttributes to FFSFileAttributes
|
||
|
//
|
||
|
FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
|
||
|
|
||
|
TmpFileHeader->Attributes = TmpFileAttribute;
|
||
|
|
||
|
*(UINT32 *) TmpFileHeader->Size &= 0xFF000000;
|
||
|
*(UINT32 *) TmpFileHeader->Size |= ActualFileSize;
|
||
|
|
||
|
SetHeaderChecksum (TmpFileHeader);
|
||
|
SetFileChecksum (TmpFileHeader, ActualFileSize);
|
||
|
|
||
|
SetFileState (EFI_FILE_HEADER_CONSTRUCTION, TmpFileHeader);
|
||
|
SetFileState (EFI_FILE_HEADER_VALID, TmpFileHeader);
|
||
|
SetFileState (EFI_FILE_DATA_VALID, TmpFileHeader);
|
||
|
|
||
|
//
|
||
|
// Copy data from FfsFileBuffer to FileHeader(cache)
|
||
|
//
|
||
|
CopyMem (FileHeader, FfsFileBuffer, BufferSize);
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Fill some other extra space using 0xFF(Erase Value).
|
||
|
|
||
|
@param ErasePolarity Fv erase value.
|
||
|
@param FileHeader Point to the start of FFS File.
|
||
|
@param ExtraLength The pading length.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
FvAdjustFfsFile (
|
||
|
IN UINT8 ErasePolarity,
|
||
|
IN EFI_FFS_FILE_HEADER *FileHeader,
|
||
|
IN UINTN ExtraLength
|
||
|
)
|
||
|
{
|
||
|
UINTN FileLength;
|
||
|
UINT8 *Ptr;
|
||
|
UINT8 PadingByte;
|
||
|
|
||
|
FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;
|
||
|
Ptr = (UINT8 *) FileHeader + FileLength;
|
||
|
|
||
|
if (ErasePolarity == 0) {
|
||
|
PadingByte = 0;
|
||
|
} else {
|
||
|
PadingByte = 0xFF;
|
||
|
}
|
||
|
//
|
||
|
// Fill the non-used space with Padding Byte
|
||
|
//
|
||
|
SetMem (Ptr, ExtraLength, PadingByte);
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Free File List entry pointed by FileListHead.
|
||
|
|
||
|
@param FileListHeader FileListEntry Header.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
FreeFileList (
|
||
|
IN LIST_ENTRY *FileListHead
|
||
|
)
|
||
|
{
|
||
|
FFS_FILE_LIST_ENTRY *FfsFileEntry;
|
||
|
LIST_ENTRY *NextEntry;
|
||
|
|
||
|
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) (FileListHead->ForwardLink);
|
||
|
|
||
|
//
|
||
|
// Loop the whole list entry to free resources
|
||
|
//
|
||
|
while (&FfsFileEntry->Link != FileListHead) {
|
||
|
NextEntry = (&FfsFileEntry->Link)->ForwardLink;
|
||
|
FreePool (FfsFileEntry);
|
||
|
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Create a new file within a PAD file area.
|
||
|
|
||
|
@param FvDevice Firmware Volume Device.
|
||
|
@param FfsFileBuffer A buffer that holds an FFS file,(it contains a File Header which is in init state).
|
||
|
@param BufferSize The size of FfsFileBuffer.
|
||
|
@param ActualFileSize The actual file length, it may not be multiples of 8.
|
||
|
@param FileName The FFS File Name.
|
||
|
@param FileType The FFS File Type.
|
||
|
@param FileAttributes The Attributes of the FFS File to be created.
|
||
|
|
||
|
@retval EFI_SUCCESS Successfully create a new file within the found PAD file area.
|
||
|
@retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.
|
||
|
@retval other errors New file is created failed.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
FvCreateNewFileInsidePadFile (
|
||
|
IN FV_DEVICE *FvDevice,
|
||
|
IN UINT8 *FfsFileBuffer,
|
||
|
IN UINTN BufferSize,
|
||
|
IN UINTN ActualFileSize,
|
||
|
IN EFI_GUID *FileName,
|
||
|
IN EFI_FV_FILETYPE FileType,
|
||
|
IN EFI_FV_FILE_ATTRIBUTES FileAttributes
|
||
|
)
|
||
|
{
|
||
|
UINTN RequiredAlignment;
|
||
|
FFS_FILE_LIST_ENTRY *PadFileEntry;
|
||
|
EFI_STATUS Status;
|
||
|
UINTN PadAreaLength;
|
||
|
UINTN PadSize;
|
||
|
EFI_FFS_FILE_HEADER *FileHeader;
|
||
|
EFI_FFS_FILE_HEADER *OldPadFileHeader;
|
||
|
EFI_FFS_FILE_HEADER *PadFileHeader;
|
||
|
EFI_FFS_FILE_HEADER *TailPadFileHeader;
|
||
|
UINTN StateOffset;
|
||
|
UINTN Offset;
|
||
|
UINTN NumBytesWritten;
|
||
|
UINT8 *StartPos;
|
||
|
LIST_ENTRY NewFileList;
|
||
|
FFS_FILE_LIST_ENTRY *NewFileListEntry;
|
||
|
FFS_FILE_LIST_ENTRY *FfsEntry;
|
||
|
FFS_FILE_LIST_ENTRY *NextFfsEntry;
|
||
|
|
||
|
//
|
||
|
// First get the required alignment from the File Attributes
|
||
|
//
|
||
|
RequiredAlignment = GetRequiredAlignment (FileAttributes);
|
||
|
|
||
|
//
|
||
|
// Find a suitable PAD File
|
||
|
//
|
||
|
Status = FvLocatePadFile (
|
||
|
FvDevice,
|
||
|
BufferSize,
|
||
|
RequiredAlignment,
|
||
|
&PadSize,
|
||
|
&PadFileEntry
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;
|
||
|
|
||
|
//
|
||
|
// Step 1: Update Pad File Header
|
||
|
//
|
||
|
SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldPadFileHeader);
|
||
|
|
||
|
StartPos = PadFileEntry->FfsHeader;
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;
|
||
|
|
||
|
NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
StateOffset,
|
||
|
&NumBytesWritten,
|
||
|
&OldPadFileHeader->State
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
SetFileState (EFI_FILE_HEADER_CONSTRUCTION, OldPadFileHeader);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Step 2: Update Pad area
|
||
|
//
|
||
|
InitializeListHead (&NewFileList);
|
||
|
|
||
|
PadAreaLength = (*(UINT32 *) OldPadFileHeader->Size & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
|
||
|
|
||
|
PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));
|
||
|
|
||
|
if (RequiredAlignment != 8) {
|
||
|
//
|
||
|
// Insert a PAD file before to achieve required alignment
|
||
|
//
|
||
|
FvFillPadFile (PadFileHeader, PadSize);
|
||
|
NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
ASSERT (NewFileListEntry != NULL);
|
||
|
NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
|
||
|
InsertTailList (&NewFileList, &NewFileListEntry->Link);
|
||
|
}
|
||
|
|
||
|
FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize);
|
||
|
|
||
|
Status = FvFillFfsFile (
|
||
|
FileHeader,
|
||
|
FfsFileBuffer,
|
||
|
BufferSize,
|
||
|
ActualFileSize,
|
||
|
FileName,
|
||
|
FileType,
|
||
|
FileAttributes
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
ASSERT (NewFileListEntry != NULL);
|
||
|
|
||
|
NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
|
||
|
InsertTailList (&NewFileList, &NewFileListEntry->Link);
|
||
|
|
||
|
FvDevice->CurrentFfsFile = NewFileListEntry;
|
||
|
|
||
|
if (PadAreaLength > (BufferSize + PadSize)) {
|
||
|
if ((PadAreaLength - BufferSize - PadSize) >= sizeof (EFI_FFS_FILE_HEADER)) {
|
||
|
//
|
||
|
// we can insert another PAD file
|
||
|
//
|
||
|
TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize);
|
||
|
FvFillPadFile (TailPadFileHeader, PadAreaLength - BufferSize - PadSize);
|
||
|
|
||
|
NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
ASSERT (NewFileListEntry != NULL);
|
||
|
|
||
|
NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;
|
||
|
InsertTailList (&NewFileList, &NewFileListEntry->Link);
|
||
|
} else {
|
||
|
//
|
||
|
// because left size cannot hold another PAD file header,
|
||
|
// adjust the writing file size (just in cache)
|
||
|
//
|
||
|
FvAdjustFfsFile (
|
||
|
FvDevice->ErasePolarity,
|
||
|
FileHeader,
|
||
|
PadAreaLength - BufferSize - PadSize
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Start writing to FV
|
||
|
//
|
||
|
StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
|
||
|
NumBytesWritten = PadAreaLength;
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
Offset,
|
||
|
&NumBytesWritten,
|
||
|
StartPos
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFileList (&NewFileList);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Step 3: Mark Pad file header as EFI_FILE_HEADER_INVALID
|
||
|
//
|
||
|
SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);
|
||
|
|
||
|
StartPos = PadFileEntry->FfsHeader;
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;
|
||
|
|
||
|
NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
StateOffset,
|
||
|
&NumBytesWritten,
|
||
|
&OldPadFileHeader->State
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If all successfully, update FFS_FILE_LIST
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Delete old pad file entry
|
||
|
//
|
||
|
FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;
|
||
|
NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;
|
||
|
|
||
|
FreePool (PadFileEntry);
|
||
|
|
||
|
FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;
|
||
|
(NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;
|
||
|
NextFfsEntry->Link.BackLink = NewFileList.BackLink;
|
||
|
(NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Free all FfsBuffer.
|
||
|
|
||
|
@param NumOfFiles Number of FfsBuffer.
|
||
|
@param FfsBuffer An array of pointer to an FFS File Buffer
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
FreeFfsBuffer (
|
||
|
IN UINTN NumOfFiles,
|
||
|
IN UINT8 **FfsBuffer
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
for (Index = 0; Index < NumOfFiles; Index++) {
|
||
|
if (FfsBuffer[Index] != NULL) {
|
||
|
FreePool (FfsBuffer[Index]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Create multiple files within a PAD File area.
|
||
|
|
||
|
@param FvDevice Firmware Volume Device.
|
||
|
@param PadFileEntry The pad file entry to be written in.
|
||
|
@param NumOfFiles Total File number to be written.
|
||
|
@param BufferSize The array of buffer size of each FfsBuffer.
|
||
|
@param ActualFileSize The array of actual file size.
|
||
|
@param PadSize The array of leading pad file size for each FFS File
|
||
|
@param FfsBuffer The array of Ffs Buffer pointer.
|
||
|
@param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
|
||
|
used to get name, attributes, type, etc.
|
||
|
|
||
|
@retval EFI_SUCCESS Add the input multiple files into PAD file area.
|
||
|
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
|
||
|
@retval other error Files can't be added into PAD file area.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
FvCreateMultipleFilesInsidePadFile (
|
||
|
IN FV_DEVICE *FvDevice,
|
||
|
IN FFS_FILE_LIST_ENTRY *PadFileEntry,
|
||
|
IN UINTN NumOfFiles,
|
||
|
IN UINTN *BufferSize,
|
||
|
IN UINTN *ActualFileSize,
|
||
|
IN UINTN *PadSize,
|
||
|
IN UINT8 **FfsBuffer,
|
||
|
IN EFI_FV_WRITE_FILE_DATA *FileData
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_FFS_FILE_HEADER *OldPadFileHeader;
|
||
|
UINTN Index;
|
||
|
EFI_FFS_FILE_HEADER *PadFileHeader;
|
||
|
EFI_FFS_FILE_HEADER *FileHeader;
|
||
|
EFI_FFS_FILE_HEADER *TailPadFileHeader;
|
||
|
UINTN TotalSize;
|
||
|
UINTN PadAreaLength;
|
||
|
LIST_ENTRY NewFileList;
|
||
|
FFS_FILE_LIST_ENTRY *NewFileListEntry;
|
||
|
UINTN Offset;
|
||
|
UINTN NumBytesWritten;
|
||
|
UINT8 *StartPos;
|
||
|
FFS_FILE_LIST_ENTRY *FfsEntry;
|
||
|
FFS_FILE_LIST_ENTRY *NextFfsEntry;
|
||
|
|
||
|
InitializeListHead (&NewFileList);
|
||
|
|
||
|
NewFileListEntry = NULL;
|
||
|
|
||
|
OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;
|
||
|
PadAreaLength = (*(UINT32 *) OldPadFileHeader->Size & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
|
||
|
|
||
|
Status = UpdateHeaderBit (
|
||
|
FvDevice,
|
||
|
OldPadFileHeader,
|
||
|
EFI_FILE_MARKED_FOR_UPDATE
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
//
|
||
|
// Update PAD area
|
||
|
//
|
||
|
TotalSize = 0;
|
||
|
PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));
|
||
|
FileHeader = PadFileHeader;
|
||
|
|
||
|
for (Index = 0; Index < NumOfFiles; Index++) {
|
||
|
if (PadSize[Index] != 0) {
|
||
|
FvFillPadFile (PadFileHeader, PadSize[Index]);
|
||
|
NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
if (NewFileListEntry == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
|
||
|
InsertTailList (&NewFileList, &NewFileListEntry->Link);
|
||
|
}
|
||
|
|
||
|
FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]);
|
||
|
Status = FvFillFfsFile (
|
||
|
FileHeader,
|
||
|
FfsBuffer[Index],
|
||
|
BufferSize[Index],
|
||
|
ActualFileSize[Index],
|
||
|
FileData[Index].NameGuid,
|
||
|
FileData[Index].Type,
|
||
|
FileData[Index].FileAttributes
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
if (NewFileListEntry == NULL) {
|
||
|
FreeFileList (&NewFileList);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
|
||
|
InsertTailList (&NewFileList, &NewFileListEntry->Link);
|
||
|
|
||
|
PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]);
|
||
|
TotalSize += PadSize[Index];
|
||
|
TotalSize += BufferSize[Index];
|
||
|
}
|
||
|
|
||
|
FvDevice->CurrentFfsFile = NewFileListEntry;
|
||
|
//
|
||
|
// Maybe we need a tail pad file
|
||
|
//
|
||
|
if (PadAreaLength > TotalSize) {
|
||
|
if ((PadAreaLength - TotalSize) >= sizeof (EFI_FFS_FILE_HEADER)) {
|
||
|
//
|
||
|
// we can insert another PAD file
|
||
|
//
|
||
|
TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[NumOfFiles - 1]);
|
||
|
FvFillPadFile (TailPadFileHeader, PadAreaLength - TotalSize);
|
||
|
|
||
|
NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
|
||
|
if (NewFileListEntry == NULL) {
|
||
|
FreeFileList (&NewFileList);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;
|
||
|
InsertTailList (&NewFileList, &NewFileListEntry->Link);
|
||
|
} else {
|
||
|
//
|
||
|
// because left size cannot hold another PAD file header,
|
||
|
// adjust the writing file size (just in cache)
|
||
|
//
|
||
|
FvAdjustFfsFile (
|
||
|
FvDevice->ErasePolarity,
|
||
|
FileHeader,
|
||
|
PadAreaLength - TotalSize
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Start writing to FV
|
||
|
//
|
||
|
StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);
|
||
|
|
||
|
Offset = (UINTN) (StartPos - FvDevice->CachedFv);
|
||
|
|
||
|
NumBytesWritten = PadAreaLength;
|
||
|
Status = FvcWrite (
|
||
|
FvDevice,
|
||
|
Offset,
|
||
|
&NumBytesWritten,
|
||
|
StartPos
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFileList (&NewFileList);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = UpdateHeaderBit (
|
||
|
FvDevice,
|
||
|
OldPadFileHeader,
|
||
|
EFI_FILE_HEADER_INVALID
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFileList (&NewFileList);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update File List Link
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// First delete old pad file entry
|
||
|
//
|
||
|
FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;
|
||
|
NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;
|
||
|
|
||
|
FreePool (PadFileEntry);
|
||
|
|
||
|
FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;
|
||
|
(NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;
|
||
|
NextFfsEntry->Link.BackLink = NewFileList.BackLink;
|
||
|
(NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Write multiple files into FV in reliable method.
|
||
|
|
||
|
@param FvDevice Firmware Volume Device.
|
||
|
@param NumOfFiles Total File number to be written.
|
||
|
@param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
|
||
|
used to get name, attributes, type, etc
|
||
|
@param FileOperation The array of operation for each file.
|
||
|
|
||
|
@retval EFI_SUCCESS Files are added into FV.
|
||
|
@retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.
|
||
|
@retval EFI_INVALID_PARAMETER File number is less than or equal to 1.
|
||
|
@retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
FvCreateMultipleFiles (
|
||
|
IN FV_DEVICE *FvDevice,
|
||
|
IN UINTN NumOfFiles,
|
||
|
IN EFI_FV_WRITE_FILE_DATA *FileData,
|
||
|
IN BOOLEAN *FileOperation
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINT8 *FfsBuffer[MAX_FILES];
|
||
|
UINTN Index1;
|
||
|
UINTN Index2;
|
||
|
UINTN BufferSize[MAX_FILES];
|
||
|
UINTN ActualFileSize[MAX_FILES];
|
||
|
UINTN RequiredAlignment[MAX_FILES];
|
||
|
UINTN PadSize[MAX_FILES];
|
||
|
FFS_FILE_LIST_ENTRY *PadFileEntry;
|
||
|
UINTN TotalSizeNeeded;
|
||
|
FREE_SPACE_ENTRY *FreeSpaceEntry;
|
||
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
|
||
|
UINTN Key;
|
||
|
EFI_GUID FileNameGuid;
|
||
|
EFI_FV_FILETYPE OldFileType;
|
||
|
EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
|
||
|
UINTN OldFileSize;
|
||
|
FFS_FILE_LIST_ENTRY *OldFfsFileEntry[MAX_FILES];
|
||
|
EFI_FFS_FILE_HEADER *OldFileHeader[MAX_FILES];
|
||
|
BOOLEAN IsCreateFile;
|
||
|
|
||
|
//
|
||
|
// To use this function, we must ensure that the NumOfFiles is great
|
||
|
// than 1
|
||
|
//
|
||
|
if (NumOfFiles <= 1) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (NumOfFiles > MAX_FILES) {
|
||
|
return EFI_UNSUPPORTED;
|
||
|
}
|
||
|
|
||
|
Fv = &FvDevice->Fv;
|
||
|
|
||
|
SetMem (FfsBuffer, NumOfFiles, 0);
|
||
|
SetMem (RequiredAlignment, NumOfFiles, 8);
|
||
|
SetMem (PadSize, NumOfFiles, 0);
|
||
|
ZeroMem (OldFfsFileEntry, sizeof (OldFfsFileEntry));
|
||
|
ZeroMem (OldFileHeader, sizeof (OldFileHeader));
|
||
|
|
||
|
//
|
||
|
// Adjust file size
|
||
|
//
|
||
|
for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
|
||
|
ActualFileSize[Index1] = FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER);
|
||
|
BufferSize[Index1] = ActualFileSize[Index1];
|
||
|
|
||
|
if (BufferSize[Index1] == sizeof (EFI_FFS_FILE_HEADER)) {
|
||
|
//
|
||
|
// clear file attributes, zero-length file does not have any attributes
|
||
|
//
|
||
|
FileData[Index1].FileAttributes = 0;
|
||
|
}
|
||
|
|
||
|
while ((BufferSize[Index1] & 0x07) != 0) {
|
||
|
BufferSize[Index1]++;
|
||
|
}
|
||
|
|
||
|
FfsBuffer[Index1] = AllocateZeroPool (BufferSize[Index1]);
|
||
|
|
||
|
//
|
||
|
// Copy File Data into FileBuffer
|
||
|
//
|
||
|
CopyMem (
|
||
|
FfsBuffer[Index1] + sizeof (EFI_FFS_FILE_HEADER),
|
||
|
FileData[Index1].Buffer,
|
||
|
FileData[Index1].BufferSize
|
||
|
);
|
||
|
|
||
|
if (FvDevice->ErasePolarity == 1) {
|
||
|
for (Index2 = 0; Index2 < sizeof (EFI_FFS_FILE_HEADER); Index2++) {
|
||
|
FfsBuffer[Index1][Index2] = (UINT8)~FfsBuffer[Index1][Index2];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((FileData[Index1].FileAttributes & FFS_ATTRIB_DATA_ALIGNMENT) != 0) {
|
||
|
RequiredAlignment[Index1] = GetRequiredAlignment (FileData[Index1].FileAttributes);
|
||
|
}
|
||
|
//
|
||
|
// If update file, mark the original file header to
|
||
|
// EFI_FILE_MARKED_FOR_UPDATE
|
||
|
//
|
||
|
IsCreateFile = FileOperation[Index1];
|
||
|
if (!IsCreateFile) {
|
||
|
|
||
|
Key = 0;
|
||
|
do {
|
||
|
OldFileType = 0;
|
||
|
Status = Fv->GetNextFile (
|
||
|
Fv,
|
||
|
&Key,
|
||
|
&OldFileType,
|
||
|
&FileNameGuid,
|
||
|
&OldFileAttributes,
|
||
|
&OldFileSize
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFfsBuffer (NumOfFiles, FfsBuffer);
|
||
|
return Status;
|
||
|
}
|
||
|
} while (!CompareGuid (&FileNameGuid, FileData[Index1].NameGuid));
|
||
|
|
||
|
//
|
||
|
// Get FfsFileEntry from the search key
|
||
|
//
|
||
|
OldFfsFileEntry[Index1] = (FFS_FILE_LIST_ENTRY *) Key;
|
||
|
OldFileHeader[Index1] = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry[Index1]->FfsHeader;
|
||
|
Status = UpdateHeaderBit (
|
||
|
FvDevice,
|
||
|
OldFileHeader[Index1],
|
||
|
EFI_FILE_MARKED_FOR_UPDATE
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFfsBuffer (NumOfFiles, FfsBuffer);
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// First to search a suitable pad file that can hold so
|
||
|
// many files
|
||
|
//
|
||
|
Status = FvSearchSuitablePadFile (
|
||
|
FvDevice,
|
||
|
NumOfFiles,
|
||
|
BufferSize,
|
||
|
RequiredAlignment,
|
||
|
PadSize,
|
||
|
&TotalSizeNeeded,
|
||
|
&PadFileEntry
|
||
|
);
|
||
|
|
||
|
if (Status == EFI_NOT_FOUND) {
|
||
|
//
|
||
|
// Try to find a free space that can hold these files
|
||
|
// and create a suitable PAD file in this free space
|
||
|
//
|
||
|
Status = FvSearchSuitableFreeSpace (
|
||
|
FvDevice,
|
||
|
NumOfFiles,
|
||
|
BufferSize,
|
||
|
RequiredAlignment,
|
||
|
PadSize,
|
||
|
&TotalSizeNeeded,
|
||
|
&FreeSpaceEntry
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFfsBuffer (NumOfFiles, FfsBuffer);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
//
|
||
|
// Create a PAD file in that space
|
||
|
//
|
||
|
Status = FvCreatePadFileInFreeSpace (
|
||
|
FvDevice,
|
||
|
FreeSpaceEntry,
|
||
|
TotalSizeNeeded,
|
||
|
&PadFileEntry
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreeFfsBuffer (NumOfFiles, FfsBuffer);
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Create multiple files inside such a pad file
|
||
|
// to achieve lock-step update
|
||
|
//
|
||
|
Status = FvCreateMultipleFilesInsidePadFile (
|
||
|
FvDevice,
|
||
|
PadFileEntry,
|
||
|
NumOfFiles,
|
||
|
BufferSize,
|
||
|
ActualFileSize,
|
||
|
PadSize,
|
||
|
FfsBuffer,
|
||
|
FileData
|
||
|
);
|
||
|
|
||
|
FreeFfsBuffer (NumOfFiles, FfsBuffer);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
//
|
||
|
// Delete those updated files
|
||
|
//
|
||
|
for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
|
||
|
IsCreateFile = FileOperation[Index1];
|
||
|
if (!IsCreateFile && OldFfsFileEntry[Index1] != NULL) {
|
||
|
(OldFfsFileEntry[Index1]->Link.BackLink)->ForwardLink = OldFfsFileEntry[Index1]->Link.ForwardLink;
|
||
|
(OldFfsFileEntry[Index1]->Link.ForwardLink)->BackLink = OldFfsFileEntry[Index1]->Link.BackLink;
|
||
|
FreePool (OldFfsFileEntry[Index1]);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Set those files' state to EFI_FILE_DELETED
|
||
|
//
|
||
|
for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
|
||
|
IsCreateFile = FileOperation[Index1];
|
||
|
if (!IsCreateFile && OldFileHeader[Index1] != NULL) {
|
||
|
Status = UpdateHeaderBit (FvDevice, OldFileHeader[Index1], EFI_FILE_DELETED);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|