From c2df8e13f68ab18f96874cadc0a3dfada67a7e7c Mon Sep 17 00:00:00 2001 From: jljusten Date: Thu, 1 Sep 2011 19:57:08 +0000 Subject: [PATCH] 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 --- .../IntelFrameworkModulePkg.dsc | 1 + .../Universal/FirmwareVolume/FwVolDxe/Ffs.c | 625 +++++++ .../FirmwareVolume/FwVolDxe/FwPadFile.c | 1032 +++++++++++ .../Universal/FirmwareVolume/FwVolDxe/FwVol.c | 651 +++++++ .../FirmwareVolume/FwVolDxe/FwVolAttrib.c | 220 +++ .../FirmwareVolume/FwVolDxe/FwVolDriver.h | 773 ++++++++ .../FirmwareVolume/FwVolDxe/FwVolDxe.inf | 68 + .../FirmwareVolume/FwVolDxe/FwVolRead.c | 580 ++++++ .../FirmwareVolume/FwVolDxe/FwVolWrite.c | 1591 +++++++++++++++++ 9 files changed, 5541 insertions(+) create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc index bd26806d21..7eaac50eaf 100644 --- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc +++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc @@ -162,6 +162,7 @@ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf + IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf [Components.IA32,Components.X64] IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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.
+ + 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.
+ + 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; +} -- 2.39.2