added BaseTools/Source/C/Common/BinderFuncs.c
authorjljusten <jljusten@7335b38e-4728-0410-8992-fb3ffe349368>
Mon, 3 Dec 2007 18:30:50 +0000 (18:30 +0000)
committerjljusten <jljusten@7335b38e-4728-0410-8992-fb3ffe349368>
Mon, 3 Dec 2007 18:30:50 +0000 (18:30 +0000)
added      BaseTools/Source/C/Common/BinderFuncs.h
added      BaseTools/Source/C/Common/FirmwareVolumeBuffer.c
added      BaseTools/Source/C/Common/FirmwareVolumeBufferLib.h
modified   BaseTools/Source/C/Common/GNUmakefile
modified   BaseTools/Source/C/Common/Makefile
  Added 'FvBuf' library.  It has a consistent function prefix ('FvBuf')
  and the functions can operate on multiple FVs at the same time.  (In
  FvLib.c, InitializeFvLib call ties the functions to a single FV.)

  The BinderFuncs.* files are functions that make the FvBuf library code
  usable in other environments, such as UEFI applications or drivers.
  In the case of BinderFuncs.c, the code targets the ANSI C type of
  environment.

git-svn-id: https://buildtools.tianocore.org/svn/buildtools/trunk/BaseTools@900 7335b38e-4728-0410-8992-fb3ffe349368

Source/C/Common/BinderFuncs.c [new file with mode: 0644]
Source/C/Common/BinderFuncs.h [new file with mode: 0644]
Source/C/Common/FirmwareVolumeBuffer.c [new file with mode: 0644]
Source/C/Common/FirmwareVolumeBufferLib.h [new file with mode: 0644]
Source/C/Common/GNUmakefile
Source/C/Common/Makefile

