+++ /dev/null
-/** @file\r
- FFS file access utilities.\r
-\r
- Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\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
- if (IS_FFS_FILE2 (FfsHeader)) {\r
- HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));\r
- } else {\r
- HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));\r
- }\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
-\r
- Attributes = FfsHeader->Attributes;\r
-\r
- if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {\r
-\r
- //\r
- // Check checksum of FFS data\r
- //\r
- if (IS_FFS_FILE2 (FfsHeader)) {\r
- FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));\r
- } else {\r
- FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));\r
- }\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
- if (IS_FFS_FILE2 (FfsHeader)) {\r
- return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2);\r
- } else {\r
- return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);\r
- }\r
- }\r
-\r
- if (IS_FFS_FILE2 (FfsHeader)) {\r
- FileLength = FFS_FILE2_SIZE (FfsHeader);\r
- } else {\r
- FileLength = FFS_FILE_SIZE (FfsHeader);\r
- }\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