summaryrefslogtreecommitdiff
path: root/IntelFrameworkModulePkg/Universal/FirmwareVolume
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-01 19:57:08 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-01 19:57:08 +0000
commitc2df8e13f68ab18f96874cadc0a3dfada67a7e7c (patch)
tree06d4e076c4e8c659045a149d2e91d667d240b802 /IntelFrameworkModulePkg/Universal/FirmwareVolume
parent16d88c2d20ccd9f8ea52967b578ece82174ea762 (diff)
downloadedk2-platforms-c2df8e13f68ab18f96874cadc0a3dfada67a7e7c.tar.xz
IntelFrameworkModulePkg: Add FwVolDxe driver
Signed-off-by: jljusten Reviewed-by: rsun3 Reviewed-by: lgao4 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12256 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'IntelFrameworkModulePkg/Universal/FirmwareVolume')
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c625
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c1032
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c651
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c220
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h773
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf68
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c580
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c1591
8 files changed, 5540 insertions, 0 deletions
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
new file mode 100644
index 0000000000..1e3c839e27
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
@@ -0,0 +1,625 @@
+/** @file
+ FFS file access utilities.
+
+ 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"
+
+#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
+
+/**
+ Set File State in the FfsHeader.
+
+ @param State File state to be set into FFS header.
+ @param FfsHeader Points to the FFS file header
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ //
+ // Set File State in the FfsHeader
+ //
+ FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);
+ return ;
+}
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
+ HighestBit >>= 1;
+ }
+
+ return (EFI_FFS_FILE_STATE) HighestBit;
+}
+
+/**
+ Convert the Buffer Address to LBA Entry Address.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param LbaListEntry Pointer to the got LBA entry that contains the address.
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA entry is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2LbaEntry (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT LBA_ENTRY **LbaListEntry
+ )
+{
+ LBA_ENTRY *LbaEntry;
+ LIST_ENTRY *Link;
+
+ Link = FvDevice->LbaHeader.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ //
+ // Locate LBA which contains the address
+ //
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+ if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {
+ break;
+ }
+
+ Link = LbaEntry->Link.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+ }
+
+ if (&LbaEntry->Link == &FvDevice->LbaHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ Link = LbaEntry->Link.BackLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ if (&LbaEntry->Link == &FvDevice->LbaHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ *LbaListEntry = LbaEntry;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert the Buffer Address to LBA Address & Offset.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param Lba Pointer to the gob Lba value
+ @param Offset Pointer to the got Offset
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA and Offset is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2Lba (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset
+ )
+{
+ LBA_ENTRY *LbaEntry;
+ EFI_STATUS Status;
+
+ LbaEntry = NULL;
+
+ Status = Buffer2LbaEntry (
+ FvDevice,
+ BufferAddress,
+ &LbaEntry
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Lba = LbaEntry->LbaIndex;
+ *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param Buffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Count;
+ UINT8 EraseByte;
+
+ if (ErasePolarity == 1) {
+ EraseByte = 0xFF;
+ } else {
+ EraseByte = 0;
+ }
+
+ for (Count = 0; Count < BufferSize; Count++) {
+ if (Buffer[Count] != EraseByte) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ )
+{
+ UINT16 Checksum;
+
+ Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);
+
+ if (Checksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Verify checksum of the FFS file header.
+
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT8 HeaderChecksum;
+
+ HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
+ HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
+
+ if (HeaderChecksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Verify checksum of the FFS file data.
+
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT8 FileChecksum;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 FileSize;
+
+ Attributes = FfsHeader->Attributes;
+
+ if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
+
+ FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
+
+ //
+ // Check checksum of FFS data
+ //
+ FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FileSize - sizeof (EFI_FFS_FILE_HEADER));
+ FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);
+
+ if (FileChecksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ } else {
+
+ if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+ }
+
+}
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFFSHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+
+ //
+ // Check if it is a free space
+ //
+ if (IsBufferErased (
+ ErasePolarity,
+ (UINT8 *) FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ )) {
+ return FALSE;
+ }
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (FileState) {
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ //
+ // fall through
+ //
+ case EFI_FILE_HEADER_INVALID:
+ return FALSE;
+
+ case EFI_FILE_HEADER_VALID:
+ //
+ // fall through
+ //
+ case EFI_FILE_DATA_VALID:
+ //
+ // fall through
+ //
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ //
+ // fall through
+ //
+ case EFI_FILE_DELETED:
+ //
+ // Here we need to verify header checksum
+ //
+ if (!VerifyHeaderChecksum (FfsHeader)) {
+ return FALSE;
+ }
+ break;
+
+ default:
+ //
+ // return
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Get next possible of Firmware File System Header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be skipped.
+
+ @return Pointer to next FFS header.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetNextPossibleFileHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT32 FileLength;
+ UINT32 SkipLength;
+
+ if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {
+ //
+ // Skip this header
+ //
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ FileLength = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
+
+ //
+ // Since FileLength is not multiple of 8, we need skip some bytes
+ // to get next possible header
+ //
+ SkipLength = FileLength;
+ while ((SkipLength & 0x07) != 0) {
+ SkipLength++;
+ }
+
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;
+}
+
+/**
+ Search FFS file with the same FFS name in FV Cache.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file header to be skipped.
+ @param StateBit FFS file state bit to be checked.
+
+ @return Pointer to next found FFS header. NULL will return if no found.
+
+**/
+EFI_FFS_FILE_HEADER *
+DuplicateFileExist (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_FFS_FILE_STATE StateBit
+ )
+{
+ UINT8 *Ptr;
+ EFI_FFS_FILE_HEADER *NextFfsFile;
+
+ //
+ // Search duplicate file, not from the beginning of FV,
+ // just search the next ocurrence of this file
+ //
+ NextFfsFile = FfsHeader;
+
+ do {
+ Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (
+ GetNextPossibleFileHeader (FvDevice->ErasePolarity,
+ NextFfsFile)
+ );
+ NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;
+
+ if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <
+ sizeof (EFI_FFS_FILE_HEADER)
+ ) {
+ break;
+ }
+
+ if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {
+ continue;
+ }
+
+ if (!VerifyFileChecksum (NextFfsFile)) {
+ continue;
+ }
+
+ if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {
+ if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {
+ return NextFfsFile;
+ }
+ }
+ } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);
+
+ return NULL;
+}
+
+/**
+ Change FFS file header state and write to FV.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file header to be updated.
+ @param State FFS file state to be set.
+
+ @retval EFI_SUCCESS File state is writen into FV.
+ @retval others File state can't be writen into FV.
+
+**/
+EFI_STATUS
+UpdateHeaderBit (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_FFS_FILE_STATE State
+ )
+{
+ EFI_STATUS Status;
+ EFI_LBA Lba;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+
+ Lba = 0;
+ Offset = 0;
+
+ SetFileState (State, FfsHeader);
+
+ Buffer2Lba (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),
+ &Lba,
+ &Offset
+ );
+ //
+ // Write the state byte into FV
+ //
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvDevice->Fvb->Write (
+ FvDevice->Fvb,
+ Lba,
+ Offset,
+ &NumBytesWritten,
+ &FfsHeader->State
+ );
+ return Status;
+}
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFFSFile (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 ErasePolarity;
+
+ ErasePolarity = FvDevice->ErasePolarity;
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (FileState) {
+ case EFI_FILE_DATA_VALID:
+ if (!VerifyFileChecksum (FfsHeader)) {
+ return FALSE;
+ }
+
+ if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ break;
+ }
+ //
+ // Check if there is another duplicated file with the EFI_FILE_DATA_VALID
+ //
+ if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (!VerifyFileChecksum (FfsHeader)) {
+ return FALSE;
+ }
+
+ if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // since its data area is not unperturbed, it cannot be reclaimed,
+ // marked it as deleted
+ //
+ UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
+ return TRUE;
+
+ } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
+ //
+ // Here the found file is more recent than this file,
+ // mark it as deleted
+ //
+ UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
+ return TRUE;
+
+ } else {
+ return TRUE;
+ }
+
+ break;
+
+ case EFI_FILE_DELETED:
+ if (!VerifyFileChecksum (FfsHeader)) {
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Locate the first file in FV.
+
+ @param FvDevice Cached FV image.
+ @param FirstFile Points to the got first FFS file header.
+
+ @retval EFI_NOT_FOUND No FFS file is found in FV.
+ @retval EFI_SUCCESS The first FFS file is got.
+
+**/
+EFI_STATUS
+FvLocateFirstFile (
+ IN FV_DEVICE *FvDevice,
+ OUT EFI_FFS_FILE_HEADER **FirstFile
+ )
+{
+ FFS_FILE_LIST_ENTRY *TmpFileList;
+ LIST_ENTRY *Link;
+
+ Link = FvDevice->FfsFileListHeader.ForwardLink;
+
+ if (Link == &FvDevice->FfsFileListHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ TmpFileList = (FFS_FILE_LIST_ENTRY *) Link;
+ *FirstFile = (EFI_FFS_FILE_HEADER *) TmpFileList->FfsHeader;
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c
new file mode 100644
index 0000000000..14b8563143
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c
@@ -0,0 +1,1032 @@
+/** @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;
+}
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
new file mode 100644
index 0000000000..f453d5ec0a
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
@@ -0,0 +1,651 @@
+/** @file
+
+ Firmware File System driver that produce full Firmware Volume2 protocol.
+ Layers on top of Firmware Block protocol to produce a file abstraction
+ of FV based files.
+
+ Copyright (c) 2006 - 2010, 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"
+
+#define KEYSIZE sizeof (UINTN)
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER TempFvh;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN FvhLength;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ //
+ // Determine the real length of FV header
+ //
+ Status = Fvb->GetAttributes (
+ Fvb,
+ &FvbAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Just avoid compiling warning
+ //
+ BaseAddress = 0;
+ FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+
+ //
+ // memory-mapped FV and non memory-mapped has different ways to read
+ //
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ Status = Fvb->GetPhysicalAddress (
+ Fvb,
+ &BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (&TempFvh, (VOID *) (UINTN) BaseAddress, FvhLength);
+ } else {
+ Status = Fvb->Read (
+ Fvb,
+ 0,
+ 0,
+ &FvhLength,
+ (UINT8 *) &TempFvh
+ );
+ }
+
+ *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
+ if (*FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read the whole header
+ //
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ CopyMem (*FwVolHeader, (VOID *) (UINTN) BaseAddress, TempFvh.HeaderLength);
+ } else {
+ //
+ // Assumed the first block is bigger than the length of Fv headder
+ //
+ FvhLength = TempFvh.HeaderLength;
+ Status = Fvb->Read (
+ Fvb,
+ 0,
+ 0,
+ &FvhLength,
+ (UINT8 *) *FwVolHeader
+ );
+ //
+ // Check whether Read successes.
+ //
+ if (EFI_ERROR (Status)) {
+ FreePool (*FwVolHeader);
+ *FwVolHeader = NULL;
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free FvDevice resource when error happens.
+
+ @param FvDevice Pointer to the FvDevice to be freed.
+**/
+VOID
+FreeFvDeviceResource (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ LBA_ENTRY *LbaEntry;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ LIST_ENTRY *NextEntry;
+
+ //
+ // Free LAB Entry
+ //
+ LbaEntry = (LBA_ENTRY *) FvDevice->LbaHeader.ForwardLink;
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+ NextEntry = (&LbaEntry->Link)->ForwardLink;
+ FreePool (LbaEntry);
+ LbaEntry = (LBA_ENTRY *) NextEntry;
+ }
+ //
+ // Free File List Entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
+ while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;
+ FreePool (FfsFileEntry);
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
+ }
+ //
+ // Free Space Entry
+ //
+ FreeSpaceEntry = (FREE_SPACE_ENTRY *) FvDevice->FreeSpaceHeader.ForwardLink;
+ while (&FreeSpaceEntry->Link != &FvDevice->FreeSpaceHeader) {
+ NextEntry = (&FreeSpaceEntry->Link)->ForwardLink;
+ FreePool (FreeSpaceEntry);
+ FreeSpaceEntry = (FREE_SPACE_ENTRY *) NextEntry;
+ }
+ //
+ // Free the cache
+ //
+ FreePool ((UINT8 *) (UINTN) FvDevice->CachedFv);
+
+ return ;
+}
+
+/**
+ Check if an FV is consistent and allocate cache for it.
+
+ @param FvDevice A pointer to the FvDevice to be checked.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_VOLUME_CORRUPTED File system is corrupted.
+ @retval EFI_SUCCESS FV is consistent and cache is allocated.
+
+**/
+EFI_STATUS
+FvCheck (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *FwCache;
+ LBA_ENTRY *LbaEntry;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ UINT8 *LbaStart;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ UINT8 *Ptr;
+ UINTN Size;
+ UINT8 *FreeStart;
+ UINTN FreeSize;
+ UINT8 ErasePolarity;
+ UINTN FileLength;
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 *TopFvAddress;
+ UINTN TestLength;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ Fvb = FvDevice->Fvb;
+
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ InitializeListHead (&FvDevice->LbaHeader);
+ InitializeListHead (&FvDevice->FreeSpaceHeader);
+ InitializeListHead (&FvDevice->FfsFileListHeader);
+
+ FwVolHeader = NULL;
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (FwVolHeader != NULL);
+
+ //
+ // Double Check firmware volume header here
+ //
+ if (!VerifyFvHeaderChecksum (FwVolHeader)) {
+ FreePool (FwVolHeader);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ BlockMap = FwVolHeader->BlockMap;
+
+ //
+ // FwVolHeader->FvLength is the whole FV length including FV header
+ //
+ FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);
+ if (FwCache == NULL) {
+ FreePool (FwVolHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;
+
+ //
+ // Copy to memory
+ //
+ LbaStart = FwCache;
+ LbaIndex = 0;
+ Ptr = NULL;
+
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ //
+ // Get volume base address
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) BaseAddress);
+
+ DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));
+ }
+ //
+ // Copy whole FV into the memory
+ //
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
+ LbaEntry = AllocatePool (sizeof (LBA_ENTRY));
+ if (LbaEntry == NULL) {
+ FreePool (FwVolHeader);
+ FreeFvDeviceResource (FvDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LbaEntry->LbaIndex = LbaIndex;
+ LbaEntry->StartingAddress = LbaStart;
+ LbaEntry->BlockLength = BlockMap->Length;
+
+ //
+ // Copy each LBA into memory
+ //
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+
+ CopyMem (LbaStart, Ptr, BlockMap->Length);
+ Ptr += BlockMap->Length;
+
+ } else {
+
+ Size = BlockMap->Length;
+ Status = Fvb->Read (
+ Fvb,
+ LbaIndex,
+ 0,
+ &Size,
+ LbaStart
+ );
+ //
+ // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
+ //
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ FreeFvDeviceResource (FvDevice);
+ return Status;
+ }
+
+ }
+
+ LbaIndex++;
+ LbaStart += BlockMap->Length;
+
+ InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);
+ }
+
+ BlockMap++;
+ }
+
+ FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;
+
+ //
+ // it is not used any more, so free FwVolHeader
+ //
+ FreePool (FwVolHeader);
+
+ //
+ // Scan to check the free space & File list
+ //
+ if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ FvDevice->ErasePolarity = ErasePolarity;
+
+ //
+ // go through the whole FV cache, check the consistence of the FV
+ //
+ Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);
+ TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength - 1);
+
+ //
+ // Build FFS list & Free Space List here
+ //
+ while (Ptr <= TopFvAddress) {
+ TestLength = TopFvAddress - Ptr + 1;
+
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {
+ //
+ // We found free space
+ //
+ FreeStart = Ptr;
+ FreeSize = 0;
+
+ do {
+ TestLength = TopFvAddress - Ptr + 1;
+
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {
+ break;
+ }
+
+ FreeSize += TestLength;
+ Ptr += TestLength;
+ } while (Ptr <= TopFvAddress);
+
+ FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));
+ if (FreeSpaceEntry == NULL) {
+ FreeFvDeviceResource (FvDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create a Free space entry
+ //
+ FreeSpaceEntry->StartingAddress = FreeStart;
+ FreeSpaceEntry->Length = FreeSize;
+ InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);
+ continue;
+ }
+ //
+ // double check boundry
+ //
+ if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {
+ break;
+ }
+
+ if (!IsValidFFSHeader (
+ FvDevice->ErasePolarity,
+ (EFI_FFS_FILE_HEADER *) Ptr
+ )) {
+ FileState = GetFileState (
+ FvDevice->ErasePolarity,
+ (EFI_FFS_FILE_HEADER *) Ptr
+ );
+ if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
+ Ptr += sizeof (EFI_FFS_FILE_HEADER);
+
+ continue;
+
+ } else {
+ //
+ // File system is corrputed, return
+ //
+ FreeFvDeviceResource (FvDevice);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {
+ FileLength = *(UINT32 *) ((EFI_FFS_FILE_HEADER *) Ptr)->Size & 0x00FFFFFF;
+ FileState = GetFileState (
+ FvDevice->ErasePolarity,
+ (EFI_FFS_FILE_HEADER *) Ptr
+ );
+
+ //
+ // check for non-deleted file
+ //
+ if (FileState != EFI_FILE_DELETED) {
+ //
+ // Create a FFS list entry for each non-deleted file
+ //
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (FfsFileEntry == NULL) {
+ FreeFvDeviceResource (FvDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FfsFileEntry->FfsHeader = Ptr;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+ }
+
+ Ptr += FileLength;
+
+ //
+ // Adjust Ptr to the next 8-byte aligned boundry.
+ //
+ while (((UINTN) Ptr & 0x07) != 0) {
+ Ptr++;
+ }
+ } else {
+ //
+ // File system is corrupted, return
+ //
+ FreeFvDeviceResource (FvDevice);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ FvDevice->CurrentFfsFile = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point function does install/reinstall FV2 protocol with full functionality.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
+ @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ BOOLEAN Reinstall;
+ BOOLEAN InstallFlag;
+
+ DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));
+ InstallFlag = FALSE;
+ //
+ // Locate all handles of Fvb protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Get FV with gEfiFirmwareFileSystemGuid
+ //
+ for (Index = 0; Index < HandleCount; Index += 1) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) &Fvb
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ FwVolHeader = NULL;
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ASSERT (FwVolHeader != NULL);
+ //
+ // Check to see that the file system is indeed formatted in a way we can
+ // understand it...
+ //
+ if (!CompareGuid (
+ &FwVolHeader->FileSystemGuid,
+ &gEfiFirmwareFileSystem2Guid
+ )) {
+ FreePool (FwVolHeader);
+ continue;
+ }
+ FreePool (FwVolHeader);
+
+ Reinstall = FALSE;
+ //
+ // Check if there is an FV protocol already installed in that handle
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Reinstall = TRUE;
+ }
+ //
+ // FwVol protocol on the handle so create a new one
+ //
+ FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));
+ if (FvDevice == NULL) {
+ goto Done;
+ }
+
+ FvDevice->Signature = FV_DEVICE_SIGNATURE;
+ FvDevice->Fvb = Fvb;
+
+ //
+ // Firmware Volume Protocol interface
+ //
+ FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;
+ FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;
+ FvDevice->Fv.ReadFile = FvReadFile;
+ FvDevice->Fv.ReadSection = FvReadFileSection;
+ FvDevice->Fv.WriteFile = FvWriteFile;
+ FvDevice->Fv.GetNextFile = FvGetNextFile;
+ FvDevice->Fv.KeySize = KEYSIZE;
+ FvDevice->Fv.GetInfo = FvGetVolumeInfo;
+ FvDevice->Fv.SetInfo = FvSetVolumeInfo;
+
+ Status = FvCheck (FvDevice);
+ if (EFI_ERROR (Status)) {
+ //
+ // The file system is not consistence
+ //
+ FreePool (FvDevice);
+ continue;
+ }
+
+ if (Reinstall) {
+ //
+ // Reinstall an New FV protocol
+ //
+ // FvDevice = FV_DEVICE_FROM_THIS (Fv);
+ // FvDevice->Fvb = Fvb;
+ // FreeFvDeviceResource (FvDevice);
+ //
+ Status = gBS->ReinstallProtocolInterface (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ Fv,
+ &FvDevice->Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ InstallFlag = TRUE;
+ } else {
+ FreePool (FvDevice);
+ }
+
+ DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Install an New FV protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &FvDevice->Handle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &FvDevice->Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ InstallFlag = TRUE;
+ } else {
+ FreePool (FvDevice);
+ }
+
+ DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+Done:
+ //
+ // As long as one Fv protocol install/reinstall successfully,
+ // success should return to ensure this image will be not unloaded.
+ // Otherwise, new Fv protocols are corrupted by other loaded driver.
+ //
+ if (InstallFlag) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No FV protocol install/reinstall successfully.
+ // EFI_NOT_FOUND should return to ensure this image will be unloaded.
+ //
+ return EFI_NOT_FOUND;
+}
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c
new file mode 100644
index 0000000000..0e4ddf8bea
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c
@@ -0,0 +1,220 @@
+/** @file
+
+ Implements get/set firmware volume attributes.
+
+ Copyright (c) 2006 - 2010, 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"
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS Successfully got volume attributes
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+ Fvb = FvDevice->Fvb;
+
+ //
+ // First get the Firmware Volume Block Attributes
+ //
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ FvbAttributes &= 0xfffff0ff;
+
+ *Attributes = FvbAttributes;
+ *Attributes |= EFI_FV2_WRITE_POLICY_RELIABLE;
+ return Status;
+}
+
+/**
+ Sets current attributes for volume.
+
+ @param This Calling context
+ @param Attributes On input, FvAttributes is a pointer to
+ an EFI_FV_ATTRIBUTES containing the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. On
+ unsuccessful return, FvAttributes is not
+ modified and the firmware volume
+ settings are not changed.
+
+ @retval EFI_SUCCESS The requested firmware volume attributes
+ were set and the resulting
+ EFI_FV_ATTRIBUTES is returned in
+ FvAttributes.
+ @retval EFI_ACCESS_DENIED Atrribute is locked down.
+ @retval EFI_INVALID_PARAMETER Atrribute is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 OldFvbAttributes;
+ EFI_FVB_ATTRIBUTES_2 NewFvbAttributes;
+ UINT64 NewStatus;
+ UINT32 Capabilities;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+ Fvb = FvDevice->Fvb;
+
+ //
+ // First get the current Volume Attributes
+ //
+ Status = Fvb->GetAttributes (
+ Fvb,
+ &OldFvbAttributes
+ );
+
+ if ((OldFvbAttributes & EFI_FVB2_LOCK_STATUS) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Only status attributes can be updated.
+ //
+ Capabilities = OldFvbAttributes & EFI_FVB2_CAPABILITIES;
+ NewStatus = (*Attributes) & EFI_FVB2_STATUS;
+
+ //
+ // Test read disable
+ //
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test read enable
+ //
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write disable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write enable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test lock
+ //
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ NewFvbAttributes = OldFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+ NewFvbAttributes |= NewStatus;
+ Status = Fvb->SetAttributes (
+ Fvb,
+ &NewFvbAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Attributes = 0;
+
+ This->GetVolumeAttributes (
+ This,
+ Attributes
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of
+ data returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @return EFI_UNSUPPORTED Could not get.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Set information with InformationType into the requested firmware volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize Size of Buffer data.
+ @param Buffer A poniter to the data buffer to be set.
+
+ @retval EFI_UNSUPPORTED Could not set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h
new file mode 100644
index 0000000000..9c2788da32
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h
@@ -0,0 +1,773 @@
+/** @file
+ Common defines and definitions for a FwVolDxe driver.
+
+ Copyright (c) 2006 - 2010, 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.
+
+**/
+
+#ifndef _FWVOL_DRIVER_H_
+#define _FWVOL_DRIVER_H_
+
+#include <PiDxe.h>
+
+#include <Guid/FirmwareFileSystem2.h>
+#include <Protocol/SectionExtraction.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define FV_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '_')
+
+//
+// Define two helper macro to extract the Capability field or Status field in FVB
+// bit fields
+//
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP \
+ )
+
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
+
+#define MAX_FILES 32
+
+//
+// Used to caculate from address -> Lba
+//
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_LBA LbaIndex;
+ UINT8 *StartingAddress;
+ UINTN BlockLength;
+} LBA_ENTRY;
+
+//
+// Used to track free space in the Fv
+//
+typedef struct {
+ LIST_ENTRY Link;
+ UINT8 *StartingAddress;
+ UINTN Length;
+} FREE_SPACE_ENTRY;
+
+//
+// Used to track all non-deleted files
+//
+typedef struct {
+ LIST_ENTRY Link;
+ UINT8 *FfsHeader;
+} FFS_FILE_LIST_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *Key;
+ EFI_HANDLE Handle;
+
+ UINT8 ErasePolarity;
+ EFI_PHYSICAL_ADDRESS CachedFv;
+ LIST_ENTRY LbaHeader;
+ LIST_ENTRY FreeSpaceHeader;
+ LIST_ENTRY FfsFileListHeader;
+
+ FFS_FILE_LIST_ENTRY *CurrentFfsFile;
+
+} FV_DEVICE;
+
+#define FV_DEVICE_FROM_THIS(a) CR (a, FV_DEVICE, Fv, FV_DEVICE_SIGNATURE)
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS Successfully got volume attributes
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+/**
+ Sets current attributes for volume.
+
+ @param This Calling context
+ @param Attributes On input, FvAttributes is a pointer to
+ an EFI_FV_ATTRIBUTES containing the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. On
+ unsuccessful return, FvAttributes is not
+ modified and the firmware volume
+ settings are not changed.
+
+ @retval EFI_SUCCESS The requested firmware volume attributes
+ were set and the resulting
+ EFI_FV_ATTRIBUTES is returned in
+ FvAttributes.
+ @retval EFI_ACCESS_DENIED Atrribute is locked down.
+ @retval EFI_INVALID_PARAMETER Atrribute is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Indicates the calling context.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ );
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Indicates the calling context.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ );
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of
+ data returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @return EFI_UNSUPPORTED Could not get.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+
+/**
+ Set information with InformationType into the requested firmware volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize Size of Buffer data.
+ @param Buffer A poniter to the data buffer to be set.
+
+ @retval EFI_UNSUPPORTED Could not set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ );
+
+/**
+ Writes data beginning at Lba:Offset from FV. The write terminates either
+ when *NumBytes of data have been written, or when the firmware end is
+ reached. *NumBytes is updated to reflect the actual number of bytes
+ written.
+
+ @param FvDevice Cached Firmware Volume
+ @param Offset Offset in the block at which to begin write
+ @param NumBytes At input, indicates the requested write size.
+ At output, indicates the actual number of bytes written.
+ @param Buffer Buffer containing source data for the write.
+
+ @retval EFI_SUCCESS Data is successfully written into FV.
+ @return error Data is failed written.
+
+**/
+EFI_STATUS
+FvcWrite (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param Buffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ );
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ );
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFFSHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFFSFile (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ );
+
+/**
+ Locate the first file in FV.
+
+ @param FvDevice Cached FV image.
+ @param FirstFile Points to the got first FFS file header.
+
+ @retval EFI_NOT_FOUND No FFS file is found in FV.
+ @retval EFI_SUCCESS The first FFS file is got.
+
+**/
+EFI_STATUS
+FvLocateFirstFile (
+ IN FV_DEVICE *FvDevice,
+ OUT EFI_FFS_FILE_HEADER **FirstFile
+ );
+
+/**
+ Convert the Buffer Address to LBA Entry Address.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param LbaListEntry Pointer to the got LBA entry that contains the address.
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA entry is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2LbaEntry (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT LBA_ENTRY **LbaListEntry
+ );
+
+/**
+ Convert the Buffer Address to LBA Address & Offset.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param Lba Pointer to the gob Lba value
+ @param Offset Pointer to the got Offset
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA and Offset is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2Lba (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset
+ );
+
+/**
+ Set File State in the FfsHeader.
+
+ @param State File state to be set into FFS header.
+ @param FfsHeader Points to the FFS file header
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ Caculate the checksum for the FFS header.
+
+ @param FfsHeader FFS File Header which needs to caculate the checksum
+
+**/
+VOID
+SetHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Caculate the checksum for the FFS File.
+
+ @param FfsHeader FFS File Header which needs to caculate the checksum
+ @param ActualFileSize The whole Ffs File Length.
+
+**/
+VOID
+SetFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN UINTN ActualFileSize
+ );
+
+/**
+ Get the alignment value from File Attributes.
+
+ @param FfsAttributes FFS attribute
+
+ @return Alignment value.
+
+**/
+UINTN
+GetRequiredAlignment (
+ IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
+ );
+
+/**
+ Locate Pad File for writing, this is got from FV Cache.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size The required FFS file size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvLocatePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ );
+
+/**
+ Locate a suitable pad file for multiple file writing.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The totalsize that can hold these files.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitablePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ );
+
+/**
+ Locate a Free Space entry which can hold these files, including
+ meeting the alignment requirements.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The got total size that can hold these files.
+ @param FreeSpaceEntry The Free Space Entry that can hold these files.
+
+ @retval EFI_SUCCESS The free space entry is found.
+ @retval EFI_NOT_FOUND The free space entry can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitableFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FREE_SPACE_ENTRY **FreeSpaceEntry
+ );
+
+/**
+ Change FFS file header state and write to FV.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file header to be updated.
+ @param State FFS file state to be set.
+
+ @retval EFI_SUCCESS File state is writen into FV.
+ @retval others File state can't be writen into FV.
+
+**/
+EFI_STATUS
+UpdateHeaderBit (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_FFS_FILE_STATE State
+ );
+
+/**
+ Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
+
+ @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
+ @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
+
+**/
+VOID
+FvFileAttrib2FfsFileAttrib (
+ IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,
+ OUT UINT8 *FfsFileAttrib
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf
new file mode 100644
index 0000000000..fb1355b5a8
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf
@@ -0,0 +1,68 @@
+## @file
+# FwVolDxe driver produces Firmware Volume2 protocol with full services
+# (read/write, get/set) based on Firmware Volume Block protocol.
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FwVolDxe
+ FILE_GUID = 233C2592-1CEC-494a-A097-15DC96379777
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = FwVolDriverInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FwVolDriver.h
+ FwPadFile.c
+ Ffs.c
+ FwVolWrite.c
+ FwVolRead.c
+ FwVolAttrib.c
+ FwVol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiFirmwareVolumeTopFileGuid ## CONSUMES
+ gEfiFirmwareFileSystem2Guid ## CONSUMES
+
+[Protocols]
+ gEfiSectionExtractionProtocolGuid ## CONSUMES
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiFirmwareVolumeBlockProtocolGuid AND gEfiSectionExtractionProtocolGuid
+
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c
new file mode 100644
index 0000000000..b1b4a73a3c
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c
@@ -0,0 +1,580 @@
+/** @file
+ Implements functions to read firmware file.
+
+ Copyright (c) 2006 - 2010, 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"
+
+UINT8 mFvAttributes[] = { 0, 4, 7, 9, 10, 12, 15, 16 };
+
+/**
+ Convert the FFS File Attributes to FV File Attributes.
+
+ @param FfsAttributes The attributes of UINT8 type.
+
+ @return The attributes of EFI_FV_FILE_ATTRIBUTES
+
+**/
+EFI_FV_FILE_ATTRIBUTES
+FfsAttributes2FvFileAttributes (
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
+ ASSERT (FfsAttributes < 8);
+ return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes];
+}
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Indicates the calling context.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINTN *KeyValue;
+ LIST_ENTRY *Link;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ UINTN FileLength;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = This->GetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyValue = (UINTN *) Key;
+ FfsFileHeader = NULL;
+
+ //
+ // Check if read operation is enabled
+ //
+ if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
+ //
+ // File type needs to be in 0 - 0x0D
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ do {
+ if (*KeyValue == 0) {
+ //
+ // Search for 1st matching file
+ //
+ Link = &FvDevice->FfsFileListHeader;
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN) FfsFileEntry;
+
+ //
+ // we ignore pad files
+ //
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ continue;
+ }
+
+ if (*FileType == 0) {
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ break;
+ }
+
+ } else {
+ //
+ // Getting link from last Ffs
+ //
+ Link = (LIST_ENTRY *) (*KeyValue);
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN) FfsFileEntry;
+
+ //
+ // we ignore pad files
+ //
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ continue;
+ }
+
+ if (*FileType == EFI_FV_FILETYPE_ALL) {
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ break;
+ }
+ }
+ } while (Link->ForwardLink != &FvDevice->FfsFileListHeader);
+
+ //
+ // Cache this file entry
+ //
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ *FileType = FfsFileHeader->Type;
+ CopyGuid (NameGuid, &FfsFileHeader->Name);
+ *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
+
+ FileLength = *(UINT32 *) FfsFileHeader->Size & 0x00FFFFFF;
+
+ //
+ // we need to substract the header size
+ //
+ *Size = FileLength - sizeof (EFI_FFS_FILE_HEADER);
+
+ if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
+ //
+ // specially deal with VTF file
+ //
+ UINT8 *SrcPtr;
+ UINT32 Tmp;
+
+ SrcPtr = (UINT8 *) FfsFileHeader;
+ SrcPtr += sizeof (EFI_FFS_FILE_HEADER);
+
+ while (*Size >= 4) {
+ Tmp = *(UINT32 *) SrcPtr;
+ if (Tmp == 0) {
+ SrcPtr += 4;
+ (*Size) -= 4;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ UINTN Key;
+ EFI_GUID SearchNameGuid;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FV_FILETYPE LocalFoundType;
+ EFI_FV_FILE_ATTRIBUTES LocalAttributes;
+ UINTN FileSize;
+ UINT8 *SrcPtr;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT8 *FileBuffer;
+
+ if (NULL == This || NULL == NameGuid) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = This->GetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // First check to see that FV is enabled for reads...
+ //
+ if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ FfsHeader = NULL;
+
+ //
+ // Check if the file was read last time.
+ //
+ FfsFileEntry = FvDevice->CurrentFfsFile;
+
+ if (FfsFileEntry != NULL) {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+ }
+
+ if ((FfsFileEntry == NULL) || (!CompareGuid (&FfsHeader->Name, NameGuid))) {
+ //
+ // If not match or no file cached, search this file
+ //
+ Key = 0;
+ do {
+ LocalFoundType = 0;
+ Status = This->GetNextFile (
+ This,
+ &Key,
+ &LocalFoundType,
+ &SearchNameGuid,
+ &LocalAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ } while (!CompareGuid (&SearchNameGuid, NameGuid));
+
+ //
+ // Get file entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
+
+ //
+ // Update the cache
+ //
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+
+ } else {
+ //
+ // Get File Size of the cached file
+ //
+ FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);
+ }
+ //
+ // Get file info
+ //
+ *FoundType = FfsHeader->Type;
+ *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
+ *AuthenticationStatus = 0;
+
+ //
+ // If Buffer is NULL, we only want to get some information
+ //
+ if (Buffer == NULL) {
+ *BufferSize = FileSize;
+ return EFI_SUCCESS;
+ }
+
+ SrcPtr = (UINT8 *) FfsHeader;
+ SrcPtr += sizeof (EFI_FFS_FILE_HEADER);
+
+ if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
+ //
+ // specially deal with VTF file
+ //
+ UINT32 Tmp;
+
+ while (FileSize >= 4) {
+ Tmp = *(UINT32 *) SrcPtr;
+ if (Tmp == 0) {
+ SrcPtr += 4;
+ FileSize -= 4;
+ } else {
+ break;
+ }
+ }
+ }
+ //
+ // If we drop out of the above loop, we've found the correct file header...
+ //
+ if (*Buffer == NULL) {
+ FileBuffer = AllocateCopyPool (FileSize, SrcPtr);
+ if (FileBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *BufferSize = FileSize;
+ *Buffer = FileBuffer;
+
+ return EFI_SUCCESS;
+ }
+ //
+ // If the user's buffer is smaller than the file size, then copy as much
+ // as we can and return an appropriate status.
+ //
+ if (FileSize > *BufferSize) {
+ CopyMem (*Buffer, SrcPtr, *BufferSize);
+ *BufferSize = FileSize;
+ return EFI_WARN_BUFFER_TOO_SMALL;
+ }
+ //
+ // User's buffer size is ok, so copy the entire file to their buffer.
+ //
+ *BufferSize = FileSize;
+ CopyMem (*Buffer, SrcPtr, *BufferSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ UINT8 *FileBuffer;
+ EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
+ UINTN StreamHandle;
+
+ if (NULL == This || NULL == NameGuid || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = This->GetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // First check to see that FV is enabled for reads...
+ //
+ if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Read the whole file into buffer
+ //
+ FileBuffer = NULL;
+ Status = This->ReadFile (
+ This,
+ NameGuid,
+ (VOID **) &FileBuffer,
+ &FileSize,
+ &FileType,
+ &FileAttributes,
+ AuthenticationStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check to see that the file actually HAS sections before we go any further.
+ //
+ if (FileType == EFI_FV_FILETYPE_RAW) {
+ FreePool (FileBuffer);
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Located the protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSectionExtractionProtocolGuid,
+ NULL,
+ (VOID **) &Sep
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ Status = Sep->OpenSectionStream (
+ Sep,
+ FileSize,
+ FileBuffer,
+ &StreamHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ if (SectionType == 0) {
+ //
+ // We need the whole section stream
+ //
+ Status = Sep->GetSection (
+ Sep,
+ StreamHandle,
+ NULL,
+ NULL,
+ 0,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus
+ );
+ } else {
+ Status = Sep->GetSection (
+ Sep,
+ StreamHandle,
+ &SectionType,
+ NULL,
+ SectionInstance,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus
+ );
+ }
+ //
+ // Handle AuthenticationStatus if necessary
+ //
+ Sep->CloseSectionStream (Sep, StreamHandle);
+
+ FreePool (FileBuffer);
+
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
new file mode 100644
index 0000000000..5c7e8abf75
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
@@ -0,0 +1,1591 @@
+/** @file
+ Implements write 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"
+
+/**
+ Caculate the checksum for the FFS header.
+
+ @param FfsHeader FFS File Header which needs to caculate the checksum
+
+**/
+VOID
+SetHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE State;
+ UINT8 HeaderChecksum;
+ UINT8 FileChecksum;
+
+ //
+ // The state and the File checksum are not included
+ //
+ State = FfsHeader->State;
+ FfsHeader->State = 0;
+
+ FileChecksum = FfsHeader->IntegrityCheck.Checksum.File;
+ FfsHeader->IntegrityCheck.Checksum.File = 0;
+
+ FfsHeader->IntegrityCheck.Checksum.Header = 0;
+
+ HeaderChecksum = CalculateSum8 (
+ (UINT8 *)FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+
+ FfsHeader->IntegrityCheck.Checksum.Header = (UINT8) (~HeaderChecksum + 1);
+
+ FfsHeader->State = State;
+ FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;
+
+ return ;
+}
+
+/**
+ Caculate the checksum for the FFS File.
+
+ @param FfsHeader FFS File Header which needs to caculate the checksum
+ @param ActualFileSize The whole Ffs File Length.
+
+**/
+VOID
+SetFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN UINTN ActualFileSize
+ )
+{
+ EFI_FFS_FILE_STATE State;
+ UINT8 FileChecksum;
+
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
+ //
+ // The file state is not included
+ //
+ State = FfsHeader->State;
+ FfsHeader->State = 0;
+
+ FfsHeader->IntegrityCheck.Checksum.File = 0;
+
+ //
+ // File checksum
+ //
+ FileChecksum = CalculateSum8 (
+ (UINT8 *)(FfsHeader + 1),
+ ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)
+ );
+
+ FfsHeader->IntegrityCheck.Checksum.File = (UINT8) (~FileChecksum + 1);
+
+ FfsHeader->State = State;
+
+ } else {
+
+ FfsHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+
+ }
+
+ return ;
+}
+
+/**
+ Get the alignment value from File Attributes.
+
+ @param FfsAttributes FFS attribute
+
+ @return Alignment value.
+
+**/
+UINTN
+GetRequiredAlignment (
+ IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ UINTN AlignmentValue;
+
+ AlignmentValue = FfsAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;
+
+ if (AlignmentValue <= 3) {
+ return 0x08;
+ }
+
+ if (AlignmentValue > 16) {
+ //
+ // Anyway, we won't reach this code
+ //
+ return 0x08;
+ }
+
+ return (UINTN)1 << AlignmentValue;
+
+}
+
+/**
+ Caculate the leading Pad file size to meet the alignment requirement.
+
+ @param FvDevice Cached Firmware Volume.
+ @param StartAddress The starting address to write the FFS File.
+ @param RequiredAlignment FFS File Data alignment requirement.
+
+ @return The required Pad File Size.
+
+**/
+UINTN
+CaculatePadFileSize (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINTN RequiredAlignment
+ )
+{
+ UINTN DataStartPos;
+ UINTN RelativePos;
+ UINTN PadSize;
+
+ DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER);
+ RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv;
+
+ PadSize = 0;
+
+ while ((RelativePos & (RequiredAlignment - 1)) != 0) {
+ RelativePos++;
+ PadSize++;
+ }
+ //
+ // If padsize is 0, no pad file needed;
+ // If padsize is great than 24, then pad file can be created
+ //
+ if ((PadSize == 0) || (PadSize >= sizeof (EFI_FFS_FILE_HEADER))) {
+ return PadSize;
+ }
+
+ //
+ // Perhaps following method can save space
+ //
+ RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv + sizeof (EFI_FFS_FILE_HEADER);
+ PadSize = sizeof (EFI_FFS_FILE_HEADER);
+
+ while ((RelativePos & (RequiredAlignment - 1)) != 0) {
+ RelativePos++;
+ PadSize++;
+ }
+
+ return PadSize;
+}
+
+/**
+ Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
+
+ @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
+ @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
+
+**/
+VOID
+FvFileAttrib2FfsFileAttrib (
+ IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,
+ OUT UINT8 *FfsFileAttrib
+ )
+{
+ UINT8 FvFileAlignment;
+ UINT8 FfsFileAlignment;
+
+ FvFileAlignment = (UINT8) (FvFileAttrib & EFI_FV_FILE_ATTRIB_ALIGNMENT);
+ FfsFileAlignment = 0;
+
+ switch (FvFileAlignment) {
+ case 0:
+ //
+ // fall through
+ //
+ case 1:
+ //
+ // fall through
+ //
+ case 2:
+ //
+ // fall through
+ //
+ case 3:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 0;
+ break;
+
+ case 4:
+ //
+ // fall through
+ //
+ case 5:
+ //
+ // fall through
+ //
+ case 6:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 1;
+ break;
+
+ case 7:
+ //
+ // fall through
+ //
+ case 8:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 2;
+ break;
+
+ case 9:
+ FfsFileAlignment = 3;
+ break;
+
+ case 10:
+ //
+ // fall through
+ //
+ case 11:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 4;
+ break;
+
+ case 12:
+ //
+ // fall through
+ //
+ case 13:
+ //
+ // fall through
+ //
+ case 14:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 5;
+ break;
+
+ case 15:
+ FfsFileAlignment = 6;
+ break;
+
+ case 16:
+ FfsFileAlignment = 7;
+ break;
+ }
+
+ *FfsFileAttrib = (UINT8) (FfsFileAlignment << 3);
+
+ return ;
+}
+
+/**
+ Locate a free space entry that can hold this FFS file.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size The FFS file size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The free space entry is found.
+ @retval EFI_NOT_FOUND The free space entry can't be found.
+
+**/
+EFI_STATUS
+FvLocateFreeSpaceEntry (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT FREE_SPACE_ENTRY **FreeSpaceEntry
+ )
+{
+ FREE_SPACE_ENTRY *FreeSpaceListEntry;
+ LIST_ENTRY *Link;
+ UINTN PadFileSize;
+
+ Link = FvDevice->FreeSpaceHeader.ForwardLink;
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
+
+ //
+ // Loop the free space entry list to find one that can hold the
+ // required the file size
+ //
+ while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
+ PadFileSize = CaculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,
+ RequiredAlignment
+ );
+ if (FreeSpaceListEntry->Length >= Size + PadFileSize) {
+ *FreeSpaceEntry = FreeSpaceListEntry;
+ *PadSize = PadFileSize;
+ return EFI_SUCCESS;
+ }
+
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Locate a free space that can hold this file.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size On input, it is the required size.
+ On output, it is the actual size of free space.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param StartingAddress The starting address of the Free Space Entry
+ that meets the requirement.
+
+ @retval EFI_SUCCESS The free space is found.
+ @retval EFI_NOT_FOUND The free space can't be found.
+
+**/
+EFI_STATUS
+FvLocateFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN OUT UINTN *Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT EFI_PHYSICAL_ADDRESS *StartingAddress
+ )
+{
+ EFI_STATUS Status;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+
+ //
+ // First find the free space entry
+ //
+ Status = FvLocateFreeSpaceEntry (
+ FvDevice,
+ *Size,
+ RequiredAlignment,
+ PadSize,
+ &FreeSpaceEntry
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Size = FreeSpaceEntry->Length;
+ *StartingAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locate Pad File for writing, this is got from FV Cache.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size The required FFS file size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvLocatePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ )
+{
+ FFS_FILE_LIST_ENTRY *FileEntry;
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINTN FileLength;
+ UINTN PadAreaLength;
+ UINTN PadFileSize;
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
+
+ //
+ // travel through the whole file list to get the pad file entry
+ //
+ while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
+ FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
+
+ if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
+ //
+ // we find one valid pad file, check its free area length
+ //
+ FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;
+ PadAreaLength = FileLength - sizeof (EFI_FFS_FILE_HEADER);
+
+ PadFileSize = CaculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + sizeof (EFI_FFS_FILE_HEADER),
+ RequiredAlignment
+ );
+ if (PadAreaLength >= (Size + PadFileSize)) {
+ *PadSize = PadFileSize;
+ *PadFileEntry = FileEntry;
+ return EFI_SUCCESS;
+ }
+ }
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate a suitable pad file for multiple file writing.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The totalsize that can hold these files.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitablePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ )
+{
+ FFS_FILE_LIST_ENTRY *FileEntry;
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINTN FileLength;
+ UINTN PadAreaLength;
+ UINTN TotalSize;
+ UINTN Index;
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
+
+ //
+ // travel through the whole file list to get the pad file entry
+ //
+ while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
+ FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
+
+ if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
+ //
+ // we find one valid pad file, check its length
+ //
+ FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;
+ PadAreaLength = FileLength - sizeof (EFI_FFS_FILE_HEADER);
+ TotalSize = 0;
+
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ PadSize[Index] = CaculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + sizeof (EFI_FFS_FILE_HEADER) + TotalSize,
+ RequiredAlignment[Index]
+ );
+ TotalSize += PadSize[Index];
+ TotalSize += BufferSize[Index];
+
+ if (TotalSize > PadAreaLength) {
+ break;
+ }
+ }
+
+ if (PadAreaLength >= TotalSize) {
+ *PadFileEntry = FileEntry;
+ *TotalSizeNeeded = TotalSize;
+ return EFI_SUCCESS;
+ }
+ }
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate a Free Space entry which can hold these files, including
+ meeting the alignment requirements.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The got total size that can hold these files.
+ @param FreeSpaceEntry The Free Space Entry that can hold these files.
+
+ @retval EFI_SUCCESS The free space entry is found.
+ @retval EFI_NOT_FOUND The free space entry can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitableFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FREE_SPACE_ENTRY **FreeSpaceEntry
+ )
+{
+ FREE_SPACE_ENTRY *FreeSpaceListEntry;
+ LIST_ENTRY *Link;
+ UINTN TotalSize;
+ UINTN Index;
+ UINT8 *StartAddr;
+
+ Link = FvDevice->FreeSpaceHeader.ForwardLink;
+
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
+
+ while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
+ TotalSize = 0;
+ StartAddr = FreeSpaceListEntry->StartingAddress;
+
+ //
+ // Caculate the totalsize we need
+ //
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ //
+ // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
+ // have had its leading pad file.
+ //
+ PadSize[Index] = CaculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,
+ RequiredAlignment[Index]
+ );
+
+ TotalSize += PadSize[Index];
+ TotalSize += BufferSize[Index];
+
+ if (TotalSize > FreeSpaceListEntry->Length) {
+ break;
+ }
+ }
+
+ if (FreeSpaceListEntry->Length >= TotalSize) {
+ *FreeSpaceEntry = FreeSpaceListEntry;
+ *TotalSizeNeeded = TotalSize;
+ return EFI_SUCCESS;
+ }
+
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Calculate the length of the remaining space in FV.
+
+ @param FvDevice Cached Firmware Volume
+ @param Offset Current offset to FV base address.
+ @param Lba LBA number for the current offset.
+ @param LOffset Offset in block for the current offset.
+
+ @return the length of remaining space.
+
+**/
+UINTN
+CalculateRemainingLength (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Offset,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *LOffset
+ )
+{
+ LIST_ENTRY *Link;
+ LBA_ENTRY *LbaEntry;
+ UINTN Count;
+
+ Count = 0;
+ *Lba = 0;
+ Link = FvDevice->LbaHeader.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+ if (Count > Offset) {
+ break;
+ }
+
+ Count += LbaEntry->BlockLength;
+ (*Lba)++;
+ Link = LbaEntry->Link.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+ }
+
+ if (Count <= Offset) {
+ return 0;
+ }
+
+ Link = LbaEntry->Link.BackLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ (*Lba)--;
+ *LOffset = (UINTN) (LbaEntry->BlockLength - (Count - Offset));
+
+ Count = 0;
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+
+ Count += LbaEntry->BlockLength;
+
+ Link = LbaEntry->Link.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+ }
+
+ Count -= *LOffset;
+
+ return Count;
+}
+
+/**
+ Writes data beginning at Lba:Offset from FV. The write terminates either
+ when *NumBytes of data have been written, or when the firmware end is
+ reached. *NumBytes is updated to reflect the actual number of bytes
+ written.
+
+ @param FvDevice Cached Firmware Volume
+ @param Offset Offset in the block at which to begin write
+ @param NumBytes At input, indicates the requested write size.
+ At output, indicates the actual number of bytes written.
+ @param Buffer Buffer containing source data for the write.
+
+ @retval EFI_SUCCESS Data is successfully written into FV.
+ @return error Data is failed written.
+
+**/
+EFI_STATUS
+FvcWrite (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_LBA Lba;
+ UINTN LOffset;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN RemainingLength;
+ UINTN WriteLength;
+ UINT8 *TmpBuffer;
+
+ LOffset = 0;
+ RemainingLength = CalculateRemainingLength (FvDevice, Offset, &Lba, &LOffset);
+ if ((UINTN) (*NumBytes) > RemainingLength) {
+ *NumBytes = (UINTN) RemainingLength;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fvb = FvDevice->Fvb;
+
+ Status = Fvb->GetAttributes (
+ Fvb,
+ &FvbAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((FvbAttributes & EFI_FV2_WRITE_STATUS) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ RemainingLength = *NumBytes;
+ WriteLength = RemainingLength;
+ TmpBuffer = Buffer;
+
+ do {
+ Status = Fvb->Write (
+ Fvb,
+ Lba,
+ LOffset,
+ &WriteLength,
+ TmpBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Status == EFI_BAD_BUFFER_SIZE) {
+ Lba++;
+ LOffset = 0;
+ TmpBuffer += WriteLength;
+ RemainingLength -= WriteLength;
+ WriteLength = (UINTN) RemainingLength;
+
+ continue;
+ } else {
+ return Status;
+ }
+ } while (1);
+
+Done:
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new FFS file into Firmware Volume device.
+
+ @param FvDevice Cached Firmware Volume.
+ @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 FFS fle is added into FV.
+ @retval EFI_INVALID_PARAMETER File type is not valid.
+ @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
+ @retval EFI_NOT_FOUND FV has no enough space for the added file.
+
+**/
+EFI_STATUS
+FvCreateNewFile (
+ 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
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_PHYSICAL_ADDRESS BufferPtr;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+ UINTN StateOffset;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ UINTN RequiredAlignment;
+ UINTN PadFileSize;
+ FFS_FILE_LIST_ENTRY *PadFileEntry;
+ EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+
+ //
+ // File Type: 0x0E~0xE0 are reserved
+ //
+ if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // First find a free space that can hold this image.
+ // Check alignment, FFS at least must be aligned at 8-byte boundry
+ //
+ RequiredAlignment = GetRequiredAlignment (FileAttributes);
+
+ Status = FvLocateFreeSpaceEntry (
+ FvDevice,
+ BufferSize,
+ RequiredAlignment,
+ &PadFileSize,
+ &FreeSpaceEntry
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Maybe we need to find a PAD file that can hold this image
+ //
+ Status = FvCreateNewFileInsidePadFile (
+ FvDevice,
+ FfsFileBuffer,
+ BufferSize,
+ ActualFileSize,
+ FileName,
+ FileType,
+ FileAttributes
+ );
+
+ return Status;
+ }
+
+ BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
+
+ //
+ // If we need a leading PAD File, create it first.
+ //
+ if (PadFileSize != 0) {
+ Status = FvCreatePadFileInFreeSpace (
+ FvDevice,
+ FreeSpaceEntry,
+ PadFileSize - sizeof (EFI_FFS_FILE_HEADER),
+ &PadFileEntry
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Maybe we create a pad file, so re-get the free space starting address
+ // and length
+ //
+ BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
+
+ //
+ // File creation step 1: Allocate File Header,
+ // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
+ // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
+ //
+ FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+
+ //
+ // update Free Space Entry, now need to substract the EFI_FFS_FILE_HEADER
+ //
+ FreeSpaceEntry->StartingAddress += sizeof (EFI_FFS_FILE_HEADER);
+ FreeSpaceEntry->Length -= sizeof (EFI_FFS_FILE_HEADER);
+
+ CopyGuid (&FileHeader->Name, FileName);
+ FileHeader->Type = FileType;
+
+ //
+ // Convert FvFileAttribute to FfsFileAttributes
+ //
+ FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
+
+ FileHeader->Attributes = TmpFileAttribute;
+
+ //
+ // File size is including the FFS File Header.
+ //
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ *(UINT32 *) FileHeader->Size |= ActualFileSize;
+
+ SetHeaderChecksum (FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_HEADER);
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ (UINT8 *) FileHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+
+ //
+ // end of step 1
+ //
+ // File creation step 2:
+ // MARK EFI_FILE_HEADER_VALID bit to TRUE,
+ // Write IntegrityCheck.File, File Data
+ //
+ SetFileState (EFI_FILE_HEADER_VALID, FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+
+ //
+ // update Free Space Entry, now need to substract the file data length
+ //
+ FreeSpaceEntry->StartingAddress += (BufferSize - sizeof (EFI_FFS_FILE_HEADER));
+ FreeSpaceEntry->Length -= (BufferSize - sizeof (EFI_FFS_FILE_HEADER));
+
+ //
+ // Caculate File Checksum
+ //
+ SetFileChecksum (FileHeader, ActualFileSize);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+
+ NumBytesWritten = BufferSize;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ FfsFileBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // each time write block successfully, write also to cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FfsFileBuffer,
+ NumBytesWritten
+ );
+
+ //
+ // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
+ //
+ SetFileState (EFI_FILE_DATA_VALID, FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+
+ //
+ // 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) BufferPtr;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+
+ //
+ // Set cache file to this file
+ //
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update a File, so after successful update, there are 2 files existing
+ in FV, one is marked for deleted, and another one is valid.
+
+ @param FvDevice Cached Firmware Volume.
+ @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 NewFileType The FFS File Type.
+ @param NewFileAttributes The Attributes of the FFS File to be created.
+
+ @retval EFI_SUCCESS FFS fle is updated into FV.
+ @retval EFI_INVALID_PARAMETER File type is not valid.
+ @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
+ @retval EFI_NOT_FOUND FV has no enough space for the added file.
+ FFS with same file name is not found in FV.
+
+**/
+EFI_STATUS
+FvUpdateFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINT8 *FfsFileBuffer,
+ IN UINTN BufferSize,
+ IN UINTN ActualFileSize,
+ IN EFI_GUID *FileName,
+ IN EFI_FV_FILETYPE NewFileType,
+ IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINTN NumBytesWritten;
+ EFI_FV_FILETYPE OldFileType;
+ EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
+ UINTN OldFileSize;
+ EFI_FFS_FILE_HEADER *OldFileHeader;
+ UINTN OldOffset;
+ UINTN OldStateOffset;
+ FFS_FILE_LIST_ENTRY *OldFfsFileEntry;
+ UINTN Key;
+ EFI_GUID FileNameGuid;
+
+ Fv = &FvDevice->Fv;
+
+ //
+ // Step 1, find old file,
+ // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
+ //
+
+ //
+ // Check if the file was read last time.
+ //
+ OldFileHeader = NULL;
+ OldFfsFileEntry = FvDevice->CurrentFfsFile;
+
+ if (OldFfsFileEntry != NULL) {
+ OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
+ }
+
+ if ((OldFfsFileEntry == NULL) || (!CompareGuid (&OldFileHeader->Name, FileName))) {
+ Key = 0;
+ do {
+ OldFileType = 0;
+ Status = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &OldFileType,
+ &FileNameGuid,
+ &OldFileAttributes,
+ &OldFileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } while (!CompareGuid (&FileNameGuid, FileName));
+
+ //
+ // Get FfsFileEntry from the search key
+ //
+ OldFfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
+
+ //
+ // Double check file state before being ready to be removed
+ //
+ OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
+ } else {
+ //
+ // Mark the cache file to invalid
+ //
+ FvDevice->CurrentFfsFile = NULL;
+ }
+ //
+ // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
+ //
+ SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
+
+ OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
+ OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ OldStateOffset,
+ &NumBytesWritten,
+ &OldFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if failed, write the bit back in the cache, its XOR operation.
+ //
+ SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
+
+ return Status;
+ }
+
+ //
+ // Step 2, Create New Files
+ //
+ Status = FvCreateNewFile (
+ FvDevice,
+ FfsFileBuffer,
+ BufferSize,
+ ActualFileSize,
+ FileName,
+ NewFileType,
+ NewFileAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If successfully, remove this file entry,
+ // although delete file may fail.
+ //
+ (OldFfsFileEntry->Link.BackLink)->ForwardLink = OldFfsFileEntry->Link.ForwardLink;
+ (OldFfsFileEntry->Link.ForwardLink)->BackLink = OldFfsFileEntry->Link.BackLink;
+ FreePool (OldFfsFileEntry);
+
+ //
+ // Step 3: Delete old files,
+ // by marking EFI_FILE_DELETED to TRUE
+ //
+ SetFileState (EFI_FILE_DELETED, OldFileHeader);
+
+ OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
+ OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ OldStateOffset,
+ &NumBytesWritten,
+ &OldFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if failed, write the bit back in the cache, its XOR operation.
+ //
+ SetFileState (EFI_FILE_DELETED, OldFileHeader);
+
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Deleted a given file from FV device.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NameGuid The FFS File Name.
+
+ @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
+ @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
+
+**/
+EFI_STATUS
+FvDeleteFile (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_GUID *NameGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN Key;
+ EFI_GUID FileNameGuid;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINTN Offset;
+ UINTN StateOffset;
+ UINTN NumBytesWritten;
+
+ Fv = &FvDevice->Fv;
+
+ //
+ // Check if the file was read last time.
+ //
+ FileHeader = NULL;
+ FfsFileEntry = FvDevice->CurrentFfsFile;
+
+ if (FfsFileEntry != NULL) {
+ FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+ }
+
+ if ((FfsFileEntry == NULL) || (!CompareGuid (&FileHeader->Name, NameGuid))) {
+ //
+ // Next search for the file using GetNextFile
+ //
+ Key = 0;
+ do {
+ FileType = 0;
+ Status = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &FileType,
+ &FileNameGuid,
+ &FileAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } while (!CompareGuid (&FileNameGuid, NameGuid));
+
+ //
+ // Get FfsFileEntry from the search key
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
+
+ //
+ // Double check file state before being ready to be removed
+ //
+ FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+ } else {
+ //
+ // Mark the cache file to NULL
+ //
+ FvDevice->CurrentFfsFile = NULL;
+ }
+
+ FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
+
+ if (FileState == EFI_FILE_HEADER_INVALID) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (FileState == EFI_FILE_DELETED) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Delete File: Mark EFI_FILE_DELETED to TRUE
+ //
+ SetFileState (EFI_FILE_DELETED, FileHeader);
+
+ Offset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if failed, write the bit back in the cache, its XOR operation.
+ //
+ SetFileState (EFI_FILE_DELETED, FileHeader);
+
+ return Status;
+ }
+ //
+ // If successfully, remove this file entry
+ //
+ FvDevice->CurrentFfsFile = NULL;
+
+ (FfsFileEntry->Link.BackLink)->ForwardLink = FfsFileEntry->Link.ForwardLink;
+ (FfsFileEntry->Link.ForwardLink)->BackLink = FfsFileEntry->Link.BackLink;
+ FreePool (FfsFileEntry);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Indicates the calling context.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index1;
+ UINTN Index2;
+ UINT8 *FileBuffer;
+ UINTN BufferSize;
+ UINTN ActualSize;
+ UINT8 ErasePolarity;
+ FV_DEVICE *FvDevice;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN Size;
+ BOOLEAN CreateNewFile[MAX_FILES];
+ UINTN NumDelete;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ UINT32 AuthenticationStatus;
+
+ if (NumberOfFiles > MAX_FILES) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ SetMem (CreateNewFile, NumberOfFiles, TRUE);
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ //
+ // First check the volume attributes.
+ //
+ Status = This->GetVolumeAttributes (
+ This,
+ &FvAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Can we have write right?
+ //
+ if ((FvAttributes & EFI_FV2_WRITE_STATUS) != 0) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ ErasePolarity = FvDevice->ErasePolarity;
+
+ //
+ // Loop for all files
+ //
+ NumDelete = 0;
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ if (FileData[Index1].BufferSize == 0) {
+ //
+ // Here we will delete this file
+ //
+ Status = This->ReadFile (
+ This,
+ FileData[Index1].NameGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ NumDelete++;
+ } else {
+ return Status;
+ }
+ }
+
+ if (FileData[Index1].Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
+ // "Standard firmware file system services will not return the handle of any pad files,
+ // nor will they permit explicit creation of such files."
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if ((NumDelete != NumberOfFiles) && (NumDelete != 0)) {
+ //
+ // A delete was request with a multiple file write
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NumDelete == NumberOfFiles) {
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ //
+ // Delete Files
+ //
+ Status = FvDeleteFile (FvDevice, FileData[Index1].NameGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ Status = This->ReadFile (
+ This,
+ FileData[Index1].NameGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ CreateNewFile[Index1] = FALSE;
+ } else if (Status == EFI_NOT_FOUND) {
+ CreateNewFile[Index1] = TRUE;
+ } else {
+ return Status;
+ }
+ //
+ // Checking alignment
+ //
+ if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) {
+ UINT8 FFSAlignmentValue;
+ UINT8 FvAlignmentValue;
+
+ FFSAlignmentValue = (UINT8) (FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT);
+ FvAlignmentValue = (UINT8) (((UINT32) (FvAttributes & EFI_FV2_ALIGNMENT)) >> 16);
+
+ if (FFSAlignmentValue > FvAlignmentValue) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if ((WritePolicy != EFI_FV_RELIABLE_WRITE) && (WritePolicy != EFI_FV_UNRELIABLE_WRITE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Checking the reliable write is supported by FV
+ //
+
+ if ((WritePolicy == EFI_FV_RELIABLE_WRITE) && (NumberOfFiles > 1)) {
+ //
+ // Only for multiple files, reliable write is meaningful
+ //
+ Status = FvCreateMultipleFiles (
+ FvDevice,
+ NumberOfFiles,
+ FileData,
+ CreateNewFile
+ );
+
+ return Status;
+ }
+
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ //
+ // Making Buffersize QWORD boundry, and add file tail.
+ //
+ ActualSize = FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER);
+ BufferSize = ActualSize;
+
+ while ((BufferSize & 0x07) != 0) {
+ BufferSize++;
+ }
+
+ FileBuffer = AllocateZeroPool (BufferSize);
+ if (FileBuffer == NULL) {
+ return Status;
+ }
+ //
+ // Copy File Data into FileBuffer
+ //
+ CopyMem (
+ FileBuffer + sizeof (EFI_FFS_FILE_HEADER),
+ FileData[Index1].Buffer,
+ FileData[Index1].BufferSize
+ );
+
+ if (ErasePolarity == 1) {
+ //
+ // Fill the file header and padding byte with Erase Byte
+ //
+ for (Index2 = 0; Index2 < sizeof (EFI_FFS_FILE_HEADER); Index2++) {
+ FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
+ }
+
+ for (Index2 = ActualSize; Index2 < BufferSize; Index2++) {
+ FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
+ }
+ }
+
+ if (CreateNewFile[Index1]) {
+ Status = FvCreateNewFile (
+ FvDevice,
+ FileBuffer,
+ BufferSize,
+ ActualSize,
+ FileData[Index1].NameGuid,
+ FileData[Index1].Type,
+ FileData[Index1].FileAttributes
+ );
+ } else {
+ Status = FvUpdateFile (
+ FvDevice,
+ FileBuffer,
+ BufferSize,
+ ActualSize,
+ FileData[Index1].NameGuid,
+ FileData[Index1].Type,
+ FileData[Index1].FileAttributes
+ );
+ }
+
+ FreePool (FileBuffer);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}