diff --git a/Source/C/Common/BinderFuncs.c b/Source/C/Common/BinderFuncs.c
new file mode 100644 (file)
index 0000000..c369f2e
--- /dev/null
@@ -0,0 +1,83 @@
+/*++\r
+\r
+Copyright (c) 1999 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are 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
+Module Name:\r
+\r
+  BinderFuncs.c\r
+\r
+Abstract:\r
+\r
+  Binder function implementations for ANSI C libraries.\r
+\r
+--*/\r
+\r
+#include "BinderFuncs.h"\r
+\r
+//\r
+// Binder Function Implementations\r
+//\r
+\r
+VOID *\r
+CommonLibBinderAllocate (\r
+  IN UINTN Size\r
+  )\r
+{\r
+  return malloc (Size);\r
+}\r
+\r
+VOID\r
+CommonLibBinderFree (\r
+  IN VOID *Pointer\r
+  )\r
+{\r
+  free (Pointer);\r
+}\r
+\r
+VOID\r
+CommonLibBinderCopyMem (\r
+  IN VOID *Destination,\r
+  IN VOID *Source,\r
+  IN UINTN Length\r
+  )\r
+{\r
+  memmove (Destination, Source, Length);\r
+}\r
+\r
+VOID\r
+CommonLibBinderSetMem (\r
+  IN VOID *Destination,\r
+  IN UINTN Length,\r
+  IN UINT8 Value\r
+  )\r
+{\r
+  memset (Destination, Value, Length);\r
+}\r
+\r
+INTN\r
+CommonLibBinderCompareMem (\r
+  IN VOID *MemOne,\r
+  IN VOID *MemTwo,\r
+  IN UINTN Length\r
+  )\r
+{\r
+  return memcmp (MemOne, MemTwo, Length);\r
+}\r
+\r
+BOOLEAN\r
+CommonLibBinderCompareGuid (\r
+  IN EFI_GUID *Guid1,\r
+  IN EFI_GUID *Guid2\r
+  )\r
+{\r
+  return CompareGuid (Guid1, Guid2) ? FALSE : TRUE;\r
+}\r
+\r
+\r
diff --git a/Source/C/Common/BinderFuncs.h b/Source/C/Common/BinderFuncs.h
new file mode 100644 (file)
index 0000000..9d00ad4
--- /dev/null
@@ -0,0 +1,75 @@
+/*++\r
+\r
+Copyright (c) 1999 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are 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
+Module Name:\r
+\r
+  BinderFuncs.h\r
+\r
+Abstract:\r
+\r
+  Prototypes for binder functions that allow common code to be\r
+  written which then links to implementation of these functions\r
+  which is appropriate for the specific environment that they\r
+  are running under.\r
+\r
+--*/\r
+\r
+#ifndef BinderFuncs_h_INCLUDED\r
+#define BinderFuncs_h_INCLUDED\r
+\r
+#include "Common/UefiBaseTypes.h"\r
+\r
+//\r
+// Binder Function Prototypes\r
+//\r
+// These binding functions must be implemented externally as appropriate for\r
+// the environment that the code will be running under.\r
+//\r
+\r
+VOID *\r
+CommonLibBinderAllocate (\r
+  IN UINTN Size\r
+  );\r
+\r
+VOID\r
+CommonLibBinderFree (\r
+  IN VOID *Pointer\r
+  );\r
+\r
+VOID\r
+CommonLibBinderCopyMem (\r
+  IN VOID *Destination,\r
+  IN VOID *Source,\r
+  IN UINTN Length\r
+  );\r
+\r
+VOID\r
+CommonLibBinderSetMem (\r
+  IN VOID *Destination,\r
+  IN UINTN Length,\r
+  IN UINT8 Value\r
+  );\r
+\r
+INTN\r
+CommonLibBinderCompareMem (\r
+  IN VOID *MemOne,\r
+  IN VOID *MemTwo,\r
+  IN UINTN Length\r
+  );\r
+\r
+BOOLEAN\r
+CommonLibBinderCompareGuid (\r
+  IN EFI_GUID *Guid1,\r
+  IN EFI_GUID *Guid2\r
+  );\r
+\r
+#endif // #ifndef CommonLibs_h_INCLUDED\r
+\r
diff --git a/Source/C/Common/FirmwareVolumeBuffer.c b/Source/C/Common/FirmwareVolumeBuffer.c
new file mode 100644 (file)
index 0000000..9cfea00
--- /dev/null
@@ -0,0 +1,1668 @@
+/*++\r
+\r
+Copyright (c) 1999 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are 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
+Module Name:\r
+\r
+  FirmwareVolumeBuffer.c\r
+\r
+Abstract:\r
+\r
+  EFI Firmware Volume routines which work on a Fv image in buffers.\r
+\r
+--*/\r
+\r
+#include "FirmwareVolumeBufferLib.h"\r
+#include "BinderFuncs.h"\r
+\r
+//\r
+// Local macros\r
+//\r
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \\r
+    ( \\r
+      (BOOLEAN) ( \\r
+          (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \\r
+        ) \\r
+    )\r
+\r
+\r
+//\r
+// Local prototypes\r
+//\r
+\r
+STATIC\r
+UINT16\r
+FvBufCalculateChecksum16 (\r
+  IN UINT16       *Buffer,\r
+  IN UINTN        Size\r
+  );\r
+\r
+STATIC\r
+UINT8\r
+FvBufCalculateChecksum8 (\r
+  IN UINT8        *Buffer,\r
+  IN UINTN        Size\r
+  );\r
+\r
+//\r
+// Procedures start\r
+//\r
+\r
+EFI_STATUS\r
+FvBufRemoveFileNew (\r
+  IN OUT VOID *Fv,\r
+  IN EFI_GUID *Name\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  SourceFv - Address of the Fv in memory, this firmware volume volume will\r
+             be modified, if SourceFfsFile exists\r
+  SourceFfsFile - Input FFS file to replace\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_FFS_FILE_HEADER*        FileToRm;\r
+  UINTN                       FileToRmLength;\r
+\r
+  Status = FvBufFindFileByName(\r
+    Fv,\r
+    Name,\r
+    &FileToRm\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FileToRmLength = FvBufExpand3ByteSize (FileToRm->Size);\r
+\r
+  CommonLibBinderSetMem (\r
+    FileToRm,\r
+    FileToRmLength,\r
+    (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY)\r
+      ? 0xFF : 0\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufRemoveFile (\r
+  IN OUT VOID *Fv,\r
+  IN EFI_GUID *Name\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  SourceFv - Address of the Fv in memory, this firmware volume volume will\r
+             be modified, if SourceFfsFile exists\r
+  SourceFfsFile - Input FFS file to replace\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_FFS_FILE_HEADER        *NextFile;\r
+  EFI_FIRMWARE_VOLUME_HEADER *TempFv;\r
+  UINTN                       FileKey;\r
+  UINTN                       FvLength;\r
+\r
+  Status = FvBufFindFileByName(\r
+    Fv,\r
+    Name,\r
+    NULL\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = FvBufGetSize (Fv, &FvLength);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TempFv = NULL;\r
+  Status = FvBufDuplicate (Fv, &TempFv);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = FvBufClearAllFiles (TempFv);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // TempFv has been allocated.  It must now be freed\r
+  // before returning.\r
+\r
+  FileKey = 0;\r
+  while (TRUE) {\r
+\r
+    Status = FvBufFindNextFile (Fv, &FileKey, &NextFile);\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    } else if (EFI_ERROR (Status)) {\r
+      CommonLibBinderFree (TempFv);\r
+      return Status;\r
+    }\r
+\r
+    if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {\r
+      continue;\r
+    }\r
+    else {\r
+      Status = FvBufAddFile (TempFv, NextFile);\r
+      if (EFI_ERROR (Status)) {\r
+        CommonLibBinderFree (TempFv);\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  CommonLibBinderCopyMem (Fv, TempFv, FvLength);\r
+  CommonLibBinderFree (TempFv);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufChecksumFile (\r
+  IN OUT VOID *FfsFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  SourceFfsFile - Input FFS file to update the checksum for\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+\r
+--*/\r
+{\r
+  EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile;\r
+  EFI_FFS_FILE_STATE StateBackup;\r
+  UINT32 FileSize;\r
+\r
+  FileSize = FvBufExpand3ByteSize (File->Size);\r
+\r
+  //\r
+  // Fill in checksums and state, they must be 0 for checksumming.\r
+  //\r
+  File->IntegrityCheck.Checksum.Header = 0;\r
+  File->IntegrityCheck.Checksum.File = 0;\r
+  StateBackup = File->State;\r
+  File->State = 0;\r
+\r
+  File->IntegrityCheck.Checksum.Header =\r
+    FvBufCalculateChecksum8 (\r
+      (UINT8 *) File,\r
+      sizeof (EFI_FFS_FILE_HEADER)\r
+      );\r
+\r
+  if (File->Attributes & FFS_ATTRIB_CHECKSUM) {\r
+    File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 (\r
+                                                (VOID*)File,\r
+                                                FileSize\r
+                                                );\r
+  } else {\r
+    File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+  }\r
+\r
+  File->State = StateBackup;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufChecksumHeader (\r
+  IN OUT VOID *Fv\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  SourceFv - Address of the Fv in memory, this firmware volume volume will\r
+             be modified, if SourceFfsFile exists\r
+  SourceFfsFile - Input FFS file to replace\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+\r
+--*/\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+\r
+  FvHeader->Checksum = 0;\r
+  FvHeader->Checksum =\r
+    FvBufCalculateChecksum16 (\r
+      (UINT16*) FvHeader,\r
+      FvHeader->HeaderLength / sizeof (UINT16)\r
+      );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufDuplicate (\r
+  IN VOID *SourceFv,\r
+  IN OUT VOID **DestinationFv\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  SourceFv - Address of the Fv in memory\r
+  DestinationFv - Output for destination Fv\r
+    DestinationFv == NULL - invalid parameter\r
+    *DestinationFv == NULL - memory will be allocated\r
+    *DestinationFv != NULL - this address will be the destination\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN size;\r
+\r
+  if (DestinationFv == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = FvBufGetSize (SourceFv, &size);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (*DestinationFv == NULL) {\r
+    *DestinationFv = CommonLibBinderAllocate (size);\r
+  }\r
+\r
+  CommonLibBinderCopyMem (*DestinationFv, SourceFv, size);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufExtend (\r
+  IN VOID **Fv,\r
+  IN UINTN Size\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Extends a firmware volume by the given number of bytes.\r
+\r
+  BUGBUG: Does not handle the case where the firmware volume has a\r
+          VTF (Volume Top File).  The VTF will not be moved to the\r
+          end of the extended FV.\r
+\r
+Arguments:\r
+\r
+  Fv - Source and destination firmware volume.\r
+       Note: The original firmware volume buffer is freed!\r
+\r
+  Size - The minimum size that the firmware volume is to be extended by.\r
+         The FV may be extended more than this size.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN OldSize;\r
+  UINTN NewSize;\r
+  UINTN BlockCount;\r
+  VOID* NewFv;\r
+\r
+  EFI_FIRMWARE_VOLUME_HEADER* hdr;\r
+  EFI_FV_BLOCK_MAP_ENTRY*     blk;\r
+\r
+  Status = FvBufGetSize (*Fv, &OldSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Locate the block map in the fv header\r
+  //\r
+  hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv;\r
+  blk = hdr->BlockMap;\r
+\r
+  //\r
+  // Calculate the number of blocks needed to achieve the requested\r
+  // size extension\r
+  //\r
+  BlockCount = ((Size + (blk->Length - 1)) / blk->Length);\r
+\r
+  //\r
+  // Calculate the new size from the number of blocks that will be added\r
+  //\r
+  NewSize = OldSize + (BlockCount * blk->Length);\r
+\r
+  NewFv = CommonLibBinderAllocate (NewSize);\r
+  if (NewFv == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Copy the old data\r
+  //\r
+  CommonLibBinderCopyMem (NewFv, *Fv, OldSize);\r
+\r
+  //\r
+  // Free the old fv buffer\r
+  //\r
+  CommonLibBinderFree (*Fv);\r
+\r
+  //\r
+  // Locate the block map in the new fv header\r
+  //\r
+  hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv;\r
+  hdr->FvLength = NewSize;\r
+  blk = hdr->BlockMap;\r
+\r
+  //\r
+  // Update the block map for the new fv\r
+  //\r
+  blk->NumBlocks += (UINT32)BlockCount;\r
+\r
+  //\r
+  // Update the FV header checksum\r
+  //\r
+  FvBufChecksumHeader (NewFv);\r
+\r
+  //\r
+  // Clear out the new area of the FV\r
+  //\r
+  CommonLibBinderSetMem (\r
+    (UINT8*)NewFv + OldSize,\r
+    (NewSize - OldSize),\r
+    (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0\r
+    );\r
+\r
+  //\r
+  // Set output with new fv that was created\r
+  //\r
+  *Fv = NewFv;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufClearAllFiles (\r
+  IN OUT VOID *Fv\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+  EFI_STATUS Status;\r
+  UINTN size = 0;\r
+\r
+  Status = FvBufGetSize (Fv, &size);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CommonLibBinderSetMem(\r
+    (UINT8*)hdr + hdr->HeaderLength,\r
+    size - hdr->HeaderLength,\r
+    (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufGetSize (\r
+  IN VOID *Fv,\r
+  OUT UINTN *Size\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clears out all files from the Fv buffer in memory\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+  EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;\r
+\r
+  *Size = 0;\r
+\r
+  while (blk->Length != 0 || blk->NumBlocks != 0) {\r
+    *Size = *Size + (blk->Length * blk->NumBlocks);\r
+    if (*Size >= 0x40000000) {\r
+      // If size is greater than 1GB, then assume it is corrupted\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+    blk++;\r
+  }\r
+\r
+  if (*Size == 0) {\r
+    // If size is 0, then assume the volume is corrupted\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufAddFile (\r
+  IN OUT VOID *Fv,\r
+  IN VOID *File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Adds a new FFS file\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+  File - FFS file to add to Fv\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+\r
+  EFI_FFS_FILE_HEADER *fhdr = NULL;\r
+  EFI_FVB_ATTRIBUTES FvbAttributes;\r
+  UINTN offset;\r
+  UINTN fsize;\r
+  UINTN newSize;\r
+  UINTN clearLoop;\r
+\r
+  EFI_STATUS Status;\r
+  UINTN fvSize;\r
+\r
+  Status = FvBufGetSize (Fv, &fvSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FvbAttributes = hdr->Attributes;\r
+  newSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);\r
+\r
+  for(\r
+      offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8);\r
+      offset + newSize <= fvSize;\r
+      offset = (UINTN)ALIGN_POINTER (offset, 8)\r
+    ) {\r
+\r
+    fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset);\r
+\r
+    if (EFI_TEST_FFS_ATTRIBUTES_BIT(\r
+          FvbAttributes,\r
+          fhdr->State,\r
+          EFI_FILE_HEADER_VALID\r
+        )\r
+      ) {\r
+      // BUGBUG: Need to make sure that the new file does not already\r
+      // exist.\r
+\r
+      fsize = FvBufExpand3ByteSize (fhdr->Size);\r
+      if (fsize == 0 || (offset + fsize > fvSize)) {\r
+        return EFI_VOLUME_CORRUPTED;\r
+      }\r
+\r
+      offset = offset + fsize;\r
+      continue;\r
+    }\r
+\r
+    clearLoop = 0;\r
+    while ((clearLoop < newSize) &&\r
+           (((UINT8*)fhdr)[clearLoop] ==\r
+             (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0)\r
+           )\r
+          ) {\r
+      clearLoop++;\r
+    }\r
+\r
+    //\r
+    // We found a place in the FV which is empty and big enough for\r
+    // the new file\r
+    //\r
+    if (clearLoop >= newSize) {\r
+      break;\r
+    }\r
+\r
+    offset = offset + 1; // Make some forward progress\r
+  }\r
+\r
+  if (offset + newSize > fvSize) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CommonLibBinderCopyMem (fhdr, File, newSize);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufAddFileWithExtend (\r
+  IN OUT VOID **Fv,\r
+  IN VOID *File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Adds a new FFS file.  Extends the firmware volume if needed.\r
+\r
+Arguments:\r
+\r
+  Fv - Source and destination firmware volume.\r
+       Note: If the FV is extended, then the original firmware volume\r
+             buffer is freed!\r
+\r
+  Size - The minimum size that the firmware volume is to be extended by.\r
+         The FV may be extended more than this size.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  EFI_FFS_FILE_HEADER* NewFile;\r
+\r
+  NewFile = (EFI_FFS_FILE_HEADER*)File;\r
+\r
+  //\r
+  // Try to add to the capsule volume\r
+  //\r
+  Status = FvBufAddFile (*Fv, NewFile);\r
+  if (Status == EFI_OUT_OF_RESOURCES) {\r
+    //\r
+    // Try to extend the capsule volume by the size of the file\r
+    //\r
+    Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Now, try to add the file again\r
+    //\r
+    Status = FvBufAddFile (*Fv, NewFile);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufAddVtfFile (\r
+  IN OUT VOID *Fv,\r
+  IN VOID *File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Adds a new FFS VFT (Volume Top File) file.  In other words, adds the\r
+  file to the end of the firmware volume.\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+  File - FFS file to add to Fv\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+\r
+  EFI_FFS_FILE_HEADER* NewFile;\r
+  UINTN                NewFileSize;\r
+\r
+  UINT8 erasedUint8;\r
+  UINTN clearLoop;\r
+\r
+  EFI_FFS_FILE_HEADER *LastFile;\r
+  UINTN LastFileSize;\r
+\r
+  UINTN fvSize;\r
+  UINTN Key;\r
+\r
+  Status = FvBufGetSize (Fv, &fvSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0);\r
+  NewFileSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);\r
+\r
+  if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Find the last file in the FV\r
+  //\r
+  Key = 0;\r
+  LastFile = NULL;\r
+  LastFileSize = 0;\r
+  do {\r
+    Status = FvBufFindNextFile (Fv, &Key, &LastFile);\r
+    LastFileSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);\r
+  } while (!EFI_ERROR (Status));\r
+\r
+  //\r
+  // If no files were found, then we start at the beginning of the FV\r
+  //\r
+  if (LastFile == NULL) {\r
+    LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength);\r
+  }\r
+\r
+  //\r
+  // We want to put the new file (VTF) at the end of the FV\r
+  //\r
+  NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize));\r
+\r
+  //\r
+  // Check to see if there is enough room for the VTF after the last file\r
+  // found in the FV\r
+  //\r
+  if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Loop to determine if the end of the FV is empty\r
+  //\r
+  clearLoop = 0;\r
+  while ((clearLoop < NewFileSize) &&\r
+         (((UINT8*)NewFile)[clearLoop] == erasedUint8)\r
+        ) {\r
+    clearLoop++;\r
+  }\r
+\r
+  //\r
+  // Check to see if there was not enough room for the file\r
+  //\r
+  if (clearLoop < NewFileSize) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CommonLibBinderCopyMem (NewFile, File, NewFileSize);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+VOID\r
+FvBufCompact3ByteSize (\r
+  OUT VOID* SizeDest,\r
+  IN UINT32 Size\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Expands the 3 byte size commonly used in Firmware Volume data structures\r
+\r
+Arguments:\r
+\r
+  Size - Address of the 3 byte array representing the size\r
+\r
+Returns:\r
+\r
+  UINT32\r
+\r
+--*/\r
+{\r
+  ((UINT8*)SizeDest)[0] = (UINT8)Size;\r
+  ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8);\r
+  ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16);\r
+}\r
+\r
+UINT32\r
+FvBufExpand3ByteSize (\r
+  IN VOID* Size\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Expands the 3 byte size commonly used in Firmware Volume data structures\r
+\r
+Arguments:\r
+\r
+  Size - Address of the 3 byte array representing the size\r
+\r
+Returns:\r
+\r
+  UINT32\r
+\r
+--*/\r
+{\r
+  return (((UINT8*)Size)[2] << 16) +\r
+         (((UINT8*)Size)[1] << 8) +\r
+         ((UINT8*)Size)[0];\r
+}\r
+\r
+EFI_STATUS\r
+FvBufFindNextFile (\r
+  IN VOID *Fv,\r
+  IN OUT UINTN *Key,\r
+  OUT VOID **File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Iterates through the files contained within the firmware volume\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+  Key - Should be 0 to get the first file.  After that, it should be\r
+        passed back in without modifying it's contents to retrieve\r
+        subsequent files.\r
+  File - Output file pointer\r
+    File == NULL - invalid parameter\r
+    otherwise - *File will be update to the location of the file\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+\r
+  EFI_FFS_FILE_HEADER *fhdr = NULL;\r
+  EFI_FVB_ATTRIBUTES FvbAttributes;\r
+  UINTN fsize;\r
+\r
+  EFI_STATUS Status;\r
+  UINTN fvSize;\r
+\r
+  if (Fv == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = FvBufGetSize (Fv, &fvSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (*Key == 0) {\r
+    *Key = hdr->HeaderLength;\r
+  }\r
+\r
+  FvbAttributes = hdr->Attributes;\r
+\r
+  for(\r
+      *Key = (UINTN)ALIGN_POINTER (*Key, 8);\r
+      (*Key + sizeof (*fhdr)) < fvSize;\r
+      *Key = (UINTN)ALIGN_POINTER (*Key, 8)\r
+    ) {\r
+\r
+    fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);\r
+    fsize = FvBufExpand3ByteSize (fhdr->Size);\r
+\r
+    if (!EFI_TEST_FFS_ATTRIBUTES_BIT(\r
+          FvbAttributes,\r
+          fhdr->State,\r
+          EFI_FILE_HEADER_VALID\r
+        ) ||\r
+        EFI_TEST_FFS_ATTRIBUTES_BIT(\r
+          FvbAttributes,\r
+          fhdr->State,\r
+          EFI_FILE_HEADER_INVALID\r
+        )\r
+      ) {\r
+      *Key = *Key + 1; // Make some forward progress\r
+      continue;\r
+    } else if(\r
+        EFI_TEST_FFS_ATTRIBUTES_BIT(\r
+          FvbAttributes,\r
+          fhdr->State,\r
+          EFI_FILE_MARKED_FOR_UPDATE\r
+        ) ||\r
+        EFI_TEST_FFS_ATTRIBUTES_BIT(\r
+          FvbAttributes,\r
+          fhdr->State,\r
+          EFI_FILE_DELETED\r
+        )\r
+      ) {\r
+      *Key = *Key + fsize;\r
+      continue;\r
+    } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(\r
+          FvbAttributes,\r
+          fhdr->State,\r
+          EFI_FILE_DATA_VALID\r
+        )\r
+      ) {\r
+      *File = (UINT8*)hdr + *Key;\r
+      *Key = *Key + fsize;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    *Key = *Key + 1; // Make some forward progress\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufFindFileByName (\r
+  IN VOID *Fv,\r
+  IN EFI_GUID *Name,\r
+  OUT VOID **File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Searches the Fv for a file by its name\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+  Name - Guid filename to search for in the firmware volume\r
+  File - Output file pointer\r
+    File == NULL - Only determine if the file exists, based on return\r
+                   value from the function call.\r
+    otherwise - *File will be update to the location of the file\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN Key;\r
+  EFI_FFS_FILE_HEADER *NextFile;\r
+\r
+  Key = 0;\r
+  while (TRUE) {\r
+    Status = FvBufFindNextFile (Fv, &Key, &NextFile);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {\r
+      if (File != NULL) {\r
+        *File = NextFile;\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufFindFileByType (\r
+  IN VOID *Fv,\r
+  IN EFI_FV_FILETYPE Type,\r
+  OUT VOID **File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Searches the Fv for a file by its type\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+  Type - FFS FILE type to search for\r
+  File - Output file pointer\r
+    (File == NULL) -> Only determine if the file exists, based on return\r
+                      value from the function call.\r
+    otherwise -> *File will be update to the location of the file\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN Key;\r
+  EFI_FFS_FILE_HEADER *NextFile;\r
+\r
+  Key = 0;\r
+  while (TRUE) {\r
+    Status = FvBufFindNextFile (Fv, &Key, &NextFile);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (Type == NextFile->Type) {\r
+      if (File != NULL) {\r
+        *File = NextFile;\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufGetFileRawData (\r
+  IN  VOID*     FfsFile,\r
+  OUT VOID**    RawData,\r
+  OUT UINTN*    RawDataSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Searches the requested file for raw data.\r
+\r
+  This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file,\r
+  or finds the EFI_SECTION_RAW section within the file and returns its data.\r
+\r
+Arguments:\r
+\r
+  FfsFile - Address of the FFS file in memory\r
+  RawData - Pointer to the raw data within the file\r
+            (This is NOT allocated.  It is within the file.)\r
+  RawDataSize - Size of the raw data within the file\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  EFI_FFS_FILE_HEADER* File;\r
+  EFI_RAW_SECTION* Section;\r
+\r
+  File = (EFI_FFS_FILE_HEADER*)FfsFile;\r
+\r
+  //\r
+  // Is the file type == EFI_FV_FILETYPE_RAW?\r
+  //\r
+  if (File->Type == EFI_FV_FILETYPE_RAW) {\r
+    //\r
+    // Raw filetypes don't have sections, so we just return the raw data\r
+    //\r
+    *RawData = (VOID*)(File + 1);\r
+    *RawDataSize = FvBufExpand3ByteSize (File->Size) - sizeof (*File);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Within the file, we now need to find the EFI_SECTION_RAW section.\r
+  //\r
+  Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, &Section);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *RawData = (VOID*)(Section + 1);\r
+  *RawDataSize =\r
+    FvBufExpand3ByteSize (Section->Size) - sizeof (*Section);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufPackageFreeformRawFile (\r
+  IN EFI_GUID*  Filename,\r
+  IN VOID*      RawData,\r
+  IN UINTN      RawDataSize,\r
+  OUT VOID**    FfsFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Packages up a FFS file containing the input raw data.\r
+\r
+  The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will\r
+  contain one EFI_FV_FILETYPE_RAW section.\r
+\r
+Arguments:\r
+\r
+  RawData - Pointer to the raw data to be packed\r
+  RawDataSize - Size of the raw data to be packed\r
+  FfsFile - Address of the packaged FFS file.\r
+            Note: The called must deallocate this memory!\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  EFI_FFS_FILE_HEADER* NewFile;\r
+  UINT32 NewFileSize;\r
+  EFI_RAW_SECTION* NewSection;\r
+  UINT32 NewSectionSize;\r
+  UINT16* Tail;\r
+\r
+  //\r
+  // The section size is the DataSize + the size of the section header\r
+  //\r
+  NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize;\r
+\r
+  //\r
+  // The file size is the size of the file header + the section size\r
+  //\r
+  NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize;\r
+\r
+  //\r
+  // Try to allocate a buffer to build the new FFS file in\r
+  //\r
+  NewFile = CommonLibBinderAllocate (NewFileSize);\r
+  if (NewFile == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CommonLibBinderSetMem (NewFile, NewFileSize, 0);\r
+\r
+  //\r
+  // The NewSection follow right after the FFS file header\r
+  //\r
+  NewSection = (EFI_RAW_SECTION*)(NewFile + 1);\r
+  FvBufCompact3ByteSize (NewSection->Size, NewSectionSize);\r
+  NewSection->Type = EFI_SECTION_RAW;\r
+\r
+  //\r
+  // Copy the actual file data into the buffer\r
+  //\r
+  CommonLibBinderCopyMem (NewSection + 1, RawData, RawDataSize);\r
+\r
+  //\r
+  // Initialize the FFS file header\r
+  //\r
+  CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID));\r
+  FvBufCompact3ByteSize (NewFile->Size, NewFileSize);\r
+  NewFile->Type = EFI_FV_FILETYPE_FREEFORM;\r
+  NewFile->Attributes = 0;\r
+  NewFile->IntegrityCheck.Checksum.Header =\r
+    FvBufCalculateChecksum8 ((UINT8*)NewFile, sizeof (*NewFile));\r
+  NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+  NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION |\r
+                             EFI_FILE_HEADER_VALID |\r
+                             EFI_FILE_DATA_VALID\r
+                           );\r
+\r
+  *FfsFile = NewFile;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufFindNextSection (\r
+  IN VOID *SectionsStart,\r
+  IN UINTN TotalSectionsSize,\r
+  IN OUT UINTN *Key,\r
+  OUT VOID **Section\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Iterates through the sections contained within a given array of sections\r
+\r
+Arguments:\r
+\r
+  SectionsStart - Address of the start of the FFS sections array\r
+  TotalSectionsSize - Total size of all the sections\r
+  Key - Should be 0 to get the first section.  After that, it should be\r
+        passed back in without modifying it's contents to retrieve\r
+        subsequent files.\r
+  Section - Output section pointer\r
+    (Section == NULL) -> invalid parameter\r
+    otherwise -> *Section will be update to the location of the file\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_COMMON_SECTION_HEADER *sectionHdr;\r
+  UINTN sectionSize;\r
+\r
+  *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned\r
+\r
+  if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key);\r
+  sectionSize = FvBufExpand3ByteSize (sectionHdr->Size);\r
+\r
+  if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if ((*Key + sectionSize) > TotalSectionsSize) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Section = (UINT8*)sectionHdr;\r
+  *Key = *Key + sectionSize;\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufCountSections (\r
+  IN VOID* FfsFile,\r
+  IN UINTN* Count\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Searches the FFS file and counts the number of sections found.\r
+  The sections are NOT recursed.\r
+\r
+Arguments:\r
+\r
+  FfsFile - Address of the FFS file in memory\r
+  Count - The location to store the section count in\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINTN                      Key;\r
+  VOID*                      SectionStart;\r
+  UINTN                      TotalSectionsSize;\r
+  EFI_COMMON_SECTION_HEADER* NextSection;\r
+\r
+  SectionStart = (VOID*)((UINTN)FfsFile + sizeof (EFI_FFS_FILE_HEADER));\r
+  TotalSectionsSize =\r
+    FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)FfsFile)->Size) -\r
+    sizeof (EFI_FFS_FILE_HEADER);\r
+  Key = 0;\r
+  *Count = 0;\r
+  while (TRUE) {\r
+    Status = FvBufFindNextSection (\r
+               SectionStart,\r
+               TotalSectionsSize,\r
+               &Key,\r
+               &NextSection\r
+               );\r
+    if (Status == EFI_NOT_FOUND) {\r
+      return EFI_SUCCESS;\r
+    } else if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Increment the section counter\r
+    //\r
+    *Count += 1;\r
+\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufFindSectionByType (\r
+  IN VOID *FfsFile,\r
+  IN UINT8 Type,\r
+  OUT VOID **Section\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Searches the FFS file for a section by its type\r
+\r
+Arguments:\r
+\r
+  FfsFile - Address of the FFS file in memory\r
+  Type - FFS FILE section type to search for\r
+  Section - Output section pointer\r
+    (Section == NULL) -> Only determine if the section exists, based on return\r
+                         value from the function call.\r
+    otherwise -> *Section will be update to the location of the file\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN Key;\r
+  VOID*                      SectionStart;\r
+  UINTN                      TotalSectionsSize;\r
+  EFI_COMMON_SECTION_HEADER* NextSection;\r
+\r
+  SectionStart = (VOID*)((UINTN)FfsFile + sizeof (EFI_FFS_FILE_HEADER));\r
+  TotalSectionsSize =\r
+    FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)FfsFile)->Size) -\r
+    sizeof (EFI_FFS_FILE_HEADER);\r
+  Key = 0;\r
+  while (TRUE) {\r
+    Status = FvBufFindNextSection (\r
+               SectionStart,\r
+               TotalSectionsSize,\r
+               &Key,\r
+               &NextSection\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (Type == NextSection->Type) {\r
+      if (Section != NULL) {\r
+        *Section = NextSection;\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufShrinkWrap (\r
+  IN VOID *Fv\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Shrinks a firmware volume (in place) to provide a minimal FV.\r
+\r
+  BUGBUG: Does not handle the case where the firmware volume has a\r
+          VTF (Volume Top File).  The VTF will not be moved to the\r
+          end of the extended FV.\r
+\r
+Arguments:\r
+\r
+  Fv - Firmware volume.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN OldSize;\r
+  UINT32 BlockCount;\r
+  UINT32 NewBlockSize = 128;\r
+  UINTN Key;\r
+  EFI_FFS_FILE_HEADER* FileIt;\r
+  VOID* EndOfLastFile;\r
+\r
+  EFI_FIRMWARE_VOLUME_HEADER* FvHdr;\r
+\r
+  Status = FvBufGetSize (Fv, &OldSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = FvBufUnifyBlockSizes (Fv, NewBlockSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Locate the block map in the fv header\r
+  //\r
+  FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+\r
+  //\r
+  // Find the end of the last file\r
+  //\r
+  Key = 0;\r
+  EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength;\r
+  while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, &FileIt))) {\r
+    EndOfLastFile =\r
+      (VOID*)((UINT8*)FileIt + FvBufExpand3ByteSize (FileIt->Size));\r
+  }\r
+\r
+  //\r
+  // Set the BlockCount to have the minimal number of blocks for the Fv.\r
+  //\r
+  BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv);\r
+  BlockCount = BlockCount + NewBlockSize - 1;\r
+  BlockCount = BlockCount / NewBlockSize;\r
+\r
+  //\r
+  // Adjust the block count to shrink the Fv in place.\r
+  //\r
+  FvHdr->BlockMap[0].NumBlocks = BlockCount;\r
+  FvHdr->FvLength = BlockCount * NewBlockSize;\r
+\r
+  //\r
+  // Update the FV header checksum\r
+  //\r
+  FvBufChecksumHeader (Fv);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+FvBufUnifyBlockSizes (\r
+  IN OUT VOID *Fv,\r
+  IN UINTN BlockSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Searches the FFS file for a section by its type\r
+\r
+Arguments:\r
+\r
+  Fv - Address of the Fv in memory\r
+  BlockSize - The size of the blocks to convert the Fv to.  If the total size\r
+              of the Fv is not evenly divisible by this size, then\r
+              EFI_INVALID_PARAMETER will be returned.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  EFI_NOT_FOUND\r
+  EFI_VOLUME_CORRUPTED\r
+\r
+--*/\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;\r
+  EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;\r
+  UINT32 Size;\r
+\r
+  Size = 0;\r
+\r
+  //\r
+  // Scan through the block map list, performing error checking, and adding\r
+  // up the total Fv size.\r
+  //\r
+  while( blk->Length != 0 ||\r
+         blk->NumBlocks != 0\r
+       ) {\r
+    Size = Size + (blk->Length * blk->NumBlocks);\r
+    blk++;\r
+    if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) {\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Make sure that the Fv size is a multiple of the new block size.\r
+  //\r
+  if ((Size % BlockSize) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Zero out the entire block map.\r
+  //\r
+  CommonLibBinderSetMem (\r
+    &hdr->BlockMap,\r
+    (UINTN)blk - (UINTN)&hdr->BlockMap,\r
+    0\r
+    );\r
+\r
+  //\r
+  // Write out the single block map entry.\r
+  //\r
+  hdr->BlockMap[0].Length = (UINT32)BlockSize;\r
+  hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+UINT16\r
+FvBufCalculateSum16 (\r
+  IN UINT16       *Buffer,\r
+  IN UINTN        Size\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+\r
+  This function calculates the UINT16 sum for the requested region.\r
+\r
+Arguments:\r
+\r
+  Buffer      Pointer to buffer containing byte data of component.\r
+  Size        Size of the buffer\r
+\r
+Returns:\r
+\r
+  The 16 bit checksum\r
+\r
+--*/\r
+{\r
+  UINTN   Index;\r
+  UINT16  Sum;\r
+\r
+  Sum = 0;\r
+\r
+  //\r
+  // Perform the word sum for buffer\r
+  //\r
+  for (Index = 0; Index < Size; Index++) {\r
+    Sum = (UINT16) (Sum + Buffer[Index]);\r
+  }\r
+\r
+  return (UINT16) Sum;\r
+}\r
+\r
+\r
+STATIC\r
+UINT16\r
+FvBufCalculateChecksum16 (\r
+  IN UINT16       *Buffer,\r
+  IN UINTN        Size\r
+  )\r
+/*++\r
+  \r
+Routine Description::\r
+\r
+  This function calculates the value needed for a valid UINT16 checksum\r
+\r
+Arguments:\r
+\r
+  Buffer      Pointer to buffer containing byte data of component.\r
+  Size        Size of the buffer\r
+\r
+Returns:\r
+\r
+  The 16 bit checksum value needed.\r
+\r
+--*/\r
+{\r
+  return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size));\r
+}\r
+\r
+\r
+STATIC\r
+UINT8\r
+FvBufCalculateSum8 (\r
+  IN UINT8  *Buffer,\r
+  IN UINTN  Size\r
+  )\r
+/*++\r
+\r
+Description:\r
+\r
+  This function calculates the UINT8 sum for the requested region.\r
+\r
+Input:\r
+\r
+  Buffer      Pointer to buffer containing byte data of component.\r
+  Size        Size of the buffer\r
+\r
+Return:\r
+\r
+  The 8 bit checksum value needed.\r
+\r
+--*/\r
+{\r
+  UINTN   Index;\r
+  UINT8   Sum;\r
+\r
+  Sum = 0;\r
+\r
+  //\r
+  // Perform the byte sum for buffer\r
+  //\r
+  for (Index = 0; Index < Size; Index++) {\r
+    Sum = (UINT8) (Sum + Buffer[Index]);\r
+  }\r
+\r
+  return Sum;\r
+}\r
+\r
+\r
+STATIC\r
+UINT8\r
+FvBufCalculateChecksum8 (\r
+  IN UINT8        *Buffer,\r
+  IN UINTN        Size\r
+  )\r
+/*++\r
+\r
+Description:\r
+\r
+  This function calculates the value needed for a valid UINT8 checksum\r
+\r
+Input:\r
+\r
+  Buffer      Pointer to buffer containing byte data of component.\r
+  Size        Size of the buffer\r
+\r
+Return:\r
+\r
+  The 8 bit checksum value needed.\r
+\r
+--*/\r
+{\r
+  return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size));\r
+}\r
+\r
+\r
diff --git a/Source/C/Common/FirmwareVolumeBufferLib.h b/Source/C/Common/FirmwareVolumeBufferLib.h
new file mode 100644 (file)
index 0000000..d51af93
--- /dev/null
@@ -0,0 +1,166 @@
+/*++\r
+\r
+Copyright (c) 1999 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are 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
+Module Name:\r
+\r
+  FirmwareVolumeBufferLib.h\r
+  \r
+Abstract:\r
+\r
+  EFI Firmware Volume routines which work on a Fv image in buffers.\r
+\r
+--*/\r
+\r
+#ifndef FirmwareVolumeBuffer_h_INCLUDED\r
+#define FirmwareVolumeBuffer_h_INCLUDED\r
+\r
+#include "Common/UefiBaseTypes.h"\r
+#include "Common/PiFirmwareFile.h"\r
+#include "Common/PiFirmwareVolume.h"\r
+\r
+EFI_STATUS\r
+FvBufAddFile (\r
+  IN OUT VOID *Fv,\r
+  IN VOID *File\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufAddFileWithExtend (\r
+  IN OUT VOID **Fv,\r
+  IN VOID *File\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufAddVtfFile (\r
+  IN OUT VOID *Fv,\r
+  IN VOID *File\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufChecksumFile (\r
+  IN OUT VOID *FfsFile\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufChecksumHeader (\r
+  IN OUT VOID *Fv\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufClearAllFiles (\r
+  IN OUT VOID *Fv\r
+  );\r
+\r
+VOID\r
+FvBufCompact3ByteSize (\r
+  OUT VOID* SizeDest,\r
+  IN UINT32 Size\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufCountSections (\r
+  IN VOID* FfsFile,\r
+  IN UINTN* Count\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufDuplicate (\r
+  IN VOID *SourceFv,\r
+  IN OUT VOID **DestinationFv\r
+  );\r
+\r
+UINT32\r
+FvBufExpand3ByteSize (\r
+  IN VOID* Size\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufExtend (\r
+  IN VOID **Fv,\r
+  IN UINTN Size\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufFindFileByName (\r
+  IN VOID *Fv,\r
+  IN EFI_GUID *Name,\r
+  OUT VOID **File\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufFindFileByType (\r
+  IN VOID *Fv,\r
+  IN EFI_FV_FILETYPE Type,\r
+  OUT VOID **File\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufFindNextFile (\r
+  IN VOID *Fv,\r
+  IN OUT UINTN *Key,\r
+  OUT VOID **File\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufFindNextSection (\r
+  IN VOID *SectionsStart,\r
+  IN UINTN TotalSectionsSize,\r
+  IN OUT UINTN *Key,\r
+  OUT VOID **Section\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufFindSectionByType (\r
+  IN VOID *FfsFile,\r
+  IN UINT8 Type,\r
+  OUT VOID **Section\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufGetFileRawData (\r
+  IN  VOID*     FfsFile,\r
+  OUT VOID**    RawData,\r
+  OUT UINTN*    RawDataSize\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufGetSize (\r
+  IN VOID *Fv,\r
+  OUT UINTN *Size\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufPackageFreeformRawFile (\r
+  IN EFI_GUID*  Filename,\r
+  IN VOID*      RawData,\r
+  IN UINTN      RawDataSize,\r
+  OUT VOID**    FfsFile\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufRemoveFile (\r
+  IN OUT VOID *Fv,\r
+  IN EFI_GUID *Name\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufUnifyBlockSizes (\r
+  IN OUT VOID *Fv,\r
+  IN UINTN BlockSize\r
+  );\r
+\r
+EFI_STATUS\r
+FvBufShrinkWrap (\r
+  IN VOID *Fv\r
+  );\r
+\r
+#endif // #ifndef FirmwareVolumeBuffer_h_INCLUDED\r
+\r
index ebaafbf..882128d 100644 (file)
@@ -7,11 +7,13 @@ LIBNAME = Common
 
 OBJECTS = \
   BasePeCoff.o \
+  BinderFuncs.o \
   CommonLib.o \
   Crc32.o \
   Decompress.o \
   EfiCompress.o \
   EfiUtilityMsgs.o \
+  FirmwareVolumeBuffer.o \
   FvLib.o \
   MemoryFile.o \
   MyAlloc.o \
index 839f4c9..cdaa006 100644 (file)
@@ -6,11 +6,13 @@ LIBNAME = Common
 \r
 OBJECTS = \\r
   BasePeCoff.obj \\r
+  BinderFuncs.obj \\r
   CommonLib.obj \\r
   Crc32.obj \\r
   Decompress.obj \\r
   EfiCompress.obj \\r
   EfiUtilityMsgs.obj \\r
+  FirmwareVolumeBuffer.obj \\r
   FvLib.obj \\r
   MemoryFile.obj \\r
   MyAlloc.obj \\r