IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf\r
IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf\r
IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf\r
+ IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf\r
\r
[Components.IA32,Components.X64]\r
IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf\r
--- /dev/null
+/** @file\r
+ FFS file access utilities.\r
+\r
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FwVolDriver.h"\r
+\r
+#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))\r
+\r
+/**\r
+ Set File State in the FfsHeader.\r
+\r
+ @param State File state to be set into FFS header.\r
+ @param FfsHeader Points to the FFS file header\r
+\r
+**/\r
+VOID\r
+SetFileState (\r
+ IN UINT8 State,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ //\r
+ // Set File State in the FfsHeader\r
+ //\r
+ FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);\r
+ return ;\r
+}\r
+\r
+/**\r
+ Get the FFS file state by checking the highest bit set in the header's state field.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param FfsHeader Points to the FFS file header\r
+\r
+ @return FFS File state\r
+\r
+**/\r
+EFI_FFS_FILE_STATE\r
+GetFileState (\r
+ IN UINT8 ErasePolarity,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ EFI_FFS_FILE_STATE FileState;\r
+ UINT8 HighestBit;\r
+\r
+ FileState = FfsHeader->State;\r
+\r
+ if (ErasePolarity != 0) {\r
+ FileState = (EFI_FFS_FILE_STATE)~FileState;\r
+ }\r
+\r
+ HighestBit = 0x80;\r
+ while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {\r
+ HighestBit >>= 1;\r
+ }\r
+\r
+ return (EFI_FFS_FILE_STATE) HighestBit;\r
+}\r
+\r
+/**\r
+ Convert the Buffer Address to LBA Entry Address.\r
+\r
+ @param FvDevice Cached FvDevice\r
+ @param BufferAddress Address of Buffer\r
+ @param LbaListEntry Pointer to the got LBA entry that contains the address.\r
+\r
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.\r
+ @retval EFI_SUCCESS LBA entry is found for Buffer address.\r
+\r
+**/\r
+EFI_STATUS\r
+Buffer2LbaEntry (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,\r
+ OUT LBA_ENTRY **LbaListEntry\r
+ )\r
+{\r
+ LBA_ENTRY *LbaEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ Link = FvDevice->LbaHeader.ForwardLink;\r
+ LbaEntry = (LBA_ENTRY *) Link;\r
+\r
+ //\r
+ // Locate LBA which contains the address\r
+ //\r
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {\r
+ if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {\r
+ break;\r
+ }\r
+\r
+ Link = LbaEntry->Link.ForwardLink;\r
+ LbaEntry = (LBA_ENTRY *) Link;\r
+ }\r
+\r
+ if (&LbaEntry->Link == &FvDevice->LbaHeader) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Link = LbaEntry->Link.BackLink;\r
+ LbaEntry = (LBA_ENTRY *) Link;\r
+\r
+ if (&LbaEntry->Link == &FvDevice->LbaHeader) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *LbaListEntry = LbaEntry;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert the Buffer Address to LBA Address & Offset.\r
+\r
+ @param FvDevice Cached FvDevice\r
+ @param BufferAddress Address of Buffer\r
+ @param Lba Pointer to the gob Lba value\r
+ @param Offset Pointer to the got Offset\r
+\r
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.\r
+ @retval EFI_SUCCESS LBA and Offset is found for Buffer address.\r
+\r
+**/\r
+EFI_STATUS\r
+Buffer2Lba (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,\r
+ OUT EFI_LBA *Lba,\r
+ OUT UINTN *Offset\r
+ )\r
+{\r
+ LBA_ENTRY *LbaEntry;\r
+ EFI_STATUS Status;\r
+\r
+ LbaEntry = NULL;\r
+\r
+ Status = Buffer2LbaEntry (\r
+ FvDevice,\r
+ BufferAddress,\r
+ &LbaEntry\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *Lba = LbaEntry->LbaIndex;\r
+ *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check if a block of buffer is erased.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param Buffer The buffer to be checked\r
+ @param BufferSize Size of the buffer in bytes\r
+\r
+ @retval TRUE The block of buffer is erased\r
+ @retval FALSE The block of buffer is not erased\r
+\r
+**/\r
+BOOLEAN\r
+IsBufferErased (\r
+ IN UINT8 ErasePolarity,\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ UINTN Count;\r
+ UINT8 EraseByte;\r
+\r
+ if (ErasePolarity == 1) {\r
+ EraseByte = 0xFF;\r
+ } else {\r
+ EraseByte = 0;\r
+ }\r
+\r
+ for (Count = 0; Count < BufferSize; Count++) {\r
+ if (Buffer[Count] != EraseByte) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Verify checksum of the firmware volume header.\r
+\r
+ @param FvHeader Points to the firmware volume header to be checked\r
+\r
+ @retval TRUE Checksum verification passed\r
+ @retval FALSE Checksum verification failed\r
+\r
+**/\r
+BOOLEAN\r
+VerifyFvHeaderChecksum (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader\r
+ )\r
+{\r
+ UINT16 Checksum;\r
+\r
+ Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);\r
+\r
+ if (Checksum == 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Verify checksum of the FFS file header.\r
+\r
+ @param FfsHeader Points to the FFS file header to be checked\r
+\r
+ @retval TRUE Checksum verification passed\r
+ @retval FALSE Checksum verification failed\r
+\r
+**/\r
+BOOLEAN\r
+VerifyHeaderChecksum (\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ UINT8 HeaderChecksum;\r
+\r
+ HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));\r
+ HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);\r
+\r
+ if (HeaderChecksum == 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Verify checksum of the FFS file data.\r
+\r
+ @param FfsHeader Points to the FFS file header to be checked\r
+\r
+ @retval TRUE Checksum verification passed\r
+ @retval FALSE Checksum verification failed\r
+\r
+**/\r
+BOOLEAN\r
+VerifyFileChecksum (\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ UINT8 FileChecksum;\r
+ EFI_FV_FILE_ATTRIBUTES Attributes;\r
+ UINT32 FileSize;\r
+\r
+ Attributes = FfsHeader->Attributes;\r
+\r
+ if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {\r
+\r
+ FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;\r
+\r
+ //\r
+ // Check checksum of FFS data\r
+ //\r
+ FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FileSize - sizeof (EFI_FFS_FILE_HEADER));\r
+ FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);\r
+\r
+ if (FileChecksum == 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+\r
+ } else {\r
+\r
+ if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Check if it's a valid FFS file header.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param FfsHeader Points to the FFS file header to be checked\r
+\r
+ @retval TRUE Valid FFS file header\r
+ @retval FALSE Invalid FFS file header\r
+\r
+**/\r
+BOOLEAN\r
+IsValidFFSHeader (\r
+ IN UINT8 ErasePolarity,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ EFI_FFS_FILE_STATE FileState;\r
+\r
+ //\r
+ // Check if it is a free space\r
+ //\r
+ if (IsBufferErased (\r
+ ErasePolarity,\r
+ (UINT8 *) FfsHeader,\r
+ sizeof (EFI_FFS_FILE_HEADER)\r
+ )) {\r
+ return FALSE;\r
+ }\r
+\r
+ FileState = GetFileState (ErasePolarity, FfsHeader);\r
+\r
+ switch (FileState) {\r
+ case EFI_FILE_HEADER_CONSTRUCTION:\r
+ //\r
+ // fall through\r
+ //\r
+ case EFI_FILE_HEADER_INVALID:\r
+ return FALSE;\r
+\r
+ case EFI_FILE_HEADER_VALID:\r
+ //\r
+ // fall through\r
+ //\r
+ case EFI_FILE_DATA_VALID:\r
+ //\r
+ // fall through\r
+ //\r
+ case EFI_FILE_MARKED_FOR_UPDATE:\r
+ //\r
+ // fall through\r
+ //\r
+ case EFI_FILE_DELETED:\r
+ //\r
+ // Here we need to verify header checksum\r
+ //\r
+ if (!VerifyHeaderChecksum (FfsHeader)) {\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // return\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Get next possible of Firmware File System Header.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param FfsHeader Points to the FFS file header to be skipped.\r
+\r
+ @return Pointer to next FFS header.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+GetNextPossibleFileHeader (\r
+ IN UINT8 ErasePolarity,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ UINT32 FileLength;\r
+ UINT32 SkipLength;\r
+\r
+ if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {\r
+ //\r
+ // Skip this header\r
+ //\r
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);\r
+ }\r
+\r
+ FileLength = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;\r
+\r
+ //\r
+ // Since FileLength is not multiple of 8, we need skip some bytes\r
+ // to get next possible header\r
+ //\r
+ SkipLength = FileLength;\r
+ while ((SkipLength & 0x07) != 0) {\r
+ SkipLength++;\r
+ }\r
+\r
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;\r
+}\r
+\r
+/**\r
+ Search FFS file with the same FFS name in FV Cache.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FfsHeader Points to the FFS file header to be skipped.\r
+ @param StateBit FFS file state bit to be checked.\r
+\r
+ @return Pointer to next found FFS header. NULL will return if no found.\r
+\r
+**/\r
+EFI_FFS_FILE_HEADER *\r
+DuplicateFileExist (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader,\r
+ IN EFI_FFS_FILE_STATE StateBit\r
+ )\r
+{\r
+ UINT8 *Ptr;\r
+ EFI_FFS_FILE_HEADER *NextFfsFile;\r
+\r
+ //\r
+ // Search duplicate file, not from the beginning of FV,\r
+ // just search the next ocurrence of this file\r
+ //\r
+ NextFfsFile = FfsHeader;\r
+\r
+ do {\r
+ Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (\r
+ GetNextPossibleFileHeader (FvDevice->ErasePolarity,\r
+ NextFfsFile)\r
+ );\r
+ NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;\r
+\r
+ if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <\r
+ sizeof (EFI_FFS_FILE_HEADER)\r
+ ) {\r
+ break;\r
+ }\r
+\r
+ if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {\r
+ continue;\r
+ }\r
+\r
+ if (!VerifyFileChecksum (NextFfsFile)) {\r
+ continue;\r
+ }\r
+\r
+ if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {\r
+ if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {\r
+ return NextFfsFile;\r
+ }\r
+ }\r
+ } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Change FFS file header state and write to FV.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FfsHeader Points to the FFS file header to be updated.\r
+ @param State FFS file state to be set.\r
+\r
+ @retval EFI_SUCCESS File state is writen into FV.\r
+ @retval others File state can't be writen into FV.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateHeaderBit (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader,\r
+ IN EFI_FFS_FILE_STATE State\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LBA Lba;\r
+ UINTN Offset;\r
+ UINTN NumBytesWritten;\r
+\r
+ Lba = 0;\r
+ Offset = 0;\r
+\r
+ SetFileState (State, FfsHeader);\r
+\r
+ Buffer2Lba (\r
+ FvDevice,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),\r
+ &Lba,\r
+ &Offset\r
+ );\r
+ //\r
+ // Write the state byte into FV\r
+ //\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
+ Status = FvDevice->Fvb->Write (\r
+ FvDevice->Fvb,\r
+ Lba,\r
+ Offset,\r
+ &NumBytesWritten,\r
+ &FfsHeader->State\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check if it's a valid FFS file.\r
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FfsHeader Points to the FFS file to be checked\r
+\r
+ @retval TRUE Valid FFS file\r
+ @retval FALSE Invalid FFS file\r
+\r
+**/\r
+BOOLEAN\r
+IsValidFFSFile (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ )\r
+{\r
+ EFI_FFS_FILE_STATE FileState;\r
+ UINT8 ErasePolarity;\r
+\r
+ ErasePolarity = FvDevice->ErasePolarity;\r
+\r
+ FileState = GetFileState (ErasePolarity, FfsHeader);\r
+\r
+ switch (FileState) {\r
+ case EFI_FILE_DATA_VALID:\r
+ if (!VerifyFileChecksum (FfsHeader)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
+ break;\r
+ }\r
+ //\r
+ // Check if there is another duplicated file with the EFI_FILE_DATA_VALID\r
+ //\r
+ if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ break;\r
+\r
+ case EFI_FILE_MARKED_FOR_UPDATE:\r
+ if (!VerifyFileChecksum (FfsHeader)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
+ //\r
+ // since its data area is not unperturbed, it cannot be reclaimed,\r
+ // marked it as deleted\r
+ //\r
+ UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);\r
+ return TRUE;\r
+\r
+ } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {\r
+ //\r
+ // Here the found file is more recent than this file,\r
+ // mark it as deleted\r
+ //\r
+ UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);\r
+ return TRUE;\r
+\r
+ } else {\r
+ return TRUE;\r
+ }\r
+\r
+ break;\r
+\r
+ case EFI_FILE_DELETED:\r
+ if (!VerifyFileChecksum (FfsHeader)) {\r
+ return FALSE;\r
+ }\r
+\r
+ break;\r
+\r
+ default:\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Locate the first file in FV.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FirstFile Points to the got first FFS file header.\r
+\r
+ @retval EFI_NOT_FOUND No FFS file is found in FV.\r
+ @retval EFI_SUCCESS The first FFS file is got.\r
+\r
+**/\r
+EFI_STATUS\r
+FvLocateFirstFile (\r
+ IN FV_DEVICE *FvDevice,\r
+ OUT EFI_FFS_FILE_HEADER **FirstFile\r
+ )\r
+{\r
+ FFS_FILE_LIST_ENTRY *TmpFileList;\r
+ LIST_ENTRY *Link;\r
+\r
+ Link = FvDevice->FfsFileListHeader.ForwardLink;\r
+\r
+ if (Link == &FvDevice->FfsFileListHeader) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ TmpFileList = (FFS_FILE_LIST_ENTRY *) Link;\r
+ *FirstFile = (EFI_FFS_FILE_HEADER *) TmpFileList->FfsHeader;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Implements functions to pad firmware file.\r
+\r
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FwVolDriver.h"\r
+\r
+/**\r
+ Calculate the checksum for a PAD file.\r
+\r
+ @param PadFileHeader The Pad File to be caculeted the checksum.\r
+\r
+**/\r
+VOID\r
+SetPadFileChecksum (\r
+ IN EFI_FFS_FILE_HEADER *PadFileHeader\r
+ )\r
+{\r
+ UINT32 PadFileLength;\r
+\r
+ if ((PadFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {\r
+\r
+ PadFileLength = *(UINT32 *) PadFileHeader->Size & 0x00FFFFFF;\r
+\r
+ //\r
+ // Calculate checksum of Pad File Data\r
+ //\r
+ PadFileHeader->IntegrityCheck.Checksum.File =\r
+ CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER), PadFileLength - sizeof (EFI_FFS_FILE_HEADER));\r
+\r
+ } else {\r
+\r
+ PadFileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Create a PAD File in the Free Space.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.\r
+ @param Size Pad file Size, not include the header.\r
+ @param PadFileEntry The Ffs File Entry that points to this Pad File.\r
+\r
+ @retval EFI_SUCCESS Successfully create a PAD file.\r
+ @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.\r
+ @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.\r
+ @retval EFI_DEVICE_ERROR Free space is not erased.\r
+**/\r
+EFI_STATUS\r
+FvCreatePadFileInFreeSpace (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN FREE_SPACE_ENTRY *FreeSpaceEntry,\r
+ IN UINTN Size,\r
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FFS_FILE_HEADER *PadFileHeader;\r
+ UINTN Offset;\r
+ UINTN NumBytesWritten;\r
+ UINTN StateOffset;\r
+ UINT8 *StartPos;\r
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
+\r
+ if (FreeSpaceEntry->Length < Size + sizeof (EFI_FFS_FILE_HEADER)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if ((Size & 0x07) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StartPos = FreeSpaceEntry->StartingAddress;\r
+\r
+ //\r
+ // First double check the space\r
+ //\r
+ if (!IsBufferErased (\r
+ FvDevice->ErasePolarity,\r
+ StartPos,\r
+ Size + sizeof (EFI_FFS_FILE_HEADER)\r
+ )) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos;\r
+\r
+ //\r
+ // Create File Step 1\r
+ //\r
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+ StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;\r
+\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ StateOffset,\r
+ &NumBytesWritten,\r
+ &PadFileHeader->State\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);\r
+ return Status;\r
+ }\r
+ //\r
+ // Update Free Space Entry, since header is allocated\r
+ //\r
+ FreeSpaceEntry->Length -= sizeof (EFI_FFS_FILE_HEADER);\r
+ FreeSpaceEntry->StartingAddress += sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ //\r
+ // Fill File Name Guid, here we assign a NULL-GUID to Pad files\r
+ //\r
+ ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));\r
+\r
+ //\r
+ // Fill File Type, checksum(0), Attributes(0), Size\r
+ //\r
+ PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;\r
+ PadFileHeader->Attributes = 0;\r
+ *(UINT32 *) PadFileHeader->Size &= 0xFF000000;\r
+ *(UINT32 *) PadFileHeader->Size |= (Size + sizeof (EFI_FFS_FILE_HEADER));\r
+\r
+ SetHeaderChecksum (PadFileHeader);\r
+ SetPadFileChecksum (PadFileHeader);\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_HEADER);\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ Offset,\r
+ &NumBytesWritten,\r
+ (UINT8 *) PadFileHeader\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Step 2, then Mark header valid, since no data write,\r
+ // mark the data valid at the same time.\r
+ //\r
+ SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);\r
+ SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+ StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;\r
+\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ StateOffset,\r
+ &NumBytesWritten,\r
+ &PadFileHeader->State\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);\r
+ SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);\r
+ return Status;\r
+ }\r
+ //\r
+ // Update Free Space Entry, since header is allocated\r
+ //\r
+ FreeSpaceEntry->Length -= Size;\r
+ FreeSpaceEntry->StartingAddress += Size;\r
+\r
+ //\r
+ // If successfully, insert an FfsFileEntry at the end of ffs file list\r
+ //\r
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ ASSERT (FfsFileEntry != NULL);\r
+\r
+ FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) StartPos;\r
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
+\r
+ *PadFileEntry = FfsFileEntry;\r
+ FvDevice->CurrentFfsFile = FfsFileEntry;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Fill pad file header within firmware cache.\r
+ \r
+ @param PadFileHeader The start of the Pad File Buffer.\r
+ @param PadFileLength The length of the pad file including the header.\r
+\r
+**/\r
+VOID\r
+FvFillPadFile (\r
+ IN EFI_FFS_FILE_HEADER *PadFileHeader,\r
+ IN UINTN PadFileLength\r
+ )\r
+{\r
+ //\r
+ // Fill File Name Guid, here we assign a NULL-GUID to Pad files\r
+ //\r
+ ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));\r
+\r
+ //\r
+ // Fill File Type, checksum(0), Attributes(0), Size\r
+ //\r
+ PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;\r
+ PadFileHeader->Attributes = 0;\r
+ *(UINT32 *) PadFileHeader->Size &= 0xFF000000;\r
+ *(UINT32 *) PadFileHeader->Size |= PadFileLength;\r
+\r
+ SetHeaderChecksum (PadFileHeader);\r
+ SetPadFileChecksum (PadFileHeader);\r
+\r
+ //\r
+ // Set File State to 0x00000111\r
+ //\r
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);\r
+ SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);\r
+ SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Create entire FFS file.\r
+ \r
+ @param FileHeader Starting Address of a Buffer that hold the FFS File image.\r
+ @param FfsFileBuffer The source buffer that contains the File Data.\r
+ @param BufferSize The length of FfsFileBuffer.\r
+ @param ActualFileSize Size of FFS file.\r
+ @param FileName The Guid of Ffs File.\r
+ @param FileType The type of the written Ffs File.\r
+ @param FileAttributes The attributes of the written Ffs File.\r
+\r
+ @retval EFI_INVALID_PARAMETER File type is not valid.\r
+ @retval EFI_SUCCESS FFS file is successfully created.\r
+\r
+**/\r
+EFI_STATUS\r
+FvFillFfsFile (\r
+ OUT EFI_FFS_FILE_HEADER *FileHeader,\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_FFS_FILE_ATTRIBUTES TmpFileAttribute;\r
+ EFI_FFS_FILE_HEADER *TmpFileHeader;\r
+\r
+ //\r
+ // File Type value 0x0E~0xE0 are reserved\r
+ //\r
+ if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TmpFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;\r
+ //\r
+ // First fill all fields ready in FfsFileBuffer\r
+ //\r
+ CopyGuid (&TmpFileHeader->Name, FileName);\r
+ TmpFileHeader->Type = FileType;\r
+\r
+ //\r
+ // Convert the FileAttributes to FFSFileAttributes\r
+ //\r
+ FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);\r
+\r
+ TmpFileHeader->Attributes = TmpFileAttribute;\r
+\r
+ *(UINT32 *) TmpFileHeader->Size &= 0xFF000000;\r
+ *(UINT32 *) TmpFileHeader->Size |= ActualFileSize;\r
+\r
+ SetHeaderChecksum (TmpFileHeader);\r
+ SetFileChecksum (TmpFileHeader, ActualFileSize);\r
+\r
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, TmpFileHeader);\r
+ SetFileState (EFI_FILE_HEADER_VALID, TmpFileHeader);\r
+ SetFileState (EFI_FILE_DATA_VALID, TmpFileHeader);\r
+\r
+ //\r
+ // Copy data from FfsFileBuffer to FileHeader(cache)\r
+ //\r
+ CopyMem (FileHeader, FfsFileBuffer, BufferSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Fill some other extra space using 0xFF(Erase Value).\r
+\r
+ @param ErasePolarity Fv erase value.\r
+ @param FileHeader Point to the start of FFS File.\r
+ @param ExtraLength The pading length.\r
+\r
+**/\r
+VOID\r
+FvAdjustFfsFile (\r
+ IN UINT8 ErasePolarity,\r
+ IN EFI_FFS_FILE_HEADER *FileHeader,\r
+ IN UINTN ExtraLength\r
+ )\r
+{\r
+ UINTN FileLength;\r
+ UINT8 *Ptr;\r
+ UINT8 PadingByte;\r
+\r
+ FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;\r
+ Ptr = (UINT8 *) FileHeader + FileLength;\r
+\r
+ if (ErasePolarity == 0) {\r
+ PadingByte = 0;\r
+ } else {\r
+ PadingByte = 0xFF;\r
+ }\r
+ //\r
+ // Fill the non-used space with Padding Byte\r
+ //\r
+ SetMem (Ptr, ExtraLength, PadingByte);\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Free File List entry pointed by FileListHead.\r
+\r
+ @param FileListHeader FileListEntry Header.\r
+\r
+**/\r
+VOID\r
+FreeFileList (\r
+ IN LIST_ENTRY *FileListHead\r
+ )\r
+{\r
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
+ LIST_ENTRY *NextEntry;\r
+\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) (FileListHead->ForwardLink);\r
+\r
+ //\r
+ // Loop the whole list entry to free resources\r
+ //\r
+ while (&FfsFileEntry->Link != FileListHead) {\r
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
+ FreePool (FfsFileEntry);\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Create a new file within a PAD file area.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param FfsFileBuffer A buffer that holds an FFS file,(it contains 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 Successfully create a new file within the found PAD file area.\r
+ @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.\r
+ @retval other errors New file is created failed.\r
+\r
+**/\r
+EFI_STATUS\r
+FvCreateNewFileInsidePadFile (\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
+ UINTN RequiredAlignment;\r
+ FFS_FILE_LIST_ENTRY *PadFileEntry;\r
+ EFI_STATUS Status;\r
+ UINTN PadAreaLength;\r
+ UINTN PadSize;\r
+ EFI_FFS_FILE_HEADER *FileHeader;\r
+ EFI_FFS_FILE_HEADER *OldPadFileHeader;\r
+ EFI_FFS_FILE_HEADER *PadFileHeader;\r
+ EFI_FFS_FILE_HEADER *TailPadFileHeader;\r
+ UINTN StateOffset;\r
+ UINTN Offset;\r
+ UINTN NumBytesWritten;\r
+ UINT8 *StartPos;\r
+ LIST_ENTRY NewFileList;\r
+ FFS_FILE_LIST_ENTRY *NewFileListEntry;\r
+ FFS_FILE_LIST_ENTRY *FfsEntry;\r
+ FFS_FILE_LIST_ENTRY *NextFfsEntry;\r
+\r
+ //\r
+ // First get the required alignment from the File Attributes\r
+ //\r
+ RequiredAlignment = GetRequiredAlignment (FileAttributes);\r
+\r
+ //\r
+ // Find a suitable PAD File\r
+ //\r
+ Status = FvLocatePadFile (\r
+ FvDevice,\r
+ BufferSize,\r
+ RequiredAlignment,\r
+ &PadSize,\r
+ &PadFileEntry\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;\r
+\r
+ //\r
+ // Step 1: Update Pad File Header\r
+ //\r
+ SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldPadFileHeader);\r
+\r
+ StartPos = PadFileEntry->FfsHeader;\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+ StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;\r
+\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ StateOffset,\r
+ &NumBytesWritten,\r
+ &OldPadFileHeader->State\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, OldPadFileHeader);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Step 2: Update Pad area\r
+ //\r
+ InitializeListHead (&NewFileList);\r
+\r
+ PadAreaLength = (*(UINT32 *) OldPadFileHeader->Size & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));\r
+\r
+ if (RequiredAlignment != 8) {\r
+ //\r
+ // Insert a PAD file before to achieve required alignment\r
+ //\r
+ FvFillPadFile (PadFileHeader, PadSize);\r
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ ASSERT (NewFileListEntry != NULL);\r
+ NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;\r
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);\r
+ }\r
+\r
+ FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize);\r
+\r
+ Status = FvFillFfsFile (\r
+ FileHeader,\r
+ FfsFileBuffer,\r
+ BufferSize,\r
+ ActualFileSize,\r
+ FileName,\r
+ FileType,\r
+ FileAttributes\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ ASSERT (NewFileListEntry != NULL);\r
+\r
+ NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;\r
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);\r
+\r
+ FvDevice->CurrentFfsFile = NewFileListEntry;\r
+\r
+ if (PadAreaLength > (BufferSize + PadSize)) {\r
+ if ((PadAreaLength - BufferSize - PadSize) >= sizeof (EFI_FFS_FILE_HEADER)) {\r
+ //\r
+ // we can insert another PAD file\r
+ //\r
+ TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize);\r
+ FvFillPadFile (TailPadFileHeader, PadAreaLength - BufferSize - PadSize);\r
+\r
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ ASSERT (NewFileListEntry != NULL);\r
+\r
+ NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;\r
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);\r
+ } else {\r
+ //\r
+ // because left size cannot hold another PAD file header,\r
+ // adjust the writing file size (just in cache)\r
+ //\r
+ FvAdjustFfsFile (\r
+ FvDevice->ErasePolarity,\r
+ FileHeader,\r
+ PadAreaLength - BufferSize - PadSize\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Start writing to FV\r
+ //\r
+ StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+\r
+ NumBytesWritten = PadAreaLength;\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ Offset,\r
+ &NumBytesWritten,\r
+ StartPos\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeFileList (&NewFileList);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Step 3: Mark Pad file header as EFI_FILE_HEADER_INVALID\r
+ //\r
+ SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);\r
+\r
+ StartPos = PadFileEntry->FfsHeader;\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+ StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;\r
+\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ StateOffset,\r
+ &NumBytesWritten,\r
+ &OldPadFileHeader->State\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If all successfully, update FFS_FILE_LIST\r
+ //\r
+\r
+ //\r
+ // Delete old pad file entry\r
+ //\r
+ FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;\r
+ NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;\r
+\r
+ FreePool (PadFileEntry);\r
+\r
+ FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;\r
+ (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;\r
+ NextFfsEntry->Link.BackLink = NewFileList.BackLink;\r
+ (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free all FfsBuffer.\r
+\r
+ @param NumOfFiles Number of FfsBuffer.\r
+ @param FfsBuffer An array of pointer to an FFS File Buffer\r
+\r
+**/\r
+VOID\r
+FreeFfsBuffer (\r
+ IN UINTN NumOfFiles,\r
+ IN UINT8 **FfsBuffer\r
+ )\r
+{\r
+ UINTN Index;\r
+ for (Index = 0; Index < NumOfFiles; Index++) {\r
+ if (FfsBuffer[Index] != NULL) {\r
+ FreePool (FfsBuffer[Index]);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Create multiple files within a PAD File area.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param PadFileEntry The pad file entry to be written in.\r
+ @param NumOfFiles Total File number to be written.\r
+ @param BufferSize The array of buffer size of each FfsBuffer.\r
+ @param ActualFileSize The array of actual file size.\r
+ @param PadSize The array of leading pad file size for each FFS File\r
+ @param FfsBuffer The array of Ffs Buffer pointer.\r
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure, \r
+ used to get name, attributes, type, etc.\r
+\r
+ @retval EFI_SUCCESS Add the input multiple files into PAD file area.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval other error Files can't be added into PAD file area.\r
+\r
+**/\r
+EFI_STATUS\r
+FvCreateMultipleFilesInsidePadFile (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN FFS_FILE_LIST_ENTRY *PadFileEntry,\r
+ IN UINTN NumOfFiles,\r
+ IN UINTN *BufferSize,\r
+ IN UINTN *ActualFileSize,\r
+ IN UINTN *PadSize,\r
+ IN UINT8 **FfsBuffer,\r
+ IN EFI_FV_WRITE_FILE_DATA *FileData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FFS_FILE_HEADER *OldPadFileHeader;\r
+ UINTN Index;\r
+ EFI_FFS_FILE_HEADER *PadFileHeader;\r
+ EFI_FFS_FILE_HEADER *FileHeader;\r
+ EFI_FFS_FILE_HEADER *TailPadFileHeader;\r
+ UINTN TotalSize;\r
+ UINTN PadAreaLength;\r
+ LIST_ENTRY NewFileList;\r
+ FFS_FILE_LIST_ENTRY *NewFileListEntry;\r
+ UINTN Offset;\r
+ UINTN NumBytesWritten;\r
+ UINT8 *StartPos;\r
+ FFS_FILE_LIST_ENTRY *FfsEntry;\r
+ FFS_FILE_LIST_ENTRY *NextFfsEntry;\r
+\r
+ InitializeListHead (&NewFileList);\r
+\r
+ NewFileListEntry = NULL;\r
+\r
+ OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;\r
+ PadAreaLength = (*(UINT32 *) OldPadFileHeader->Size & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ Status = UpdateHeaderBit (\r
+ FvDevice,\r
+ OldPadFileHeader,\r
+ EFI_FILE_MARKED_FOR_UPDATE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Update PAD area\r
+ //\r
+ TotalSize = 0;\r
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));\r
+ FileHeader = PadFileHeader;\r
+\r
+ for (Index = 0; Index < NumOfFiles; Index++) {\r
+ if (PadSize[Index] != 0) {\r
+ FvFillPadFile (PadFileHeader, PadSize[Index]);\r
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ if (NewFileListEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;\r
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);\r
+ }\r
+\r
+ FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]);\r
+ Status = FvFillFfsFile (\r
+ FileHeader,\r
+ FfsBuffer[Index],\r
+ BufferSize[Index],\r
+ ActualFileSize[Index],\r
+ FileData[Index].NameGuid,\r
+ FileData[Index].Type,\r
+ FileData[Index].FileAttributes\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ if (NewFileListEntry == NULL) {\r
+ FreeFileList (&NewFileList);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;\r
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);\r
+\r
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]);\r
+ TotalSize += PadSize[Index];\r
+ TotalSize += BufferSize[Index];\r
+ }\r
+\r
+ FvDevice->CurrentFfsFile = NewFileListEntry;\r
+ //\r
+ // Maybe we need a tail pad file\r
+ //\r
+ if (PadAreaLength > TotalSize) {\r
+ if ((PadAreaLength - TotalSize) >= sizeof (EFI_FFS_FILE_HEADER)) {\r
+ //\r
+ // we can insert another PAD file\r
+ //\r
+ TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[NumOfFiles - 1]);\r
+ FvFillPadFile (TailPadFileHeader, PadAreaLength - TotalSize);\r
+\r
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ if (NewFileListEntry == NULL) {\r
+ FreeFileList (&NewFileList);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;\r
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);\r
+ } else {\r
+ //\r
+ // because left size cannot hold another PAD file header,\r
+ // adjust the writing file size (just in cache)\r
+ //\r
+ FvAdjustFfsFile (\r
+ FvDevice->ErasePolarity,\r
+ FileHeader,\r
+ PadAreaLength - TotalSize\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Start writing to FV\r
+ //\r
+ StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);\r
+\r
+ NumBytesWritten = PadAreaLength;\r
+ Status = FvcWrite (\r
+ FvDevice,\r
+ Offset,\r
+ &NumBytesWritten,\r
+ StartPos\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeFileList (&NewFileList);\r
+ return Status;\r
+ }\r
+\r
+ Status = UpdateHeaderBit (\r
+ FvDevice,\r
+ OldPadFileHeader,\r
+ EFI_FILE_HEADER_INVALID\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeFileList (&NewFileList);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Update File List Link\r
+ //\r
+\r
+ //\r
+ // First delete old pad file entry\r
+ //\r
+ FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;\r
+ NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;\r
+\r
+ FreePool (PadFileEntry);\r
+\r
+ FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;\r
+ (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;\r
+ NextFfsEntry->Link.BackLink = NewFileList.BackLink;\r
+ (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write multiple files into FV in reliable method.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param NumOfFiles Total File number to be written.\r
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure, \r
+ used to get name, attributes, type, etc\r
+ @param FileOperation The array of operation for each file.\r
+\r
+ @retval EFI_SUCCESS Files are added into FV.\r
+ @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.\r
+ @retval EFI_INVALID_PARAMETER File number is less than or equal to 1.\r
+ @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.\r
+\r
+**/\r
+EFI_STATUS\r
+FvCreateMultipleFiles (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN UINTN NumOfFiles,\r
+ IN EFI_FV_WRITE_FILE_DATA *FileData,\r
+ IN BOOLEAN *FileOperation\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *FfsBuffer[MAX_FILES];\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ UINTN BufferSize[MAX_FILES];\r
+ UINTN ActualFileSize[MAX_FILES];\r
+ UINTN RequiredAlignment[MAX_FILES];\r
+ UINTN PadSize[MAX_FILES];\r
+ FFS_FILE_LIST_ENTRY *PadFileEntry;\r
+ UINTN TotalSizeNeeded;\r
+ FREE_SPACE_ENTRY *FreeSpaceEntry;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+ UINTN Key;\r
+ EFI_GUID FileNameGuid;\r
+ EFI_FV_FILETYPE OldFileType;\r
+ EFI_FV_FILE_ATTRIBUTES OldFileAttributes;\r
+ UINTN OldFileSize;\r
+ FFS_FILE_LIST_ENTRY *OldFfsFileEntry[MAX_FILES];\r
+ EFI_FFS_FILE_HEADER *OldFileHeader[MAX_FILES];\r
+ BOOLEAN IsCreateFile;\r
+\r
+ //\r
+ // To use this function, we must ensure that the NumOfFiles is great\r
+ // than 1\r
+ //\r
+ if (NumOfFiles <= 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (NumOfFiles > MAX_FILES) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Fv = &FvDevice->Fv;\r
+\r
+ SetMem (FfsBuffer, NumOfFiles, 0);\r
+ SetMem (RequiredAlignment, NumOfFiles, 8);\r
+ SetMem (PadSize, NumOfFiles, 0);\r
+ ZeroMem (OldFfsFileEntry, sizeof (OldFfsFileEntry));\r
+ ZeroMem (OldFileHeader, sizeof (OldFileHeader));\r
+\r
+ //\r
+ // Adjust file size\r
+ //\r
+ for (Index1 = 0; Index1 < NumOfFiles; Index1++) {\r
+ ActualFileSize[Index1] = FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER);\r
+ BufferSize[Index1] = ActualFileSize[Index1];\r
+\r
+ if (BufferSize[Index1] == sizeof (EFI_FFS_FILE_HEADER)) {\r
+ //\r
+ // clear file attributes, zero-length file does not have any attributes\r
+ //\r
+ FileData[Index1].FileAttributes = 0;\r
+ }\r
+\r
+ while ((BufferSize[Index1] & 0x07) != 0) {\r
+ BufferSize[Index1]++;\r
+ }\r
+\r
+ FfsBuffer[Index1] = AllocateZeroPool (BufferSize[Index1]);\r
+\r
+ //\r
+ // Copy File Data into FileBuffer\r
+ //\r
+ CopyMem (\r
+ FfsBuffer[Index1] + sizeof (EFI_FFS_FILE_HEADER),\r
+ FileData[Index1].Buffer,\r
+ FileData[Index1].BufferSize\r
+ );\r
+\r
+ if (FvDevice->ErasePolarity == 1) {\r
+ for (Index2 = 0; Index2 < sizeof (EFI_FFS_FILE_HEADER); Index2++) {\r
+ FfsBuffer[Index1][Index2] = (UINT8)~FfsBuffer[Index1][Index2];\r
+ }\r
+ }\r
+\r
+ if ((FileData[Index1].FileAttributes & FFS_ATTRIB_DATA_ALIGNMENT) != 0) {\r
+ RequiredAlignment[Index1] = GetRequiredAlignment (FileData[Index1].FileAttributes);\r
+ }\r
+ //\r
+ // If update file, mark the original file header to\r
+ // EFI_FILE_MARKED_FOR_UPDATE\r
+ //\r
+ IsCreateFile = FileOperation[Index1];\r
+ if (!IsCreateFile) {\r
+\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
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);\r
+ return Status;\r
+ }\r
+ } while (!CompareGuid (&FileNameGuid, FileData[Index1].NameGuid));\r
+\r
+ //\r
+ // Get FfsFileEntry from the search key\r
+ //\r
+ OldFfsFileEntry[Index1] = (FFS_FILE_LIST_ENTRY *) Key;\r
+ OldFileHeader[Index1] = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry[Index1]->FfsHeader;\r
+ Status = UpdateHeaderBit (\r
+ FvDevice,\r
+ OldFileHeader[Index1],\r
+ EFI_FILE_MARKED_FOR_UPDATE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // First to search a suitable pad file that can hold so\r
+ // many files\r
+ //\r
+ Status = FvSearchSuitablePadFile (\r
+ FvDevice,\r
+ NumOfFiles,\r
+ BufferSize,\r
+ RequiredAlignment,\r
+ PadSize,\r
+ &TotalSizeNeeded,\r
+ &PadFileEntry\r
+ );\r
+\r
+ if (Status == EFI_NOT_FOUND) {\r
+ //\r
+ // Try to find a free space that can hold these files\r
+ // and create a suitable PAD file in this free space\r
+ //\r
+ Status = FvSearchSuitableFreeSpace (\r
+ FvDevice,\r
+ NumOfFiles,\r
+ BufferSize,\r
+ RequiredAlignment,\r
+ PadSize,\r
+ &TotalSizeNeeded,\r
+ &FreeSpaceEntry\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Create a PAD file in that space\r
+ //\r
+ Status = FvCreatePadFileInFreeSpace (\r
+ FvDevice,\r
+ FreeSpaceEntry,\r
+ TotalSizeNeeded,\r
+ &PadFileEntry\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Create multiple files inside such a pad file\r
+ // to achieve lock-step update\r
+ //\r
+ Status = FvCreateMultipleFilesInsidePadFile (\r
+ FvDevice,\r
+ PadFileEntry,\r
+ NumOfFiles,\r
+ BufferSize,\r
+ ActualFileSize,\r
+ PadSize,\r
+ FfsBuffer,\r
+ FileData\r
+ );\r
+\r
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Delete those updated files\r
+ //\r
+ for (Index1 = 0; Index1 < NumOfFiles; Index1++) {\r
+ IsCreateFile = FileOperation[Index1];\r
+ if (!IsCreateFile && OldFfsFileEntry[Index1] != NULL) {\r
+ (OldFfsFileEntry[Index1]->Link.BackLink)->ForwardLink = OldFfsFileEntry[Index1]->Link.ForwardLink;\r
+ (OldFfsFileEntry[Index1]->Link.ForwardLink)->BackLink = OldFfsFileEntry[Index1]->Link.BackLink;\r
+ FreePool (OldFfsFileEntry[Index1]);\r
+ }\r
+ }\r
+ //\r
+ // Set those files' state to EFI_FILE_DELETED\r
+ //\r
+ for (Index1 = 0; Index1 < NumOfFiles; Index1++) {\r
+ IsCreateFile = FileOperation[Index1];\r
+ if (!IsCreateFile && OldFileHeader[Index1] != NULL) {\r
+ Status = UpdateHeaderBit (FvDevice, OldFileHeader[Index1], EFI_FILE_DELETED);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Firmware File System driver that produce full Firmware Volume2 protocol.\r
+ Layers on top of Firmware Block protocol to produce a file abstraction\r
+ of FV based files.\r
+\r
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FwVolDriver.h"\r
+\r
+#define KEYSIZE sizeof (UINTN)\r
+\r
+/**\r
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
+ copy the real length volume header into it.\r
+\r
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to\r
+ read the volume header\r
+ @param FwVolHeader Pointer to pointer to allocated buffer in which\r
+ the volume header is returned.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
+ @retval EFI_SUCCESS Successfully read volume header to the allocated\r
+ buffer.\r
+ @retval EFI_ACCESS_DENIED Read status of FV is not enabled.\r
+**/\r
+EFI_STATUS\r
+GetFwVolHeader (\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
+ UINTN FvhLength;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+\r
+ //\r
+ // Determine the real length of FV header\r
+ //\r
+ Status = Fvb->GetAttributes (\r
+ Fvb,\r
+ &FvbAttributes\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Just avoid compiling warning\r
+ //\r
+ BaseAddress = 0;\r
+ FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
+\r
+ //\r
+ // memory-mapped FV and non memory-mapped has different ways to read\r
+ //\r
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
+ Status = Fvb->GetPhysicalAddress (\r
+ Fvb,\r
+ &BaseAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ CopyMem (&TempFvh, (VOID *) (UINTN) BaseAddress, FvhLength);\r
+ } else {\r
+ Status = Fvb->Read (\r
+ Fvb,\r
+ 0,\r
+ 0,\r
+ &FvhLength,\r
+ (UINT8 *) &TempFvh\r
+ );\r
+ }\r
+\r
+ *FwVolHeader = AllocatePool (TempFvh.HeaderLength);\r
+ if (*FwVolHeader == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Read the whole header\r
+ //\r
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
+ CopyMem (*FwVolHeader, (VOID *) (UINTN) BaseAddress, TempFvh.HeaderLength);\r
+ } else {\r
+ //\r
+ // Assumed the first block is bigger than the length of Fv headder\r
+ //\r
+ FvhLength = TempFvh.HeaderLength;\r
+ Status = Fvb->Read (\r
+ Fvb,\r
+ 0,\r
+ 0,\r
+ &FvhLength,\r
+ (UINT8 *) *FwVolHeader\r
+ );\r
+ //\r
+ // Check whether Read successes.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (*FwVolHeader);\r
+ *FwVolHeader = NULL;\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free FvDevice resource when error happens.\r
+\r
+ @param FvDevice Pointer to the FvDevice to be freed.\r
+**/\r
+VOID\r
+FreeFvDeviceResource (\r
+ IN FV_DEVICE *FvDevice\r
+ )\r
+{\r
+ LBA_ENTRY *LbaEntry;\r
+ FREE_SPACE_ENTRY *FreeSpaceEntry;\r
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
+ LIST_ENTRY *NextEntry;\r
+\r
+ //\r
+ // Free LAB Entry\r
+ //\r
+ LbaEntry = (LBA_ENTRY *) FvDevice->LbaHeader.ForwardLink;\r
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {\r
+ NextEntry = (&LbaEntry->Link)->ForwardLink;\r
+ FreePool (LbaEntry);\r
+ LbaEntry = (LBA_ENTRY *) NextEntry;\r
+ }\r
+ //\r
+ // Free File List Entry\r
+ //\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;\r
+ while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {\r
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
+ FreePool (FfsFileEntry);\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
+ }\r
+ //\r
+ // Free Space Entry\r
+ //\r
+ FreeSpaceEntry = (FREE_SPACE_ENTRY *) FvDevice->FreeSpaceHeader.ForwardLink;\r
+ while (&FreeSpaceEntry->Link != &FvDevice->FreeSpaceHeader) {\r
+ NextEntry = (&FreeSpaceEntry->Link)->ForwardLink;\r
+ FreePool (FreeSpaceEntry);\r
+ FreeSpaceEntry = (FREE_SPACE_ENTRY *) NextEntry;\r
+ }\r
+ //\r
+ // Free the cache\r
+ //\r
+ FreePool ((UINT8 *) (UINTN) FvDevice->CachedFv);\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Check if an FV is consistent and allocate cache for it.\r
+\r
+ @param FvDevice A pointer to the FvDevice to be checked.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
+ @retval EFI_VOLUME_CORRUPTED File system is corrupted.\r
+ @retval EFI_SUCCESS FV is consistent and cache is allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+FvCheck (\r
+ IN FV_DEVICE *FvDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+ UINT8 *FwCache;\r
+ LBA_ENTRY *LbaEntry;\r
+ FREE_SPACE_ENTRY *FreeSpaceEntry;\r
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
+ UINT8 *LbaStart;\r
+ UINTN Index;\r
+ EFI_LBA LbaIndex;\r
+ UINT8 *Ptr;\r
+ UINTN Size;\r
+ UINT8 *FreeStart;\r
+ UINTN FreeSize;\r
+ UINT8 ErasePolarity;\r
+ UINTN FileLength;\r
+ EFI_FFS_FILE_STATE FileState;\r
+ UINT8 *TopFvAddress;\r
+ UINTN TestLength;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+\r
+ Fvb = FvDevice->Fvb;\r
+\r
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ InitializeListHead (&FvDevice->LbaHeader);\r
+ InitializeListHead (&FvDevice->FreeSpaceHeader);\r
+ InitializeListHead (&FvDevice->FfsFileListHeader);\r
+\r
+ FwVolHeader = NULL;\r
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ASSERT (FwVolHeader != NULL);\r
+\r
+ //\r
+ // Double Check firmware volume header here\r
+ //\r
+ if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
+ FreePool (FwVolHeader);\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ BlockMap = FwVolHeader->BlockMap;\r
+\r
+ //\r
+ // FwVolHeader->FvLength is the whole FV length including FV header\r
+ //\r
+ FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);\r
+ if (FwCache == NULL) {\r
+ FreePool (FwVolHeader);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;\r
+\r
+ //\r
+ // Copy to memory\r
+ //\r
+ LbaStart = FwCache;\r
+ LbaIndex = 0;\r
+ Ptr = NULL;\r
+\r
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
+ //\r
+ // Get volume base address\r
+ //\r
+ Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (FwVolHeader);\r
+ return Status;\r
+ }\r
+\r
+ Ptr = (UINT8 *) ((UINTN) BaseAddress);\r
+\r
+ DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));\r
+ }\r
+ //\r
+ // Copy whole FV into the memory\r
+ //\r
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
+\r
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {\r
+ LbaEntry = AllocatePool (sizeof (LBA_ENTRY));\r
+ if (LbaEntry == NULL) {\r
+ FreePool (FwVolHeader);\r
+ FreeFvDeviceResource (FvDevice);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ LbaEntry->LbaIndex = LbaIndex;\r
+ LbaEntry->StartingAddress = LbaStart;\r
+ LbaEntry->BlockLength = BlockMap->Length;\r
+\r
+ //\r
+ // Copy each LBA into memory\r
+ //\r
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
+\r
+ CopyMem (LbaStart, Ptr, BlockMap->Length);\r
+ Ptr += BlockMap->Length;\r
+\r
+ } else {\r
+\r
+ Size = BlockMap->Length;\r
+ Status = Fvb->Read (\r
+ Fvb,\r
+ LbaIndex,\r
+ 0,\r
+ &Size,\r
+ LbaStart\r
+ );\r
+ //\r
+ // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (FwVolHeader);\r
+ FreeFvDeviceResource (FvDevice);\r
+ return Status;\r
+ }\r
+\r
+ }\r
+\r
+ LbaIndex++;\r
+ LbaStart += BlockMap->Length;\r
+\r
+ InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);\r
+ }\r
+\r
+ BlockMap++;\r
+ }\r
+\r
+ FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;\r
+\r
+ //\r
+ // it is not used any more, so free FwVolHeader\r
+ //\r
+ FreePool (FwVolHeader);\r
+\r
+ //\r
+ // Scan to check the free space & File list\r
+ //\r
+ if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
+ ErasePolarity = 1;\r
+ } else {\r
+ ErasePolarity = 0;\r
+ }\r
+\r
+ FvDevice->ErasePolarity = ErasePolarity;\r
+\r
+ //\r
+ // go through the whole FV cache, check the consistence of the FV\r
+ //\r
+ Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);\r
+ TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength - 1);\r
+\r
+ //\r
+ // Build FFS list & Free Space List here\r
+ //\r
+ while (Ptr <= TopFvAddress) {\r
+ TestLength = TopFvAddress - Ptr + 1;\r
+\r
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
+ }\r
+\r
+ if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {\r
+ //\r
+ // We found free space\r
+ //\r
+ FreeStart = Ptr;\r
+ FreeSize = 0;\r
+\r
+ do {\r
+ TestLength = TopFvAddress - Ptr + 1;\r
+\r
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
+ }\r
+\r
+ if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {\r
+ break;\r
+ }\r
+\r
+ FreeSize += TestLength;\r
+ Ptr += TestLength;\r
+ } while (Ptr <= TopFvAddress);\r
+\r
+ FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));\r
+ if (FreeSpaceEntry == NULL) {\r
+ FreeFvDeviceResource (FvDevice);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Create a Free space entry\r
+ //\r
+ FreeSpaceEntry->StartingAddress = FreeStart;\r
+ FreeSpaceEntry->Length = FreeSize;\r
+ InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);\r
+ continue;\r
+ }\r
+ //\r
+ // double check boundry\r
+ //\r
+ if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {\r
+ break;\r
+ }\r
+\r
+ if (!IsValidFFSHeader (\r
+ FvDevice->ErasePolarity,\r
+ (EFI_FFS_FILE_HEADER *) Ptr\r
+ )) {\r
+ FileState = GetFileState (\r
+ FvDevice->ErasePolarity,\r
+ (EFI_FFS_FILE_HEADER *) Ptr\r
+ );\r
+ if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
+ Ptr += sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ continue;\r
+\r
+ } else {\r
+ //\r
+ // File system is corrputed, return\r
+ //\r
+ FreeFvDeviceResource (FvDevice);\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+ }\r
+\r
+ if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {\r
+ FileLength = *(UINT32 *) ((EFI_FFS_FILE_HEADER *) Ptr)->Size & 0x00FFFFFF;\r
+ FileState = GetFileState (\r
+ FvDevice->ErasePolarity,\r
+ (EFI_FFS_FILE_HEADER *) Ptr\r
+ );\r
+\r
+ //\r
+ // check for non-deleted file\r
+ //\r
+ if (FileState != EFI_FILE_DELETED) {\r
+ //\r
+ // Create a FFS list entry for each non-deleted file\r
+ //\r
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
+ if (FfsFileEntry == NULL) {\r
+ FreeFvDeviceResource (FvDevice);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ FfsFileEntry->FfsHeader = Ptr;\r
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
+ }\r
+\r
+ Ptr += FileLength;\r
+\r
+ //\r
+ // Adjust Ptr to the next 8-byte aligned boundry.\r
+ //\r
+ while (((UINTN) Ptr & 0x07) != 0) {\r
+ Ptr++;\r
+ }\r
+ } else {\r
+ //\r
+ // File system is corrupted, return\r
+ //\r
+ FreeFvDeviceResource (FvDevice);\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+ }\r
+\r
+ FvDevice->CurrentFfsFile = NULL;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Entry point function does install/reinstall FV2 protocol with full functionality.\r
+\r
+ @param ImageHandle A handle for the image that is initializing this driver\r
+ @param SystemTable A pointer to the EFI system table\r
+\r
+ @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.\r
+ @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FwVolDriverInit (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+ FV_DEVICE *FvDevice;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+ BOOLEAN Reinstall;\r
+ BOOLEAN InstallFlag;\r
+\r
+ DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));\r
+ InstallFlag = FALSE;\r
+ //\r
+ // Locate all handles of Fvb protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Get FV with gEfiFirmwareFileSystemGuid\r
+ //\r
+ for (Index = 0; Index < HandleCount; Index += 1) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID **) &Fvb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ FwVolHeader = NULL;\r
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ ASSERT (FwVolHeader != NULL);\r
+ //\r
+ // Check to see that the file system is indeed formatted in a way we can\r
+ // understand it...\r
+ //\r
+ if (!CompareGuid (\r
+ &FwVolHeader->FileSystemGuid,\r
+ &gEfiFirmwareFileSystem2Guid\r
+ )) {\r
+ FreePool (FwVolHeader);\r
+ continue;\r
+ }\r
+ FreePool (FwVolHeader);\r
+\r
+ Reinstall = FALSE;\r
+ //\r
+ // Check if there is an FV protocol already installed in that handle\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ (VOID **) &Fv\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Reinstall = TRUE;\r
+ }\r
+ //\r
+ // FwVol protocol on the handle so create a new one\r
+ //\r
+ FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));\r
+ if (FvDevice == NULL) {\r
+ goto Done;\r
+ }\r
+\r
+ FvDevice->Signature = FV_DEVICE_SIGNATURE;\r
+ FvDevice->Fvb = Fvb;\r
+\r
+ //\r
+ // Firmware Volume Protocol interface\r
+ //\r
+ FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;\r
+ FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;\r
+ FvDevice->Fv.ReadFile = FvReadFile;\r
+ FvDevice->Fv.ReadSection = FvReadFileSection;\r
+ FvDevice->Fv.WriteFile = FvWriteFile;\r
+ FvDevice->Fv.GetNextFile = FvGetNextFile;\r
+ FvDevice->Fv.KeySize = KEYSIZE;\r
+ FvDevice->Fv.GetInfo = FvGetVolumeInfo;\r
+ FvDevice->Fv.SetInfo = FvSetVolumeInfo;\r
+\r
+ Status = FvCheck (FvDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // The file system is not consistence\r
+ //\r
+ FreePool (FvDevice);\r
+ continue;\r
+ }\r
+\r
+ if (Reinstall) {\r
+ //\r
+ // Reinstall an New FV protocol\r
+ //\r
+ // FvDevice = FV_DEVICE_FROM_THIS (Fv);\r
+ // FvDevice->Fvb = Fvb;\r
+ // FreeFvDeviceResource (FvDevice);\r
+ //\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ Fv,\r
+ &FvDevice->Fv\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ InstallFlag = TRUE;\r
+ } else {\r
+ FreePool (FvDevice);\r
+ }\r
+ \r
+ DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ //\r
+ // Install an New FV protocol\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &FvDevice->Handle,\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &FvDevice->Fv\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ InstallFlag = TRUE;\r
+ } else {\r
+ FreePool (FvDevice);\r
+ }\r
+ \r
+ DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+Done:\r
+ //\r
+ // As long as one Fv protocol install/reinstall successfully,\r
+ // success should return to ensure this image will be not unloaded.\r
+ // Otherwise, new Fv protocols are corrupted by other loaded driver.\r
+ //\r
+ if (InstallFlag) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ \r
+ //\r
+ // No FV protocol install/reinstall successfully.\r
+ // EFI_NOT_FOUND should return to ensure this image will be unloaded.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Implements get/set firmware volume attributes.\r
+\r
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FwVolDriver.h"\r
+\r
+/**\r
+ Retrieves attributes, insures positive polarity of attribute bits, returns\r
+ resulting attributes in output parameter.\r
+\r
+ @param This Calling context\r
+ @param Attributes output buffer which contains attributes\r
+\r
+ @retval EFI_SUCCESS Successfully got volume attributes\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvGetVolumeAttributes (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ OUT EFI_FV_ATTRIBUTES *Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FV_DEVICE *FvDevice;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
+\r
+ FvDevice = FV_DEVICE_FROM_THIS (This);\r
+ Fvb = FvDevice->Fvb;\r
+\r
+ //\r
+ // First get the Firmware Volume Block Attributes\r
+ //\r
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
+ FvbAttributes &= 0xfffff0ff;\r
+\r
+ *Attributes = FvbAttributes;\r
+ *Attributes |= EFI_FV2_WRITE_POLICY_RELIABLE;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sets current attributes for volume.\r
+\r
+ @param This Calling context\r
+ @param Attributes On input, FvAttributes is a pointer to\r
+ an EFI_FV_ATTRIBUTES containing the\r
+ desired firmware volume settings. On\r
+ successful return, it contains the new\r
+ settings of the firmware volume. On\r
+ unsuccessful return, FvAttributes is not\r
+ modified and the firmware volume\r
+ settings are not changed.\r
+ \r
+ @retval EFI_SUCCESS The requested firmware volume attributes\r
+ were set and the resulting\r
+ EFI_FV_ATTRIBUTES is returned in\r
+ FvAttributes.\r
+ @retval EFI_ACCESS_DENIED Atrribute is locked down.\r
+ @retval EFI_INVALID_PARAMETER Atrribute is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvSetVolumeAttributes (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN OUT EFI_FV_ATTRIBUTES *Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FV_DEVICE *FvDevice;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FVB_ATTRIBUTES_2 OldFvbAttributes;\r
+ EFI_FVB_ATTRIBUTES_2 NewFvbAttributes;\r
+ UINT64 NewStatus;\r
+ UINT32 Capabilities;\r
+\r
+ FvDevice = FV_DEVICE_FROM_THIS (This);\r
+ Fvb = FvDevice->Fvb;\r
+\r
+ //\r
+ // First get the current Volume Attributes\r
+ //\r
+ Status = Fvb->GetAttributes (\r
+ Fvb,\r
+ &OldFvbAttributes\r
+ );\r
+\r
+ if ((OldFvbAttributes & EFI_FVB2_LOCK_STATUS) != 0) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // Only status attributes can be updated.\r
+ //\r
+ Capabilities = OldFvbAttributes & EFI_FVB2_CAPABILITIES;\r
+ NewStatus = (*Attributes) & EFI_FVB2_STATUS;\r
+\r
+ //\r
+ // Test read disable\r
+ //\r
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Test read enable\r
+ //\r
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
+ if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Test write disable\r
+ //\r
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Test write enable\r
+ //\r
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Test lock\r
+ //\r
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
+ if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ NewFvbAttributes = OldFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
+ NewFvbAttributes |= NewStatus;\r
+ Status = Fvb->SetAttributes (\r
+ Fvb,\r
+ &NewFvbAttributes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *Attributes = 0;\r
+\r
+ This->GetVolumeAttributes (\r
+ This,\r
+ Attributes\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return information of type InformationType for the requested firmware\r
+ volume.\r
+\r
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.\r
+ @param InformationType InformationType for requested.\r
+ @param BufferSize On input, size of Buffer.On output, the amount of\r
+ data returned in Buffer.\r
+ @param Buffer A poniter to the data buffer to return.\r
+\r
+ @return EFI_UNSUPPORTED Could not get.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvGetVolumeInfo (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *InformationType,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Set information with InformationType into the requested firmware volume.\r
+\r
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.\r
+ @param InformationType InformationType for requested.\r
+ @param BufferSize Size of Buffer data.\r
+ @param Buffer A poniter to the data buffer to be set.\r
+\r
+ @retval EFI_UNSUPPORTED Could not set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvSetVolumeInfo (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *InformationType,\r
+ IN UINTN BufferSize,\r
+ IN CONST VOID *Buffer\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file\r
+ Common defines and definitions for a FwVolDxe driver.\r
+\r
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FWVOL_DRIVER_H_\r
+#define _FWVOL_DRIVER_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Guid/FirmwareFileSystem2.h>\r
+#include <Protocol/SectionExtraction.h>\r
+#include <Protocol/FaultTolerantWrite.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#define FV_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '_')\r
+\r
+//\r
+// Define two helper macro to extract the Capability field or Status field in FVB\r
+// bit fields\r
+//\r
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \\r
+ EFI_FVB2_READ_ENABLED_CAP | \\r
+ EFI_FVB2_WRITE_DISABLED_CAP | \\r
+ EFI_FVB2_WRITE_ENABLED_CAP | \\r
+ EFI_FVB2_LOCK_CAP \\r
+ )\r
+\r
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)\r
+\r
+#define MAX_FILES 32\r
+\r
+//\r
+// Used to caculate from address -> Lba\r
+//\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+ EFI_LBA LbaIndex;\r
+ UINT8 *StartingAddress;\r
+ UINTN BlockLength;\r
+} LBA_ENTRY;\r
+\r
+//\r
+// Used to track free space in the Fv\r
+//\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+ UINT8 *StartingAddress;\r
+ UINTN Length;\r
+} FREE_SPACE_ENTRY;\r
+\r
+//\r
+// Used to track all non-deleted files\r
+//\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+ UINT8 *FfsHeader;\r
+} FFS_FILE_LIST_ENTRY;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+ UINT8 *Key;\r
+ EFI_HANDLE Handle;\r
+\r
+ UINT8 ErasePolarity;\r
+ EFI_PHYSICAL_ADDRESS CachedFv;\r
+ LIST_ENTRY LbaHeader;\r
+ LIST_ENTRY FreeSpaceHeader;\r
+ LIST_ENTRY FfsFileListHeader;\r
+\r
+ FFS_FILE_LIST_ENTRY *CurrentFfsFile;\r
+\r
+} FV_DEVICE;\r
+\r
+#define FV_DEVICE_FROM_THIS(a) CR (a, FV_DEVICE, Fv, FV_DEVICE_SIGNATURE)\r
+\r
+/**\r
+ Retrieves attributes, insures positive polarity of attribute bits, returns\r
+ resulting attributes in output parameter.\r
+\r
+ @param This Calling context\r
+ @param Attributes output buffer which contains attributes\r
+\r
+ @retval EFI_SUCCESS Successfully got volume attributes\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvGetVolumeAttributes (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ OUT EFI_FV_ATTRIBUTES *Attributes\r
+ );\r
+\r
+/**\r
+ Sets current attributes for volume.\r
+\r
+ @param This Calling context\r
+ @param Attributes On input, FvAttributes is a pointer to\r
+ an EFI_FV_ATTRIBUTES containing the\r
+ desired firmware volume settings. On\r
+ successful return, it contains the new\r
+ settings of the firmware volume. On\r
+ unsuccessful return, FvAttributes is not\r
+ modified and the firmware volume\r
+ settings are not changed.\r
+ \r
+ @retval EFI_SUCCESS The requested firmware volume attributes\r
+ were set and the resulting\r
+ EFI_FV_ATTRIBUTES is returned in\r
+ FvAttributes.\r
+ @retval EFI_ACCESS_DENIED Atrribute is locked down.\r
+ @retval EFI_INVALID_PARAMETER Atrribute is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvSetVolumeAttributes (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN OUT EFI_FV_ATTRIBUTES *Attributes\r
+ );\r
+\r
+/**\r
+ Given the input key, search for the next matching file in the volume.\r
+\r
+ @param This Indicates the calling context.\r
+ @param Key Key is a pointer to a caller allocated\r
+ buffer that contains implementation specific\r
+ data that is used to track where to begin\r
+ the search for the next file. The size of\r
+ the buffer must be at least This->KeySize\r
+ bytes long. To reinitialize the search and\r
+ begin from the beginning of the firmware\r
+ volume, the entire buffer must be cleared to\r
+ zero. Other than clearing the buffer to\r
+ initiate a new search, the caller must not\r
+ modify the data in the buffer between calls\r
+ to GetNextFile().\r
+ @param FileType FileType is a pointer to a caller allocated\r
+ EFI_FV_FILETYPE. The GetNextFile() API can\r
+ filter it's search for files based on the\r
+ value of *FileType input. A *FileType input\r
+ of 0 causes GetNextFile() to search for\r
+ files of all types. If a file is found, the\r
+ file's type is returned in *FileType.\r
+ *FileType is not modified if no file is\r
+ found.\r
+ @param NameGuid NameGuid is a pointer to a caller allocated\r
+ EFI_GUID. If a file is found, the file's\r
+ name is returned in *NameGuid. *NameGuid is\r
+ not modified if no file is found.\r
+ @param Attributes Attributes is a pointer to a caller\r
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file\r
+ is found, the file's attributes are returned\r
+ in *Attributes. *Attributes is not modified\r
+ if no file is found.\r
+ @param Size Size is a pointer to a caller allocated\r
+ UINTN. If a file is found, the file's size\r
+ is returned in *Size. *Size is not modified\r
+ if no file is found.\r
+\r
+ @retval EFI_SUCCESS Successfully find the file.\r
+ @retval EFI_DEVICE_ERROR Device error.\r
+ @retval EFI_ACCESS_DENIED Fv could not read.\r
+ @retval EFI_NOT_FOUND No matching file found.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvGetNextFile (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN OUT VOID *Key,\r
+ IN OUT EFI_FV_FILETYPE *FileType,\r
+ OUT EFI_GUID *NameGuid,\r
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,\r
+ OUT UINTN *Size\r
+ );\r
+\r
+/**\r
+ Locates a file in the firmware volume and\r
+ copies it to the supplied buffer.\r
+\r
+ @param This Indicates the calling context.\r
+ @param NameGuid Pointer to an EFI_GUID, which is the\r
+ filename.\r
+ @param Buffer Buffer is a pointer to pointer to a buffer\r
+ in which the file or section contents or are\r
+ returned.\r
+ @param BufferSize BufferSize is a pointer to caller allocated\r
+ UINTN. On input *BufferSize indicates the\r
+ size in bytes of the memory region pointed\r
+ to by Buffer. On output, *BufferSize\r
+ contains the number of bytes required to\r
+ read the file.\r
+ @param FoundType FoundType is a pointer to a caller allocated\r
+ EFI_FV_FILETYPE that on successful return\r
+ from Read() contains the type of file read.\r
+ This output reflects the file type\r
+ irrespective of the value of the SectionType\r
+ input.\r
+ @param FileAttributes FileAttributes is a pointer to a caller\r
+ allocated EFI_FV_FILE_ATTRIBUTES. On\r
+ successful return from Read(),\r
+ *FileAttributes contains the attributes of\r
+ the file read.\r
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a\r
+ caller allocated UINTN in which the\r
+ authentication status is returned.\r
+\r
+ @retval EFI_SUCCESS Successfully read to memory buffer.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.\r
+ @retval EFI_NOT_FOUND Not found.\r
+ @retval EFI_DEVICE_ERROR Device error.\r
+ @retval EFI_ACCESS_DENIED Could not read.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvReadFile (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *NameGuid,\r
+ IN OUT VOID **Buffer,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT EFI_FV_FILETYPE *FoundType,\r
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,\r
+ OUT UINT32 *AuthenticationStatus\r
+ );\r
+\r
+/**\r
+ Locates a section in a given FFS File and\r
+ copies it to the supplied buffer (not including section header).\r
+\r
+ @param This Indicates the calling context.\r
+ @param NameGuid Pointer to an EFI_GUID, which is the\r
+ filename.\r
+ @param SectionType Indicates the section type to return.\r
+ @param SectionInstance Indicates which instance of sections with a\r
+ type of SectionType to return.\r
+ @param Buffer Buffer is a pointer to pointer to a buffer\r
+ in which the file or section contents or are\r
+ returned.\r
+ @param BufferSize BufferSize is a pointer to caller allocated\r
+ UINTN.\r
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a\r
+ caller allocated UINT32 in which the\r
+ authentication status is returned.\r
+\r
+ @retval EFI_SUCCESS Successfully read the file section into\r
+ buffer.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.\r
+ @retval EFI_NOT_FOUND Section not found.\r
+ @retval EFI_DEVICE_ERROR Device error.\r
+ @retval EFI_ACCESS_DENIED Could not read.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvReadFileSection (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *NameGuid,\r
+ IN EFI_SECTION_TYPE SectionType,\r
+ IN UINTN SectionInstance,\r
+ IN OUT VOID **Buffer,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT UINT32 *AuthenticationStatus\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
+/**\r
+ Return information of type InformationType for the requested firmware\r
+ volume.\r
+\r
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.\r
+ @param InformationType InformationType for requested.\r
+ @param BufferSize On input, size of Buffer.On output, the amount of\r
+ data returned in Buffer.\r
+ @param Buffer A poniter to the data buffer to return.\r
+\r
+ @return EFI_UNSUPPORTED Could not get.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvGetVolumeInfo (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *InformationType,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ Set information with InformationType into the requested firmware volume.\r
+\r
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.\r
+ @param InformationType InformationType for requested.\r
+ @param BufferSize Size of Buffer data.\r
+ @param Buffer A poniter to the data buffer to be set.\r
+\r
+ @retval EFI_UNSUPPORTED Could not set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvSetVolumeInfo (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *InformationType,\r
+ IN UINTN BufferSize,\r
+ IN CONST VOID *Buffer\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
+\r
+/**\r
+ Check if a block of buffer is erased.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param Buffer The buffer to be checked\r
+ @param BufferSize Size of the buffer in bytes\r
+\r
+ @retval TRUE The block of buffer is erased\r
+ @retval FALSE The block of buffer is not erased\r
+\r
+**/\r
+BOOLEAN\r
+IsBufferErased (\r
+ IN UINT8 ErasePolarity,\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize\r
+ );\r
+\r
+/**\r
+ Get the FFS file state by checking the highest bit set in the header's state field.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param FfsHeader Points to the FFS file header\r
+\r
+ @return FFS File state\r
+\r
+**/\r
+EFI_FFS_FILE_STATE\r
+GetFileState (\r
+ IN UINT8 ErasePolarity,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ );\r
+\r
+/**\r
+ Verify checksum of the firmware volume header.\r
+\r
+ @param FvHeader Points to the firmware volume header to be checked\r
+\r
+ @retval TRUE Checksum verification passed\r
+ @retval FALSE Checksum verification failed\r
+\r
+**/\r
+BOOLEAN\r
+VerifyFvHeaderChecksum (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader\r
+ );\r
+\r
+/**\r
+ Check if it's a valid FFS file header.\r
+\r
+ @param ErasePolarity Erase polarity attribute of the firmware volume\r
+ @param FfsHeader Points to the FFS file header to be checked\r
+\r
+ @retval TRUE Valid FFS file header\r
+ @retval FALSE Invalid FFS file header\r
+\r
+**/\r
+BOOLEAN\r
+IsValidFFSHeader (\r
+ IN UINT8 ErasePolarity,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ );\r
+\r
+/**\r
+ Check if it's a valid FFS file.\r
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FfsHeader Points to the FFS file to be checked\r
+\r
+ @retval TRUE Valid FFS file\r
+ @retval FALSE Invalid FFS file\r
+\r
+**/\r
+BOOLEAN\r
+IsValidFFSFile (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ );\r
+\r
+/**\r
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
+ copy the real length volume header into it.\r
+\r
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to\r
+ read the volume header\r
+ @param FwVolHeader Pointer to pointer to allocated buffer in which\r
+ the volume header is returned.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
+ @retval EFI_SUCCESS Successfully read volume header to the allocated\r
+ buffer.\r
+ @retval EFI_ACCESS_DENIED Read status of FV is not enabled.\r
+**/\r
+EFI_STATUS\r
+GetFwVolHeader (\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r
+ );\r
+\r
+/**\r
+ Locate the first file in FV.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FirstFile Points to the got first FFS file header.\r
+\r
+ @retval EFI_NOT_FOUND No FFS file is found in FV.\r
+ @retval EFI_SUCCESS The first FFS file is got.\r
+\r
+**/\r
+EFI_STATUS\r
+FvLocateFirstFile (\r
+ IN FV_DEVICE *FvDevice,\r
+ OUT EFI_FFS_FILE_HEADER **FirstFile\r
+ );\r
+\r
+/**\r
+ Convert the Buffer Address to LBA Entry Address.\r
+\r
+ @param FvDevice Cached FvDevice\r
+ @param BufferAddress Address of Buffer\r
+ @param LbaListEntry Pointer to the got LBA entry that contains the address.\r
+\r
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.\r
+ @retval EFI_SUCCESS LBA entry is found for Buffer address.\r
+\r
+**/\r
+EFI_STATUS\r
+Buffer2LbaEntry (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,\r
+ OUT LBA_ENTRY **LbaListEntry\r
+ );\r
+\r
+/**\r
+ Convert the Buffer Address to LBA Address & Offset.\r
+\r
+ @param FvDevice Cached FvDevice\r
+ @param BufferAddress Address of Buffer\r
+ @param Lba Pointer to the gob Lba value\r
+ @param Offset Pointer to the got Offset\r
+\r
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.\r
+ @retval EFI_SUCCESS LBA and Offset is found for Buffer address.\r
+\r
+**/\r
+EFI_STATUS\r
+Buffer2Lba (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,\r
+ OUT EFI_LBA *Lba,\r
+ OUT UINTN *Offset\r
+ );\r
+\r
+/**\r
+ Set File State in the FfsHeader.\r
+\r
+ @param State File state to be set into FFS header.\r
+ @param FfsHeader Points to the FFS file header\r
+\r
+**/\r
+VOID\r
+SetFileState (\r
+ IN UINT8 State,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ );\r
+\r
+/**\r
+ Create a PAD File in the Free Space.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.\r
+ @param Size Pad file Size, not include the header.\r
+ @param PadFileEntry The Ffs File Entry that points to this Pad File.\r
+\r
+ @retval EFI_SUCCESS Successfully create a PAD file.\r
+ @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.\r
+ @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.\r
+ @retval EFI_DEVICE_ERROR Free space is not erased.\r
+**/\r
+EFI_STATUS\r
+FvCreatePadFileInFreeSpace (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN FREE_SPACE_ENTRY *FreeSpaceEntry,\r
+ IN UINTN Size,\r
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry\r
+ );\r
+\r
+/**\r
+ Create a new file within a PAD file area.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param FfsFileBuffer A buffer that holds an FFS file,(it contains 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 Successfully create a new file within the found PAD file area.\r
+ @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.\r
+ @retval other errors New file is created failed.\r
+\r
+**/\r
+EFI_STATUS\r
+FvCreateNewFileInsidePadFile (\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
+/**\r
+ Write multiple files into FV in reliable method.\r
+\r
+ @param FvDevice Firmware Volume Device.\r
+ @param NumOfFiles Total File number to be written.\r
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure, \r
+ used to get name, attributes, type, etc\r
+ @param FileOperation The array of operation for each file.\r
+\r
+ @retval EFI_SUCCESS Files are added into FV.\r
+ @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.\r
+ @retval EFI_INVALID_PARAMETER File number is less than or equal to 1.\r
+ @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.\r
+\r
+**/\r
+EFI_STATUS\r
+FvCreateMultipleFiles (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN UINTN NumOfFiles,\r
+ IN EFI_FV_WRITE_FILE_DATA *FileData,\r
+ IN BOOLEAN *FileOperation\r
+ );\r
+\r
+/**\r
+ Caculate the checksum for the FFS header.\r
+\r
+ @param FfsHeader FFS File Header which needs to caculate the checksum\r
+\r
+**/\r
+VOID\r
+SetHeaderChecksum (\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader\r
+ );\r
+\r
+/**\r
+ Caculate the checksum for the FFS File.\r
+\r
+ @param FfsHeader FFS File Header which needs to caculate 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
+/**\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
+/**\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
+/**\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
+/**\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
+/**\r
+ Change FFS file header state and write to FV.\r
+\r
+ @param FvDevice Cached FV image.\r
+ @param FfsHeader Points to the FFS file header to be updated.\r
+ @param State FFS file state to be set.\r
+\r
+ @retval EFI_SUCCESS File state is writen into FV.\r
+ @retval others File state can't be writen into FV.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateHeaderBit (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_FFS_FILE_HEADER *FfsHeader,\r
+ IN EFI_FFS_FILE_STATE State\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
+#endif\r
--- /dev/null
+## @file\r
+# FwVolDxe driver produces Firmware Volume2 protocol with full services\r
+# (read/write, get/set) based on Firmware Volume Block protocol.\r
+#\r
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are\r
+# licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = FwVolDxe\r
+ FILE_GUID = 233C2592-1CEC-494a-A097-15DC96379777\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = FwVolDriverInit\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ FwVolDriver.h\r
+ FwPadFile.c\r
+ Ffs.c\r
+ FwVolWrite.c\r
+ FwVolRead.c\r
+ FwVolAttrib.c\r
+ FwVol.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
+ BaseMemoryLib\r
+ BaseLib\r
+ UefiLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+\r
+\r
+[Guids]\r
+ gEfiFirmwareVolumeTopFileGuid ## CONSUMES\r
+ gEfiFirmwareFileSystem2Guid ## CONSUMES\r
+\r
+[Protocols]\r
+ gEfiSectionExtractionProtocolGuid ## CONSUMES\r
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES\r
+ gEfiFirmwareVolume2ProtocolGuid ## PRODUCES\r
+\r
+[Depex]\r
+ gEfiFirmwareVolumeBlockProtocolGuid AND gEfiSectionExtractionProtocolGuid\r
+\r
--- /dev/null
+/** @file\r
+ Implements functions to read firmware file.\r
+\r
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FwVolDriver.h"\r
+\r
+UINT8 mFvAttributes[] = { 0, 4, 7, 9, 10, 12, 15, 16 };\r
+\r
+/**\r
+ Convert the FFS File Attributes to FV File Attributes.\r
+\r
+ @param FfsAttributes The attributes of UINT8 type.\r
+\r
+ @return The attributes of EFI_FV_FILE_ATTRIBUTES\r
+\r
+**/\r
+EFI_FV_FILE_ATTRIBUTES\r
+FfsAttributes2FvFileAttributes (\r
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes\r
+ )\r
+{\r
+ FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);\r
+ ASSERT (FfsAttributes < 8);\r
+ return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes];\r
+}\r
+\r
+/**\r
+ Given the input key, search for the next matching file in the volume.\r
+\r
+ @param This Indicates the calling context.\r
+ @param Key Key is a pointer to a caller allocated\r
+ buffer that contains implementation specific\r
+ data that is used to track where to begin\r
+ the search for the next file. The size of\r
+ the buffer must be at least This->KeySize\r
+ bytes long. To reinitialize the search and\r
+ begin from the beginning of the firmware\r
+ volume, the entire buffer must be cleared to\r
+ zero. Other than clearing the buffer to\r
+ initiate a new search, the caller must not\r
+ modify the data in the buffer between calls\r
+ to GetNextFile().\r
+ @param FileType FileType is a pointer to a caller allocated\r
+ EFI_FV_FILETYPE. The GetNextFile() API can\r
+ filter it's search for files based on the\r
+ value of *FileType input. A *FileType input\r
+ of 0 causes GetNextFile() to search for\r
+ files of all types. If a file is found, the\r
+ file's type is returned in *FileType.\r
+ *FileType is not modified if no file is\r
+ found.\r
+ @param NameGuid NameGuid is a pointer to a caller allocated\r
+ EFI_GUID. If a file is found, the file's\r
+ name is returned in *NameGuid. *NameGuid is\r
+ not modified if no file is found.\r
+ @param Attributes Attributes is a pointer to a caller\r
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file\r
+ is found, the file's attributes are returned\r
+ in *Attributes. *Attributes is not modified\r
+ if no file is found.\r
+ @param Size Size is a pointer to a caller allocated\r
+ UINTN. If a file is found, the file's size\r
+ is returned in *Size. *Size is not modified\r
+ if no file is found.\r
+\r
+ @retval EFI_SUCCESS Successfully find the file.\r
+ @retval EFI_DEVICE_ERROR Device error.\r
+ @retval EFI_ACCESS_DENIED Fv could not read.\r
+ @retval EFI_NOT_FOUND No matching file found.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvGetNextFile (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN OUT VOID *Key,\r
+ IN OUT EFI_FV_FILETYPE *FileType,\r
+ OUT EFI_GUID *NameGuid,\r
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,\r
+ OUT UINTN *Size\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FV_DEVICE *FvDevice;\r
+ EFI_FV_ATTRIBUTES FvAttributes;\r
+ EFI_FFS_FILE_HEADER *FfsFileHeader;\r
+ UINTN *KeyValue;\r
+ LIST_ENTRY *Link;\r
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
+ UINTN FileLength;\r
+\r
+ FvDevice = FV_DEVICE_FROM_THIS (This);\r
+\r
+ Status = This->GetVolumeAttributes (This, &FvAttributes);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ KeyValue = (UINTN *) Key;\r
+ FfsFileHeader = NULL;\r
+\r
+ //\r
+ // Check if read operation is enabled\r
+ //\r
+ if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {\r
+ //\r
+ // File type needs to be in 0 - 0x0D\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ do {\r
+ if (*KeyValue == 0) {\r
+ //\r
+ // Search for 1st matching file\r
+ //\r
+ Link = &FvDevice->FfsFileListHeader;\r
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;\r
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;\r
+\r
+ //\r
+ // remember the key\r
+ //\r
+ *KeyValue = (UINTN) FfsFileEntry;\r
+\r
+ //\r
+ // we ignore pad files\r
+ //\r
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
+ continue;\r
+ }\r
+\r
+ if (*FileType == 0) {\r
+ break;\r
+ }\r
+\r
+ if (*FileType == FfsFileHeader->Type) {\r
+ break;\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // Getting link from last Ffs\r
+ //\r
+ Link = (LIST_ENTRY *) (*KeyValue);\r
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;\r
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;\r
+\r
+ //\r
+ // remember the key\r
+ //\r
+ *KeyValue = (UINTN) FfsFileEntry;\r
+\r
+ //\r
+ // we ignore pad files\r
+ //\r
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
+ continue;\r
+ }\r
+\r
+ if (*FileType == EFI_FV_FILETYPE_ALL) {\r
+ break;\r
+ }\r
+\r
+ if (*FileType == FfsFileHeader->Type) {\r
+ break;\r
+ }\r
+ }\r
+ } while (Link->ForwardLink != &FvDevice->FfsFileListHeader);\r
+\r
+ //\r
+ // Cache this file entry\r
+ //\r
+ FvDevice->CurrentFfsFile = FfsFileEntry;\r
+\r
+ *FileType = FfsFileHeader->Type;\r
+ CopyGuid (NameGuid, &FfsFileHeader->Name);\r
+ *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);\r
+\r
+ FileLength = *(UINT32 *) FfsFileHeader->Size & 0x00FFFFFF;\r
+\r
+ //\r
+ // we need to substract the header size\r
+ //\r
+ *Size = FileLength - sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {\r
+ //\r
+ // specially deal with VTF file\r
+ //\r
+ UINT8 *SrcPtr;\r
+ UINT32 Tmp;\r
+\r
+ SrcPtr = (UINT8 *) FfsFileHeader;\r
+ SrcPtr += sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ while (*Size >= 4) {\r
+ Tmp = *(UINT32 *) SrcPtr;\r
+ if (Tmp == 0) {\r
+ SrcPtr += 4;\r
+ (*Size) -= 4;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Locates a file in the firmware volume and\r
+ copies it to the supplied buffer.\r
+\r
+ @param This Indicates the calling context.\r
+ @param NameGuid Pointer to an EFI_GUID, which is the\r
+ filename.\r
+ @param Buffer Buffer is a pointer to pointer to a buffer\r
+ in which the file or section contents or are\r
+ returned.\r
+ @param BufferSize BufferSize is a pointer to caller allocated\r
+ UINTN. On input *BufferSize indicates the\r
+ size in bytes of the memory region pointed\r
+ to by Buffer. On output, *BufferSize\r
+ contains the number of bytes required to\r
+ read the file.\r
+ @param FoundType FoundType is a pointer to a caller allocated\r
+ EFI_FV_FILETYPE that on successful return\r
+ from Read() contains the type of file read.\r
+ This output reflects the file type\r
+ irrespective of the value of the SectionType\r
+ input.\r
+ @param FileAttributes FileAttributes is a pointer to a caller\r
+ allocated EFI_FV_FILE_ATTRIBUTES. On\r
+ successful return from Read(),\r
+ *FileAttributes contains the attributes of\r
+ the file read.\r
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a\r
+ caller allocated UINTN in which the\r
+ authentication status is returned.\r
+\r
+ @retval EFI_SUCCESS Successfully read to memory buffer.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.\r
+ @retval EFI_NOT_FOUND Not found.\r
+ @retval EFI_DEVICE_ERROR Device error.\r
+ @retval EFI_ACCESS_DENIED Could not read.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvReadFile (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *NameGuid,\r
+ IN OUT VOID **Buffer,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT EFI_FV_FILETYPE *FoundType,\r
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,\r
+ OUT UINT32 *AuthenticationStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FV_DEVICE *FvDevice;\r
+ UINTN Key;\r
+ EFI_GUID SearchNameGuid;\r
+ EFI_FV_ATTRIBUTES FvAttributes;\r
+ EFI_FV_FILETYPE LocalFoundType;\r
+ EFI_FV_FILE_ATTRIBUTES LocalAttributes;\r
+ UINTN FileSize;\r
+ UINT8 *SrcPtr;\r
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
+ EFI_FFS_FILE_HEADER *FfsHeader;\r
+ UINT8 *FileBuffer;\r
+\r
+ if (NULL == This || NULL == NameGuid) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FvDevice = FV_DEVICE_FROM_THIS (This);\r
+\r
+ Status = This->GetVolumeAttributes (This, &FvAttributes);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // First check to see that FV is enabled for reads...\r
+ //\r
+ if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ FfsHeader = NULL;\r
+\r
+ //\r
+ // Check if the file was read last time.\r
+ //\r
+ FfsFileEntry = FvDevice->CurrentFfsFile;\r
+\r
+ if (FfsFileEntry != NULL) {\r
+ FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;\r
+ }\r
+\r
+ if ((FfsFileEntry == NULL) || (!CompareGuid (&FfsHeader->Name, NameGuid))) {\r
+ //\r
+ // If not match or no file cached, search this file\r
+ //\r
+ Key = 0;\r
+ do {\r
+ LocalFoundType = 0;\r
+ Status = This->GetNextFile (\r
+ This,\r
+ &Key,\r
+ &LocalFoundType,\r
+ &SearchNameGuid,\r
+ &LocalAttributes,\r
+ &FileSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ } while (!CompareGuid (&SearchNameGuid, NameGuid));\r
+\r
+ //\r
+ // Get file entry\r
+ //\r
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;\r
+\r
+ //\r
+ // Update the cache\r
+ //\r
+ FvDevice->CurrentFfsFile = FfsFileEntry;\r
+\r
+ FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;\r
+\r
+ } else {\r
+ //\r
+ // Get File Size of the cached file\r
+ //\r
+ FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;\r
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
+ }\r
+ //\r
+ // Get file info\r
+ //\r
+ *FoundType = FfsHeader->Type;\r
+ *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);\r
+ *AuthenticationStatus = 0;\r
+\r
+ //\r
+ // If Buffer is NULL, we only want to get some information\r
+ //\r
+ if (Buffer == NULL) {\r
+ *BufferSize = FileSize;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ SrcPtr = (UINT8 *) FfsHeader;\r
+ SrcPtr += sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {\r
+ //\r
+ // specially deal with VTF file\r
+ //\r
+ UINT32 Tmp;\r
+\r
+ while (FileSize >= 4) {\r
+ Tmp = *(UINT32 *) SrcPtr;\r
+ if (Tmp == 0) {\r
+ SrcPtr += 4;\r
+ FileSize -= 4;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // If we drop out of the above loop, we've found the correct file header...\r
+ //\r
+ if (*Buffer == NULL) {\r
+ FileBuffer = AllocateCopyPool (FileSize, SrcPtr);\r
+ if (FileBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ *BufferSize = FileSize;\r
+ *Buffer = FileBuffer;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // If the user's buffer is smaller than the file size, then copy as much\r
+ // as we can and return an appropriate status.\r
+ //\r
+ if (FileSize > *BufferSize) {\r
+ CopyMem (*Buffer, SrcPtr, *BufferSize);\r
+ *BufferSize = FileSize;\r
+ return EFI_WARN_BUFFER_TOO_SMALL;\r
+ }\r
+ //\r
+ // User's buffer size is ok, so copy the entire file to their buffer.\r
+ //\r
+ *BufferSize = FileSize;\r
+ CopyMem (*Buffer, SrcPtr, *BufferSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Locates a section in a given FFS File and\r
+ copies it to the supplied buffer (not including section header).\r
+\r
+ @param This Indicates the calling context.\r
+ @param NameGuid Pointer to an EFI_GUID, which is the\r
+ filename.\r
+ @param SectionType Indicates the section type to return.\r
+ @param SectionInstance Indicates which instance of sections with a\r
+ type of SectionType to return.\r
+ @param Buffer Buffer is a pointer to pointer to a buffer\r
+ in which the file or section contents or are\r
+ returned.\r
+ @param BufferSize BufferSize is a pointer to caller allocated\r
+ UINTN.\r
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a\r
+ caller allocated UINT32 in which the\r
+ authentication status is returned.\r
+\r
+ @retval EFI_SUCCESS Successfully read the file section into\r
+ buffer.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.\r
+ @retval EFI_NOT_FOUND Section not found.\r
+ @retval EFI_DEVICE_ERROR Device error.\r
+ @retval EFI_ACCESS_DENIED Could not read.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvReadFileSection (\r
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
+ IN CONST EFI_GUID *NameGuid,\r
+ IN EFI_SECTION_TYPE SectionType,\r
+ IN UINTN SectionInstance,\r
+ IN OUT VOID **Buffer,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT UINT32 *AuthenticationStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FV_ATTRIBUTES FvAttributes;\r
+ EFI_FV_FILETYPE FileType;\r
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
+ UINTN FileSize;\r
+ UINT8 *FileBuffer;\r
+ EFI_SECTION_EXTRACTION_PROTOCOL *Sep;\r
+ UINTN StreamHandle;\r
+\r
+ if (NULL == This || NULL == NameGuid || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = This->GetVolumeAttributes (This, &FvAttributes);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // First check to see that FV is enabled for reads...\r
+ //\r
+ if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // Read the whole file into buffer\r
+ //\r
+ FileBuffer = NULL;\r
+ Status = This->ReadFile (\r
+ This,\r
+ NameGuid,\r
+ (VOID **) &FileBuffer,\r
+ &FileSize,\r
+ &FileType,\r
+ &FileAttributes,\r
+ AuthenticationStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Check to see that the file actually HAS sections before we go any further.\r
+ //\r
+ if (FileType == EFI_FV_FILETYPE_RAW) {\r
+ FreePool (FileBuffer);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Located the protocol\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiSectionExtractionProtocolGuid,\r
+ NULL,\r
+ (VOID **) &Sep\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (FileBuffer);\r
+ return Status;\r
+ }\r
+\r
+ Status = Sep->OpenSectionStream (\r
+ Sep,\r
+ FileSize,\r
+ FileBuffer,\r
+ &StreamHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (FileBuffer);\r
+ return Status;\r
+ }\r
+\r
+ if (SectionType == 0) {\r
+ //\r
+ // We need the whole section stream\r
+ //\r
+ Status = Sep->GetSection (\r
+ Sep,\r
+ StreamHandle,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ Buffer,\r
+ BufferSize,\r
+ AuthenticationStatus\r
+ );\r
+ } else {\r
+ Status = Sep->GetSection (\r
+ Sep,\r
+ StreamHandle,\r
+ &SectionType,\r
+ NULL,\r
+ SectionInstance,\r
+ Buffer,\r
+ BufferSize,\r
+ AuthenticationStatus\r
+ );\r
+ }\r
+ //\r
+ // Handle AuthenticationStatus if necessary\r
+ //\r
+ Sep->CloseSectionStream (Sep, StreamHandle);\r
+\r
+ FreePool (FileBuffer);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ Implements write firmware file.\r
+\r
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FwVolDriver.h"\r
+\r
+/**\r
+ Caculate the checksum for the FFS header.\r
+\r
+ @param FfsHeader FFS File Header which needs to caculate 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 HeaderChecksum;\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
+ HeaderChecksum = CalculateSum8 (\r
+ (UINT8 *)FfsHeader,\r
+ sizeof (EFI_FFS_FILE_HEADER)\r
+ );\r
+\r
+ FfsHeader->IntegrityCheck.Checksum.Header = (UINT8) (~HeaderChecksum + 1);\r
+\r
+ FfsHeader->State = State;\r
+ FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Caculate the checksum for the FFS File.\r
+\r
+ @param FfsHeader FFS File Header which needs to caculate 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
+ EFI_FFS_FILE_STATE State;\r
+ UINT8 FileChecksum;\r
+\r
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {\r
+ //\r
+ // The file state is not included\r
+ //\r
+ State = FfsHeader->State;\r
+ FfsHeader->State = 0;\r
+\r
+ FfsHeader->IntegrityCheck.Checksum.File = 0;\r
+\r
+ //\r
+ // File checksum \r
+ //\r
+ FileChecksum = CalculateSum8 (\r
+ (UINT8 *)(FfsHeader + 1),\r
+ ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)\r
+ );\r
+\r
+ FfsHeader->IntegrityCheck.Checksum.File = (UINT8) (~FileChecksum + 1);\r
+\r
+ FfsHeader->State = State;\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
+ Caculate 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 RequiredAlignment FFS File Data alignment requirement.\r
+\r
+ @return The required Pad File Size.\r
+\r
+**/\r
+UINTN\r
+CaculatePadFileSize (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN EFI_PHYSICAL_ADDRESS StartAddress,\r
+ IN UINTN RequiredAlignment\r
+ )\r
+{\r
+ UINTN DataStartPos;\r
+ UINTN RelativePos;\r
+ UINTN PadSize;\r
+\r
+ DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER);\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
+\r
+ FvFileAlignment = (UINT8) (FvFileAttrib & EFI_FV_FILE_ATTRIB_ALIGNMENT);\r
+ FfsFileAlignment = 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
+\r
+ *FfsFileAttrib = (UINT8) (FfsFileAlignment << 3);\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 = CaculatePadFileSize (\r
+ FvDevice,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,\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 a free space that can hold this file.\r
+\r
+ @param FvDevice Cached Firmware Volume.\r
+ @param Size On input, it is the required size.\r
+ On output, it is the actual size of free space.\r
+ @param RequiredAlignment FFS File Data alignment requirement.\r
+ @param PadSize Pointer to the size of leading Pad File.\r
+ @param StartingAddress The starting address of the Free Space Entry\r
+ that meets the requirement.\r
+\r
+ @retval EFI_SUCCESS The free space is found.\r
+ @retval EFI_NOT_FOUND The free space can't be found.\r
+\r
+**/\r
+EFI_STATUS\r
+FvLocateFreeSpace (\r
+ IN FV_DEVICE *FvDevice,\r
+ IN OUT UINTN *Size,\r
+ IN UINTN RequiredAlignment,\r
+ OUT UINTN *PadSize,\r
+ OUT EFI_PHYSICAL_ADDRESS *StartingAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FREE_SPACE_ENTRY *FreeSpaceEntry;\r
+\r
+ //\r
+ // First find the free space entry\r
+ //\r
+ Status = FvLocateFreeSpaceEntry (\r
+ FvDevice,\r
+ *Size,\r
+ RequiredAlignment,\r
+ PadSize,\r
+ &FreeSpaceEntry\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *Size = FreeSpaceEntry->Length;\r
+ *StartingAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;\r
+\r
+ return EFI_SUCCESS;\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 FileLength;\r
+ UINTN PadAreaLength;\r
+ UINTN PadFileSize;\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
+ FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;\r
+ PadAreaLength = FileLength - sizeof (EFI_FFS_FILE_HEADER);\r
+\r
+ PadFileSize = CaculatePadFileSize (\r
+ FvDevice,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + sizeof (EFI_FFS_FILE_HEADER),\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 FileLength;\r
+ UINTN PadAreaLength;\r
+ UINTN TotalSize;\r
+ UINTN Index;\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
+ FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;\r
+ PadAreaLength = FileLength - sizeof (EFI_FFS_FILE_HEADER);\r
+ TotalSize = 0;\r
+\r
+ for (Index = 0; Index < NumOfFiles; Index++) {\r
+ PadSize[Index] = CaculatePadFileSize (\r
+ FvDevice,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + sizeof (EFI_FFS_FILE_HEADER) + TotalSize,\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
+ // Caculate 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] = CaculatePadFileSize (\r
+ FvDevice,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,\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
+\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 boundry\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
+ 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
+ sizeof (EFI_FFS_FILE_HEADER)\r
+ );\r
+\r
+ //\r
+ // update Free Space Entry, now need to substract the EFI_FFS_FILE_HEADER\r
+ //\r
+ FreeSpaceEntry->StartingAddress += sizeof (EFI_FFS_FILE_HEADER);\r
+ FreeSpaceEntry->Length -= sizeof (EFI_FFS_FILE_HEADER);\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
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;\r
+ *(UINT32 *) FileHeader->Size |= ActualFileSize;\r
+\r
+ SetHeaderChecksum (FileHeader);\r
+\r
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);\r
+\r
+ NumBytesWritten = sizeof (EFI_FFS_FILE_HEADER);\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
+ sizeof (EFI_FFS_FILE_HEADER)\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
+ sizeof (EFI_FFS_FILE_HEADER)\r
+ );\r
+\r
+ //\r
+ // update Free Space Entry, now need to substract the file data length\r
+ //\r
+ FreeSpaceEntry->StartingAddress += (BufferSize - sizeof (EFI_FFS_FILE_HEADER));\r
+ FreeSpaceEntry->Length -= (BufferSize - sizeof (EFI_FFS_FILE_HEADER));\r
+\r
+ //\r
+ // Caculate 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
+ sizeof (EFI_FFS_FILE_HEADER)\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
+\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
+ 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 boundry, and add file tail.\r
+ //\r
+ ActualSize = FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER);\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 + sizeof (EFI_FFS_FILE_HEADER),\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 < sizeof (EFI_FFS_FILE_HEADER); 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