+++ /dev/null
-/** @file\r
- Implements write firmware file.\r
-\r
- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "FwVolDriver.h"\r
-\r
-/**\r
- Calculate the checksum for the FFS header.\r
-\r
- @param FfsHeader FFS File Header which needs to calculate the checksum\r
-\r
-**/\r
-VOID\r
-SetHeaderChecksum (\r
- IN EFI_FFS_FILE_HEADER *FfsHeader\r
- )\r
-{\r
- EFI_FFS_FILE_STATE State;\r
- UINT8 FileChecksum;\r
-\r
- //\r
- // The state and the File checksum are not included\r
- //\r
- State = FfsHeader->State;\r
- FfsHeader->State = 0;\r
-\r
- FileChecksum = FfsHeader->IntegrityCheck.Checksum.File;\r
- FfsHeader->IntegrityCheck.Checksum.File = 0;\r
-\r
- FfsHeader->IntegrityCheck.Checksum.Header = 0;\r
-\r
- if (IS_FFS_FILE2 (FfsHeader)) {\r
- FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (\r
- (UINT8 *) FfsHeader,\r
- sizeof (EFI_FFS_FILE_HEADER2)\r
- );\r
- } else {\r
- FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (\r
- (UINT8 *) FfsHeader,\r
- sizeof (EFI_FFS_FILE_HEADER)\r
- );\r
- }\r
-\r
- FfsHeader->State = State;\r
- FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- Calculate the checksum for the FFS File.\r
-\r
- @param FfsHeader FFS File Header which needs to calculate the checksum\r
- @param ActualFileSize The whole Ffs File Length.\r
-\r
-**/\r
-VOID\r
-SetFileChecksum (\r
- IN EFI_FFS_FILE_HEADER *FfsHeader,\r
- IN UINTN ActualFileSize\r
- )\r
-{\r
- if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {\r
-\r
- FfsHeader->IntegrityCheck.Checksum.File = 0;\r
-\r
- if (IS_FFS_FILE2 (FfsHeader)) {\r
- FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (\r
- (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2),\r
- ActualFileSize - sizeof (EFI_FFS_FILE_HEADER2)\r
- );\r
- } else {\r
- FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (\r
- (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER),\r
- ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)\r
- );\r
- }\r
-\r
- } else {\r
-\r
- FfsHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
-\r
- }\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- Get the alignment value from File Attributes.\r
-\r
- @param FfsAttributes FFS attribute\r
-\r
- @return Alignment value.\r
-\r
-**/\r
-UINTN\r
-GetRequiredAlignment (\r
- IN EFI_FV_FILE_ATTRIBUTES FfsAttributes\r
- )\r
-{\r
- UINTN AlignmentValue;\r
-\r
- AlignmentValue = FfsAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;\r
-\r
- if (AlignmentValue <= 3) {\r
- return 0x08;\r
- }\r
-\r
- if (AlignmentValue > 16) {\r
- //\r
- // Anyway, we won't reach this code\r
- //\r
- return 0x08;\r
- }\r
-\r
- return (UINTN)1 << AlignmentValue;\r
-\r
-}\r
-\r
-/**\r
- Calculate the leading Pad file size to meet the alignment requirement.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param StartAddress The starting address to write the FFS File.\r
- @param BufferSize The FFS File Buffer Size.\r
- @param RequiredAlignment FFS File Data alignment requirement.\r
-\r
- @return The required Pad File Size.\r
-\r
-**/\r
-UINTN\r
-CalculatePadFileSize (\r
- IN FV_DEVICE *FvDevice,\r
- IN EFI_PHYSICAL_ADDRESS StartAddress,\r
- IN UINTN BufferSize,\r
- IN UINTN RequiredAlignment\r
- )\r
-{\r
- UINTN DataStartPos;\r
- UINTN RelativePos;\r
- UINTN PadSize;\r
-\r
- if (BufferSize > 0x00FFFFFF) {\r
- DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER2);\r
- } else {\r
- DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER);\r
- }\r
- RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv;\r
-\r
- PadSize = 0;\r
-\r
- while ((RelativePos & (RequiredAlignment - 1)) != 0) {\r
- RelativePos++;\r
- PadSize++;\r
- }\r
- //\r
- // If padsize is 0, no pad file needed;\r
- // If padsize is great than 24, then pad file can be created\r
- //\r
- if ((PadSize == 0) || (PadSize >= sizeof (EFI_FFS_FILE_HEADER))) {\r
- return PadSize;\r
- }\r
-\r
- //\r
- // Perhaps following method can save space\r
- //\r
- RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv + sizeof (EFI_FFS_FILE_HEADER);\r
- PadSize = sizeof (EFI_FFS_FILE_HEADER);\r
-\r
- while ((RelativePos & (RequiredAlignment - 1)) != 0) {\r
- RelativePos++;\r
- PadSize++;\r
- }\r
-\r
- return PadSize;\r
-}\r
-\r
-/**\r
- Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.\r
-\r
- @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES\r
- @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.\r
-\r
-**/\r
-VOID\r
-FvFileAttrib2FfsFileAttrib (\r
- IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,\r
- OUT UINT8 *FfsFileAttrib\r
- )\r
-{\r
- UINT8 FvFileAlignment;\r
- UINT8 FfsFileAlignment;\r
- UINT8 FfsFileAlignment2;\r
-\r
- FvFileAlignment = (UINT8) (FvFileAttrib & EFI_FV_FILE_ATTRIB_ALIGNMENT);\r
- FfsFileAlignment = 0;\r
- FfsFileAlignment2 = 0;\r
-\r
- switch (FvFileAlignment) {\r
- case 0:\r
- //\r
- // fall through\r
- //\r
- case 1:\r
- //\r
- // fall through\r
- //\r
- case 2:\r
- //\r
- // fall through\r
- //\r
- case 3:\r
- //\r
- // fall through\r
- //\r
- FfsFileAlignment = 0;\r
- break;\r
-\r
- case 4:\r
- //\r
- // fall through\r
- //\r
- case 5:\r
- //\r
- // fall through\r
- //\r
- case 6:\r
- //\r
- // fall through\r
- //\r
- FfsFileAlignment = 1;\r
- break;\r
-\r
- case 7:\r
- //\r
- // fall through\r
- //\r
- case 8:\r
- //\r
- // fall through\r
- //\r
- FfsFileAlignment = 2;\r
- break;\r
-\r
- case 9:\r
- FfsFileAlignment = 3;\r
- break;\r
-\r
- case 10:\r
- //\r
- // fall through\r
- //\r
- case 11:\r
- //\r
- // fall through\r
- //\r
- FfsFileAlignment = 4;\r
- break;\r
-\r
- case 12:\r
- //\r
- // fall through\r
- //\r
- case 13:\r
- //\r
- // fall through\r
- //\r
- case 14:\r
- //\r
- // fall through\r
- //\r
- FfsFileAlignment = 5;\r
- break;\r
-\r
- case 15:\r
- FfsFileAlignment = 6;\r
- break;\r
-\r
- case 16:\r
- FfsFileAlignment = 7;\r
- break;\r
-\r
- case 17:\r
- FfsFileAlignment = 0;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 18:\r
- FfsFileAlignment = 1;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 19:\r
- FfsFileAlignment = 2;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 20:\r
- FfsFileAlignment = 3;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 21:\r
- FfsFileAlignment = 4;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 22:\r
- FfsFileAlignment = 5;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 23:\r
- FfsFileAlignment = 6;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- case 24:\r
- FfsFileAlignment = 7;\r
- FfsFileAlignment2 = 1;\r
- break;\r
- }\r
-\r
- *FfsFileAttrib = (UINT8) ((FfsFileAlignment << 3) | (FfsFileAlignment2 << 1));\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- Locate a free space entry that can hold this FFS file.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param Size The FFS file size.\r
- @param RequiredAlignment FFS File Data alignment requirement.\r
- @param PadSize Pointer to the size of leading Pad File.\r
- @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.\r
-\r
- @retval EFI_SUCCESS The free space entry is found.\r
- @retval EFI_NOT_FOUND The free space entry can't be found.\r
-\r
-**/\r
-EFI_STATUS\r
-FvLocateFreeSpaceEntry (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINTN Size,\r
- IN UINTN RequiredAlignment,\r
- OUT UINTN *PadSize,\r
- OUT FREE_SPACE_ENTRY **FreeSpaceEntry\r
- )\r
-{\r
- FREE_SPACE_ENTRY *FreeSpaceListEntry;\r
- LIST_ENTRY *Link;\r
- UINTN PadFileSize;\r
-\r
- Link = FvDevice->FreeSpaceHeader.ForwardLink;\r
- FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;\r
-\r
- //\r
- // Loop the free space entry list to find one that can hold the\r
- // required the file size\r
- //\r
- while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {\r
- PadFileSize = CalculatePadFileSize (\r
- FvDevice,\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,\r
- Size,\r
- RequiredAlignment\r
- );\r
- if (FreeSpaceListEntry->Length >= Size + PadFileSize) {\r
- *FreeSpaceEntry = FreeSpaceListEntry;\r
- *PadSize = PadFileSize;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-\r
-}\r
-\r
-/**\r
- Locate Pad File for writing, this is got from FV Cache.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param Size The required FFS file size.\r
- @param RequiredAlignment FFS File Data alignment requirement.\r
- @param PadSize Pointer to the size of leading Pad File.\r
- @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.\r
-\r
- @retval EFI_SUCCESS The required pad file is found.\r
- @retval EFI_NOT_FOUND The required pad file can't be found.\r
-\r
-**/\r
-EFI_STATUS\r
-FvLocatePadFile (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINTN Size,\r
- IN UINTN RequiredAlignment,\r
- OUT UINTN *PadSize,\r
- OUT FFS_FILE_LIST_ENTRY **PadFileEntry\r
- )\r
-{\r
- FFS_FILE_LIST_ENTRY *FileEntry;\r
- EFI_FFS_FILE_STATE FileState;\r
- EFI_FFS_FILE_HEADER *FileHeader;\r
- UINTN PadAreaLength;\r
- UINTN PadFileSize;\r
- UINTN HeaderSize;\r
-\r
- FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;\r
-\r
- //\r
- // travel through the whole file list to get the pad file entry\r
- //\r
- while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {\r
-\r
- FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;\r
- FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);\r
-\r
- if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {\r
- //\r
- // we find one valid pad file, check its free area length\r
- //\r
- if (IS_FFS_FILE2 (FileHeader)) {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
- PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;\r
- } else {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
- PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;\r
- }\r
-\r
- PadFileSize = CalculatePadFileSize (\r
- FvDevice,\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize,\r
- Size,\r
- RequiredAlignment\r
- );\r
- if (PadAreaLength >= (Size + PadFileSize)) {\r
- *PadSize = PadFileSize;\r
- *PadFileEntry = FileEntry;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Locate a suitable pad file for multiple file writing.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param NumOfFiles The number of Files that needed updating\r
- @param BufferSize The array of each file size.\r
- @param RequiredAlignment The array of of FFS File Data alignment requirement.\r
- @param PadSize The array of size of each leading Pad File.\r
- @param TotalSizeNeeded The totalsize that can hold these files.\r
- @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.\r
-\r
- @retval EFI_SUCCESS The required pad file is found.\r
- @retval EFI_NOT_FOUND The required pad file can't be found.\r
-\r
-**/\r
-EFI_STATUS\r
-FvSearchSuitablePadFile (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINTN NumOfFiles,\r
- IN UINTN *BufferSize,\r
- IN UINTN *RequiredAlignment,\r
- OUT UINTN *PadSize,\r
- OUT UINTN *TotalSizeNeeded,\r
- OUT FFS_FILE_LIST_ENTRY **PadFileEntry\r
- )\r
-{\r
- FFS_FILE_LIST_ENTRY *FileEntry;\r
- EFI_FFS_FILE_STATE FileState;\r
- EFI_FFS_FILE_HEADER *FileHeader;\r
- UINTN PadAreaLength;\r
- UINTN TotalSize;\r
- UINTN Index;\r
- UINTN HeaderSize;\r
-\r
- FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;\r
-\r
- //\r
- // travel through the whole file list to get the pad file entry\r
- //\r
- while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {\r
-\r
- FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;\r
- FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);\r
-\r
- if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {\r
- //\r
- // we find one valid pad file, check its length\r
- //\r
- if (IS_FFS_FILE2 (FileHeader)) {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
- PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;\r
- } else {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
- PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;\r
- }\r
- TotalSize = 0;\r
-\r
- for (Index = 0; Index < NumOfFiles; Index++) {\r
- PadSize[Index] = CalculatePadFileSize (\r
- FvDevice,\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize + TotalSize,\r
- BufferSize[Index],\r
- RequiredAlignment[Index]\r
- );\r
- TotalSize += PadSize[Index];\r
- TotalSize += BufferSize[Index];\r
-\r
- if (TotalSize > PadAreaLength) {\r
- break;\r
- }\r
- }\r
-\r
- if (PadAreaLength >= TotalSize) {\r
- *PadFileEntry = FileEntry;\r
- *TotalSizeNeeded = TotalSize;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Locate a Free Space entry which can hold these files, including\r
- meeting the alignment requirements.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param NumOfFiles The number of Files that needed updating\r
- @param BufferSize The array of each file size.\r
- @param RequiredAlignment The array of of FFS File Data alignment requirement.\r
- @param PadSize The array of size of each leading Pad File.\r
- @param TotalSizeNeeded The got total size that can hold these files.\r
- @param FreeSpaceEntry The Free Space Entry that can hold these files.\r
-\r
- @retval EFI_SUCCESS The free space entry is found.\r
- @retval EFI_NOT_FOUND The free space entry can't be found.\r
-\r
-**/\r
-EFI_STATUS\r
-FvSearchSuitableFreeSpace (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINTN NumOfFiles,\r
- IN UINTN *BufferSize,\r
- IN UINTN *RequiredAlignment,\r
- OUT UINTN *PadSize,\r
- OUT UINTN *TotalSizeNeeded,\r
- OUT FREE_SPACE_ENTRY **FreeSpaceEntry\r
- )\r
-{\r
- FREE_SPACE_ENTRY *FreeSpaceListEntry;\r
- LIST_ENTRY *Link;\r
- UINTN TotalSize;\r
- UINTN Index;\r
- UINT8 *StartAddr;\r
-\r
- Link = FvDevice->FreeSpaceHeader.ForwardLink;\r
-\r
- FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;\r
-\r
- while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {\r
- TotalSize = 0;\r
- StartAddr = FreeSpaceListEntry->StartingAddress;\r
-\r
- //\r
- // Calculate the totalsize we need\r
- //\r
- for (Index = 0; Index < NumOfFiles; Index++) {\r
- //\r
- // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file\r
- // have had its leading pad file.\r
- //\r
- PadSize[Index] = CalculatePadFileSize (\r
- FvDevice,\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,\r
- BufferSize[Index],\r
- RequiredAlignment[Index]\r
- );\r
-\r
- TotalSize += PadSize[Index];\r
- TotalSize += BufferSize[Index];\r
-\r
- if (TotalSize > FreeSpaceListEntry->Length) {\r
- break;\r
- }\r
- }\r
-\r
- if (FreeSpaceListEntry->Length >= TotalSize) {\r
- *FreeSpaceEntry = FreeSpaceListEntry;\r
- *TotalSizeNeeded = TotalSize;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Calculate the length of the remaining space in FV.\r
-\r
- @param FvDevice Cached Firmware Volume\r
- @param Offset Current offset to FV base address.\r
- @param Lba LBA number for the current offset.\r
- @param LOffset Offset in block for the current offset.\r
-\r
- @return the length of remaining space.\r
-\r
-**/\r
-UINTN\r
-CalculateRemainingLength (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINTN Offset,\r
- OUT EFI_LBA *Lba,\r
- OUT UINTN *LOffset\r
- )\r
-{\r
- LIST_ENTRY *Link;\r
- LBA_ENTRY *LbaEntry;\r
- UINTN Count;\r
-\r
- Count = 0;\r
- *Lba = 0;\r
- Link = FvDevice->LbaHeader.ForwardLink;\r
- LbaEntry = (LBA_ENTRY *) Link;\r
-\r
- while (&LbaEntry->Link != &FvDevice->LbaHeader) {\r
- if (Count > Offset) {\r
- break;\r
- }\r
-\r
- Count += LbaEntry->BlockLength;\r
- (*Lba)++;\r
- Link = LbaEntry->Link.ForwardLink;\r
- LbaEntry = (LBA_ENTRY *) Link;\r
- }\r
-\r
- if (Count <= Offset) {\r
- return 0;\r
- }\r
-\r
- Link = LbaEntry->Link.BackLink;\r
- LbaEntry = (LBA_ENTRY *) Link;\r
-\r
- (*Lba)--;\r
- *LOffset = (UINTN) (LbaEntry->BlockLength - (Count - Offset));\r
-\r
- Count = 0;\r
- while (&LbaEntry->Link != &FvDevice->LbaHeader) {\r
-\r
- Count += LbaEntry->BlockLength;\r
-\r
- Link = LbaEntry->Link.ForwardLink;\r
- LbaEntry = (LBA_ENTRY *) Link;\r
- }\r
-\r
- Count -= *LOffset;\r
-\r
- return Count;\r
-}\r
-\r
-/**\r
- Writes data beginning at Lba:Offset from FV. The write terminates either\r
- when *NumBytes of data have been written, or when the firmware end is\r
- reached. *NumBytes is updated to reflect the actual number of bytes\r
- written.\r
-\r
- @param FvDevice Cached Firmware Volume\r
- @param Offset Offset in the block at which to begin write\r
- @param NumBytes At input, indicates the requested write size.\r
- At output, indicates the actual number of bytes written.\r
- @param Buffer Buffer containing source data for the write.\r
-\r
- @retval EFI_SUCCESS Data is successfully written into FV.\r
- @return error Data is failed written.\r
-\r
-**/\r
-EFI_STATUS\r
-FvcWrite (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINTN Offset,\r
- IN OUT UINTN *NumBytes,\r
- IN UINT8 *Buffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
- EFI_LBA Lba;\r
- UINTN LOffset;\r
- EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
- UINTN RemainingLength;\r
- UINTN WriteLength;\r
- UINT8 *TmpBuffer;\r
-\r
- LOffset = 0;\r
- RemainingLength = CalculateRemainingLength (FvDevice, Offset, &Lba, &LOffset);\r
- if ((UINTN) (*NumBytes) > RemainingLength) {\r
- *NumBytes = (UINTN) RemainingLength;\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Fvb = FvDevice->Fvb;\r
-\r
- Status = Fvb->GetAttributes (\r
- Fvb,\r
- &FvbAttributes\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if ((FvbAttributes & EFI_FV2_WRITE_STATUS) == 0) {\r
- return EFI_ACCESS_DENIED;\r
- }\r
-\r
- RemainingLength = *NumBytes;\r
- WriteLength = RemainingLength;\r
- TmpBuffer = Buffer;\r
-\r
- do {\r
- Status = Fvb->Write (\r
- Fvb,\r
- Lba,\r
- LOffset,\r
- &WriteLength,\r
- TmpBuffer\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- if (Status == EFI_BAD_BUFFER_SIZE) {\r
- Lba++;\r
- LOffset = 0;\r
- TmpBuffer += WriteLength;\r
- RemainingLength -= WriteLength;\r
- WriteLength = (UINTN) RemainingLength;\r
-\r
- continue;\r
- } else {\r
- return Status;\r
- }\r
- } while (1);\r
-\r
-Done:\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Create a new FFS file into Firmware Volume device.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param FfsFileBuffer A buffer that holds an FFS file,(it contains\r
- a File Header which is in init state).\r
- @param BufferSize The size of FfsFileBuffer.\r
- @param ActualFileSize The actual file length, it may not be multiples of 8.\r
- @param FileName The FFS File Name.\r
- @param FileType The FFS File Type.\r
- @param FileAttributes The Attributes of the FFS File to be created.\r
-\r
- @retval EFI_SUCCESS FFS fle is added into FV.\r
- @retval EFI_INVALID_PARAMETER File type is not valid.\r
- @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.\r
- @retval EFI_NOT_FOUND FV has no enough space for the added file.\r
-\r
-**/\r
-EFI_STATUS\r
-FvCreateNewFile (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINT8 *FfsFileBuffer,\r
- IN UINTN BufferSize,\r
- IN UINTN ActualFileSize,\r
- IN EFI_GUID *FileName,\r
- IN EFI_FV_FILETYPE FileType,\r
- IN EFI_FV_FILE_ATTRIBUTES FileAttributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FFS_FILE_HEADER *FileHeader;\r
- EFI_PHYSICAL_ADDRESS BufferPtr;\r
- UINTN Offset;\r
- UINTN NumBytesWritten;\r
- UINTN StateOffset;\r
- FREE_SPACE_ENTRY *FreeSpaceEntry;\r
- UINTN RequiredAlignment;\r
- UINTN PadFileSize;\r
- FFS_FILE_LIST_ENTRY *PadFileEntry;\r
- EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;\r
- FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
- UINTN HeaderSize;\r
-\r
- //\r
- // File Type: 0x0E~0xE0 are reserved\r
- //\r
- if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // First find a free space that can hold this image.\r
- // Check alignment, FFS at least must be aligned at 8-byte boundary\r
- //\r
- RequiredAlignment = GetRequiredAlignment (FileAttributes);\r
-\r
- Status = FvLocateFreeSpaceEntry (\r
- FvDevice,\r
- BufferSize,\r
- RequiredAlignment,\r
- &PadFileSize,\r
- &FreeSpaceEntry\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Maybe we need to find a PAD file that can hold this image\r
- //\r
- Status = FvCreateNewFileInsidePadFile (\r
- FvDevice,\r
- FfsFileBuffer,\r
- BufferSize,\r
- ActualFileSize,\r
- FileName,\r
- FileType,\r
- FileAttributes\r
- );\r
-\r
- return Status;\r
- }\r
-\r
- BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;\r
-\r
- //\r
- // If we need a leading PAD File, create it first.\r
- //\r
- if (PadFileSize != 0) {\r
- Status = FvCreatePadFileInFreeSpace (\r
- FvDevice,\r
- FreeSpaceEntry,\r
- PadFileSize - sizeof (EFI_FFS_FILE_HEADER),\r
- &PadFileEntry\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
- //\r
- // Maybe we create a pad file, so re-get the free space starting address\r
- // and length\r
- //\r
- BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;\r
-\r
- //\r
- // File creation step 1: Allocate File Header,\r
- // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,\r
- // Write Name, IntegrityCheck.Header, Type, Attributes, and Size\r
- //\r
- FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;\r
- if (ActualFileSize > 0x00FFFFFF) {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
- } else {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
- }\r
- SetFileState (EFI_FILE_HEADER_CONSTRUCTION, FileHeader);\r
-\r
- Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);\r
- StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;\r
-\r
- NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
- Status = FvcWrite (\r
- FvDevice,\r
- StateOffset,\r
- &NumBytesWritten,\r
- &FileHeader->State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // update header 2 cache\r
- //\r
- CopyMem (\r
- (UINT8 *) (UINTN) BufferPtr,\r
- FileHeader,\r
- HeaderSize\r
- );\r
-\r
- //\r
- // update Free Space Entry, now need to substract the file header length\r
- //\r
- FreeSpaceEntry->StartingAddress += HeaderSize;\r
- FreeSpaceEntry->Length -= HeaderSize;\r
-\r
- CopyGuid (&FileHeader->Name, FileName);\r
- FileHeader->Type = FileType;\r
-\r
- //\r
- // Convert FvFileAttribute to FfsFileAttributes\r
- //\r
- FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);\r
-\r
- FileHeader->Attributes = TmpFileAttribute;\r
-\r
- //\r
- // File size is including the FFS File Header.\r
- //\r
- if (ActualFileSize > 0x00FFFFFF) {\r
- ((EFI_FFS_FILE_HEADER2 *) FileHeader)->ExtendedSize = (UINT32) ActualFileSize;\r
- *(UINT32 *) FileHeader->Size &= 0xFF000000;\r
- FileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;\r
- } else {\r
- *(UINT32 *) FileHeader->Size &= 0xFF000000;\r
- *(UINT32 *) FileHeader->Size |= ActualFileSize;\r
- }\r
-\r
- SetHeaderChecksum (FileHeader);\r
-\r
- Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);\r
-\r
- NumBytesWritten = HeaderSize;\r
- Status = FvcWrite (\r
- FvDevice,\r
- Offset,\r
- &NumBytesWritten,\r
- (UINT8 *) FileHeader\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // update header 2 cache\r
- //\r
- CopyMem (\r
- (UINT8 *) (UINTN) BufferPtr,\r
- FileHeader,\r
- HeaderSize\r
- );\r
-\r
- //\r
- // end of step 1\r
- //\r
- // File creation step 2:\r
- // MARK EFI_FILE_HEADER_VALID bit to TRUE,\r
- // Write IntegrityCheck.File, File Data\r
- //\r
- SetFileState (EFI_FILE_HEADER_VALID, FileHeader);\r
-\r
- Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);\r
- StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;\r
-\r
- NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
- Status = FvcWrite (\r
- FvDevice,\r
- StateOffset,\r
- &NumBytesWritten,\r
- &FileHeader->State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // update header 2 cache\r
- //\r
- CopyMem (\r
- (UINT8 *) (UINTN) BufferPtr,\r
- FileHeader,\r
- HeaderSize\r
- );\r
-\r
- //\r
- // update Free Space Entry, now need to substract the file data length\r
- //\r
- FreeSpaceEntry->StartingAddress += (BufferSize - HeaderSize);\r
- FreeSpaceEntry->Length -= (BufferSize - HeaderSize);\r
-\r
- //\r
- // Calculate File Checksum\r
- //\r
- SetFileChecksum (FileHeader, ActualFileSize);\r
-\r
- Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);\r
-\r
- NumBytesWritten = BufferSize;\r
- Status = FvcWrite (\r
- FvDevice,\r
- Offset,\r
- &NumBytesWritten,\r
- FfsFileBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // each time write block successfully, write also to cache\r
- //\r
- CopyMem (\r
- (UINT8 *) (UINTN) BufferPtr,\r
- FfsFileBuffer,\r
- NumBytesWritten\r
- );\r
-\r
- //\r
- // Step 3: Mark EFI_FILE_DATA_VALID to TRUE\r
- //\r
- SetFileState (EFI_FILE_DATA_VALID, FileHeader);\r
-\r
- Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);\r
- StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;\r
-\r
- NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
- Status = FvcWrite (\r
- FvDevice,\r
- StateOffset,\r
- &NumBytesWritten,\r
- &FileHeader->State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // update header 2 cache\r
- //\r
- CopyMem (\r
- (UINT8 *) (UINTN) BufferPtr,\r
- FileHeader,\r
- HeaderSize\r
- );\r
-\r
- //\r
- // If successfully, insert an FfsFileEntry at the end of ffs file list\r
- //\r
-\r
- FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
- ASSERT (FfsFileEntry != NULL);\r
- FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) BufferPtr;\r
- InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
-\r
- //\r
- // Set cache file to this file\r
- //\r
- FvDevice->CurrentFfsFile = FfsFileEntry;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Update a File, so after successful update, there are 2 files existing\r
- in FV, one is marked for deleted, and another one is valid.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param FfsFileBuffer A buffer that holds an FFS file,(it contains\r
- a File Header which is in init state).\r
- @param BufferSize The size of FfsFileBuffer.\r
- @param ActualFileSize The actual file length, it may not be multiples of 8.\r
- @param FileName The FFS File Name.\r
- @param NewFileType The FFS File Type.\r
- @param NewFileAttributes The Attributes of the FFS File to be created.\r
-\r
- @retval EFI_SUCCESS FFS fle is updated into FV.\r
- @retval EFI_INVALID_PARAMETER File type is not valid.\r
- @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.\r
- @retval EFI_NOT_FOUND FV has no enough space for the added file.\r
- FFS with same file name is not found in FV.\r
-\r
-**/\r
-EFI_STATUS\r
-FvUpdateFile (\r
- IN FV_DEVICE *FvDevice,\r
- IN UINT8 *FfsFileBuffer,\r
- IN UINTN BufferSize,\r
- IN UINTN ActualFileSize,\r
- IN EFI_GUID *FileName,\r
- IN EFI_FV_FILETYPE NewFileType,\r
- IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
- UINTN NumBytesWritten;\r
- EFI_FV_FILETYPE OldFileType;\r
- EFI_FV_FILE_ATTRIBUTES OldFileAttributes;\r
- UINTN OldFileSize;\r
- EFI_FFS_FILE_HEADER *OldFileHeader;\r
- UINTN OldOffset;\r
- UINTN OldStateOffset;\r
- FFS_FILE_LIST_ENTRY *OldFfsFileEntry;\r
- UINTN Key;\r
- EFI_GUID FileNameGuid;\r
-\r
- Fv = &FvDevice->Fv;\r
-\r
- //\r
- // Step 1, find old file,\r
- // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header\r
- //\r
-\r
- //\r
- // Check if the file was read last time.\r
- //\r
- OldFileHeader = NULL;\r
- OldFfsFileEntry = FvDevice->CurrentFfsFile;\r
-\r
- if (OldFfsFileEntry != NULL) {\r
- OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;\r
- }\r
-\r
- if ((OldFfsFileEntry == NULL) || (!CompareGuid (&OldFileHeader->Name, FileName))) {\r
- Key = 0;\r
- do {\r
- OldFileType = 0;\r
- Status = Fv->GetNextFile (\r
- Fv,\r
- &Key,\r
- &OldFileType,\r
- &FileNameGuid,\r
- &OldFileAttributes,\r
- &OldFileSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } while (!CompareGuid (&FileNameGuid, FileName));\r
-\r
- //\r
- // Get FfsFileEntry from the search key\r
- //\r
- OldFfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;\r
-\r
- //\r
- // Double check file state before being ready to be removed\r
- //\r
- OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;\r
- } else {\r
- //\r
- // Mark the cache file to invalid\r
- //\r
- FvDevice->CurrentFfsFile = NULL;\r
- }\r
- //\r
- // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE\r
- //\r
- SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);\r
-\r
- OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);\r
- OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;\r
-\r
- NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
- Status = FvcWrite (\r
- FvDevice,\r
- OldStateOffset,\r
- &NumBytesWritten,\r
- &OldFileHeader->State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // if failed, write the bit back in the cache, its XOR operation.\r
- //\r
- SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);\r
-\r
- return Status;\r
- }\r
-\r
- //\r
- // Step 2, Create New Files\r
- //\r
- Status = FvCreateNewFile (\r
- FvDevice,\r
- FfsFileBuffer,\r
- BufferSize,\r
- ActualFileSize,\r
- FileName,\r
- NewFileType,\r
- NewFileAttributes\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // If successfully, remove this file entry,\r
- // although delete file may fail.\r
- //\r
- (OldFfsFileEntry->Link.BackLink)->ForwardLink = OldFfsFileEntry->Link.ForwardLink;\r
- (OldFfsFileEntry->Link.ForwardLink)->BackLink = OldFfsFileEntry->Link.BackLink;\r
- FreePool (OldFfsFileEntry);\r
-\r
- //\r
- // Step 3: Delete old files,\r
- // by marking EFI_FILE_DELETED to TRUE\r
- //\r
- SetFileState (EFI_FILE_DELETED, OldFileHeader);\r
-\r
- OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);\r
- OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;\r
-\r
- NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
- Status = FvcWrite (\r
- FvDevice,\r
- OldStateOffset,\r
- &NumBytesWritten,\r
- &OldFileHeader->State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // if failed, write the bit back in the cache, its XOR operation.\r
- //\r
- SetFileState (EFI_FILE_DELETED, OldFileHeader);\r
-\r
- return Status;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Deleted a given file from FV device.\r
-\r
- @param FvDevice Cached Firmware Volume.\r
- @param NameGuid The FFS File Name.\r
-\r
- @retval EFI_SUCCESS FFS file with the specified FFS name is removed.\r
- @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.\r
-\r
-**/\r
-EFI_STATUS\r
-FvDeleteFile (\r
- IN FV_DEVICE *FvDevice,\r
- IN EFI_GUID *NameGuid\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Key;\r
- EFI_GUID FileNameGuid;\r
- EFI_FV_FILETYPE FileType;\r
- EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
- UINTN FileSize;\r
- EFI_FFS_FILE_HEADER *FileHeader;\r
- FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
- EFI_FFS_FILE_STATE FileState;\r
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
- UINTN Offset;\r
- UINTN StateOffset;\r
- UINTN NumBytesWritten;\r
-\r
- Fv = &FvDevice->Fv;\r
-\r
- //\r
- // Check if the file was read last time.\r
- //\r
- FileHeader = NULL;\r
- FfsFileEntry = FvDevice->CurrentFfsFile;\r
-\r
- if (FfsFileEntry != NULL) {\r
- FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;\r
- }\r
-\r
- if ((FfsFileEntry == NULL) || (!CompareGuid (&FileHeader->Name, NameGuid))) {\r
- //\r
- // Next search for the file using GetNextFile\r
- //\r
- Key = 0;\r
- do {\r
- FileType = 0;\r
- Status = Fv->GetNextFile (\r
- Fv,\r
- &Key,\r
- &FileType,\r
- &FileNameGuid,\r
- &FileAttributes,\r
- &FileSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } while (!CompareGuid (&FileNameGuid, NameGuid));\r
-\r
- //\r
- // Get FfsFileEntry from the search key\r
- //\r
- FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;\r
-\r
- //\r
- // Double check file state before being ready to be removed\r
- //\r
- FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;\r
- } else {\r
- //\r
- // Mark the cache file to NULL\r
- //\r
- FvDevice->CurrentFfsFile = NULL;\r
- }\r
-\r
- FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);\r
-\r
- if (FileState == EFI_FILE_HEADER_INVALID) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if (FileState == EFI_FILE_DELETED) {\r
- return EFI_NOT_FOUND;\r
- }\r
- //\r
- // Delete File: Mark EFI_FILE_DELETED to TRUE\r
- //\r
- SetFileState (EFI_FILE_DELETED, FileHeader);\r
-\r
- Offset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader - FvDevice->CachedFv);\r
- StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;\r
-\r
- NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
- Status = FvcWrite (\r
- FvDevice,\r
- StateOffset,\r
- &NumBytesWritten,\r
- &FileHeader->State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // if failed, write the bit back in the cache, its XOR operation.\r
- //\r
- SetFileState (EFI_FILE_DELETED, FileHeader);\r
-\r
- return Status;\r
- }\r
- //\r
- // If successfully, remove this file entry\r
- //\r
- FvDevice->CurrentFfsFile = NULL;\r
-\r
- (FfsFileEntry->Link.BackLink)->ForwardLink = FfsFileEntry->Link.ForwardLink;\r
- (FfsFileEntry->Link.ForwardLink)->BackLink = FfsFileEntry->Link.BackLink;\r
- FreePool (FfsFileEntry);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Writes one or more files to the firmware volume.\r
-\r
- @param This Indicates the calling context.\r
- @param NumberOfFiles Number of files.\r
- @param WritePolicy WritePolicy indicates the level of reliability\r
- for the write in the event of a power failure or\r
- other system failure during the write operation.\r
- @param FileData FileData is an pointer to an array of\r
- EFI_FV_WRITE_DATA. Each element of array\r
- FileData represents a file to be written.\r
-\r
- @retval EFI_SUCCESS Files successfully written to firmware volume\r
- @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.\r
- @retval EFI_DEVICE_ERROR Device error.\r
- @retval EFI_WRITE_PROTECTED Write protected.\r
- @retval EFI_NOT_FOUND Not found.\r
- @retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_UNSUPPORTED This function not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvWriteFile (\r
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
- IN UINT32 NumberOfFiles,\r
- IN EFI_FV_WRITE_POLICY WritePolicy,\r
- IN EFI_FV_WRITE_FILE_DATA *FileData\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Index1;\r
- UINTN Index2;\r
- UINT8 *FileBuffer;\r
- UINTN BufferSize;\r
- UINTN ActualSize;\r
- UINT8 ErasePolarity;\r
- FV_DEVICE *FvDevice;\r
- EFI_FV_FILETYPE FileType;\r
- EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
- UINTN Size;\r
- BOOLEAN CreateNewFile[MAX_FILES];\r
- UINTN NumDelete;\r
- EFI_FV_ATTRIBUTES FvAttributes;\r
- UINT32 AuthenticationStatus;\r
- UINTN HeaderSize;\r
-\r
- if (NumberOfFiles > MAX_FILES) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- SetMem (CreateNewFile, NumberOfFiles, TRUE);\r
-\r
- FvDevice = FV_DEVICE_FROM_THIS (This);\r
-\r
- //\r
- // First check the volume attributes.\r
- //\r
- Status = This->GetVolumeAttributes (\r
- This,\r
- &FvAttributes\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Can we have write right?\r
- //\r
- if ((FvAttributes & EFI_FV2_WRITE_STATUS) == 0) {\r
- return EFI_WRITE_PROTECTED;\r
- }\r
-\r
- ErasePolarity = FvDevice->ErasePolarity;\r
-\r
- //\r
- // Loop for all files\r
- //\r
- NumDelete = 0;\r
- for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {\r
-\r
- if ((FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER) > 0x00FFFFFF) && !FvDevice->IsFfs3Fv) {\r
- //\r
- // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.\r
- //\r
- DEBUG ((EFI_D_ERROR, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (FileData[Index1].BufferSize == 0) {\r
- //\r
- // Here we will delete this file\r
- //\r
- Status = This->ReadFile (\r
- This,\r
- FileData[Index1].NameGuid,\r
- NULL,\r
- &Size,\r
- &FileType,\r
- &FileAttributes,\r
- &AuthenticationStatus\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- NumDelete++;\r
- } else {\r
- return Status;\r
- }\r
- }\r
-\r
- if (FileData[Index1].Type == EFI_FV_FILETYPE_FFS_PAD) {\r
- //\r
- // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:\r
- // "Standard firmware file system services will not return the handle of any pad files,\r
- // nor will they permit explicit creation of such files."\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
-\r
- if ((NumDelete != NumberOfFiles) && (NumDelete != 0)) {\r
- //\r
- // A delete was request with a multiple file write\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (NumDelete == NumberOfFiles) {\r
- for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {\r
- //\r
- // Delete Files\r
- //\r
- Status = FvDeleteFile (FvDevice, FileData[Index1].NameGuid);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
- }\r
-\r
- for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {\r
- Status = This->ReadFile (\r
- This,\r
- FileData[Index1].NameGuid,\r
- NULL,\r
- &Size,\r
- &FileType,\r
- &FileAttributes,\r
- &AuthenticationStatus\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- CreateNewFile[Index1] = FALSE;\r
- } else if (Status == EFI_NOT_FOUND) {\r
- CreateNewFile[Index1] = TRUE;\r
- } else {\r
- return Status;\r
- }\r
- //\r
- // Checking alignment\r
- //\r
- if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) {\r
- UINT8 FFSAlignmentValue;\r
- UINT8 FvAlignmentValue;\r
-\r
- FFSAlignmentValue = (UINT8) (FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT);\r
- FvAlignmentValue = (UINT8) (((UINT32) (FvAttributes & EFI_FV2_ALIGNMENT)) >> 16);\r
-\r
- if (FFSAlignmentValue > FvAlignmentValue) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
- }\r
-\r
- if ((WritePolicy != EFI_FV_RELIABLE_WRITE) && (WritePolicy != EFI_FV_UNRELIABLE_WRITE)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Checking the reliable write is supported by FV\r
- //\r
-\r
- if ((WritePolicy == EFI_FV_RELIABLE_WRITE) && (NumberOfFiles > 1)) {\r
- //\r
- // Only for multiple files, reliable write is meaningful\r
- //\r
- Status = FvCreateMultipleFiles (\r
- FvDevice,\r
- NumberOfFiles,\r
- FileData,\r
- CreateNewFile\r
- );\r
-\r
- return Status;\r
- }\r
-\r
- for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {\r
- //\r
- // Making Buffersize QWORD boundary, and add file tail.\r
- //\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
- ActualSize = FileData[Index1].BufferSize + HeaderSize;\r
- if (ActualSize > 0x00FFFFFF) {\r
- HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
- ActualSize = FileData[Index1].BufferSize + HeaderSize;\r
- }\r
- BufferSize = ActualSize;\r
-\r
- while ((BufferSize & 0x07) != 0) {\r
- BufferSize++;\r
- }\r
-\r
- FileBuffer = AllocateZeroPool (BufferSize);\r
- if (FileBuffer == NULL) {\r
- return Status;\r
- }\r
- //\r
- // Copy File Data into FileBuffer\r
- //\r
- CopyMem (\r
- FileBuffer + HeaderSize,\r
- FileData[Index1].Buffer,\r
- FileData[Index1].BufferSize\r
- );\r
-\r
- if (ErasePolarity == 1) {\r
- //\r
- // Fill the file header and padding byte with Erase Byte\r
- //\r
- for (Index2 = 0; Index2 < HeaderSize; Index2++) {\r
- FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];\r
- }\r
-\r
- for (Index2 = ActualSize; Index2 < BufferSize; Index2++) {\r
- FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];\r
- }\r
- }\r
-\r
- if (CreateNewFile[Index1]) {\r
- Status = FvCreateNewFile (\r
- FvDevice,\r
- FileBuffer,\r
- BufferSize,\r
- ActualSize,\r
- FileData[Index1].NameGuid,\r
- FileData[Index1].Type,\r
- FileData[Index1].FileAttributes\r
- );\r
- } else {\r
- Status = FvUpdateFile (\r
- FvDevice,\r
- FileBuffer,\r
- BufferSize,\r
- ActualSize,\r
- FileData[Index1].NameGuid,\r
- FileData[Index1].Type,\r
- FileData[Index1].FileAttributes\r
- );\r
- }\r
-\r
- FreePool (FileBuffer);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r