]> git.proxmox.com Git - mirror_edk2.git/commitdiff
IntelFrameworkModulePkg: Add FwVolDxe driver
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 1 Sep 2011 19:57:08 +0000 (19:57 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 1 Sep 2011 19:57:08 +0000 (19:57 +0000)
Signed-off-by: jljusten
Reviewed-by: rsun3
Reviewed-by: lgao4
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12256 6f19259b-4bc3-4df7-8a09-765794883524

IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c [new file with mode: 0644]

index bd26806d21508d81da28c7e19064bbd7761e9d01..7eaac50eafa40af8f7735a34ae8f06ef6cfa7959 100644 (file)
   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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
new file mode 100644 (file)
index 0000000..1e3c839
--- /dev/null
@@ -0,0 +1,625 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c
new file mode 100644 (file)
index 0000000..14b8563
--- /dev/null
@@ -0,0 +1,1032 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
new file mode 100644 (file)
index 0000000..f453d5e
--- /dev/null
@@ -0,0 +1,651 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c
new file mode 100644 (file)
index 0000000..0e4ddf8
--- /dev/null
@@ -0,0 +1,220 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h
new file mode 100644 (file)
index 0000000..9c2788d
--- /dev/null
@@ -0,0 +1,773 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf
new file mode 100644 (file)
index 0000000..fb1355b
--- /dev/null
@@ -0,0 +1,68 @@
+## @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c
new file mode 100644 (file)
index 0000000..b1b4a73
--- /dev/null
@@ -0,0 +1,580 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
new file mode 100644 (file)
index 0000000..5c7e8ab
--- /dev/null
@@ -0,0 +1,1591 @@
+/** @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