summaryrefslogtreecommitdiff
path: root/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c')
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c1586
1 files changed, 1586 insertions, 0 deletions
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
new file mode 100644
index 0000000000..99385e0f57
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
@@ -0,0 +1,1586 @@
+/** @file
+ Implements write firmware file.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+/**
+ Calculate the checksum for the FFS header.
+
+ @param FfsHeader FFS File Header which needs to calculate the checksum
+
+**/
+VOID
+SetHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE State;
+ 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;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER2)
+ );
+ } else {
+ FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+ }
+
+ FfsHeader->State = State;
+ FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;
+
+ return ;
+}
+
+/**
+ Calculate the checksum for the FFS File.
+
+ @param FfsHeader FFS File Header which needs to calculate the checksum
+ @param ActualFileSize The whole Ffs File Length.
+
+**/
+VOID
+SetFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN UINTN ActualFileSize
+ )
+{
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
+
+ FfsHeader->IntegrityCheck.Checksum.File = 0;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2),
+ ActualFileSize - sizeof (EFI_FFS_FILE_HEADER2)
+ );
+ } else {
+ FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER),
+ ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)
+ );
+ }
+
+ } 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;
+
+}
+
+/**
+ Calculate 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 BufferSize The FFS File Buffer Size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+
+ @return The required Pad File Size.
+
+**/
+UINTN
+CalculatePadFileSize (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINTN BufferSize,
+ IN UINTN RequiredAlignment
+ )
+{
+ UINTN DataStartPos;
+ UINTN RelativePos;
+ UINTN PadSize;
+
+ if (BufferSize > 0x00FFFFFF) {
+ DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ 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 = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,
+ Size,
+ 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 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 PadAreaLength;
+ UINTN PadFileSize;
+ UINTN HeaderSize;
+
+ 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
+ //
+ if (IS_FFS_FILE2 (FileHeader)) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
+ }
+
+ PadFileSize = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize,
+ Size,
+ 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 PadAreaLength;
+ UINTN TotalSize;
+ UINTN Index;
+ UINTN HeaderSize;
+
+ 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
+ //
+ if (IS_FFS_FILE2 (FileHeader)) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
+ }
+ TotalSize = 0;
+
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ PadSize[Index] = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize + TotalSize,
+ BufferSize[Index],
+ 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;
+
+ //
+ // Calculate 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] = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,
+ BufferSize[Index],
+ 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;
+ UINTN HeaderSize;
+
+ //
+ // 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 boundary
+ //
+ 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;
+ if (ActualFileSize > 0x00FFFFFF) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ }
+ 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,
+ HeaderSize
+ );
+
+ //
+ // update Free Space Entry, now need to substract the file header length
+ //
+ FreeSpaceEntry->StartingAddress += HeaderSize;
+ FreeSpaceEntry->Length -= HeaderSize;
+
+ 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.
+ //
+ if (ActualFileSize > 0x00FFFFFF) {
+ ((EFI_FFS_FILE_HEADER2 *) FileHeader)->ExtendedSize = (UINT32) ActualFileSize;
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ FileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ } else {
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ *(UINT32 *) FileHeader->Size |= ActualFileSize;
+ }
+
+ SetHeaderChecksum (FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+
+ NumBytesWritten = HeaderSize;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ (UINT8 *) FileHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ HeaderSize
+ );
+
+ //
+ // 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,
+ HeaderSize
+ );
+
+ //
+ // update Free Space Entry, now need to substract the file data length
+ //
+ FreeSpaceEntry->StartingAddress += (BufferSize - HeaderSize);
+ FreeSpaceEntry->Length -= (BufferSize - HeaderSize);
+
+ //
+ // Calculate 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,
+ HeaderSize
+ );
+
+ //
+ // 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;
+ UINTN HeaderSize;
+
+ 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 + sizeof (EFI_FFS_FILE_HEADER) > 0x00FFFFFF) && !FvDevice->IsFfs3Fv) {
+ //
+ // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
+ //
+ DEBUG ((EFI_D_ERROR, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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 boundary, and add file tail.
+ //
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ ActualSize = FileData[Index1].BufferSize + HeaderSize;
+ if (ActualSize > 0x00FFFFFF) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ ActualSize = FileData[Index1].BufferSize + HeaderSize;
+ }
+ BufferSize = ActualSize;
+
+ while ((BufferSize & 0x07) != 0) {
+ BufferSize++;
+ }
+
+ FileBuffer = AllocateZeroPool (BufferSize);
+ if (FileBuffer == NULL) {
+ return Status;
+ }
+ //
+ // Copy File Data into FileBuffer
+ //
+ CopyMem (
+ FileBuffer + HeaderSize,
+ FileData[Index1].Buffer,
+ FileData[Index1].BufferSize
+ );
+
+ if (ErasePolarity == 1) {
+ //
+ // Fill the file header and padding byte with Erase Byte
+ //
+ for (Index2 = 0; Index2 < HeaderSize; 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;
+}