]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFv/GenFvInternalLib.c
BaseTools: PI 1.6 to support FV extended header contain FV used size
[mirror_edk2.git] / BaseTools / Source / C / GenFv / GenFvInternalLib.c
index ad3e7a6e080ccf2022f6be12f7d2e09fcc0b44e8..2b80e7919ba250c3ce1d4de6a5f13ad790787855 100644 (file)
@@ -1,7 +1,10 @@
 /** @file\r
+This file contains the internal functions required to generate a Firmware Volume.\r
 \r
-Copyright (c) 2004 - 2008, Intel Corporation                                                         \r
-All rights reserved. This program and the accompanying materials                          \r
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>\r
+Portions Copyright (c) 2016 HP Development Company, L.P.<BR>\r
+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
@@ -9,21 +12,18 @@ http://opensource.org/licenses/bsd-license.php
 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
-  GenFvInternalLib.c\r
-\r
-Abstract:\r
-\r
-  This file contains the internal functions required to generate a Firmware Volume.\r
-\r
 **/\r
 \r
 //\r
 // Include files\r
 //\r
-#ifdef __GNUC__\r
+\r
+#if defined(__FreeBSD__)\r
+#include <uuid.h>\r
+#elif defined(__GNUC__)\r
 #include <uuid/uuid.h>\r
+#endif\r
+#ifdef __GNUC__\r
 #include <sys/stat.h>\r
 #endif\r
 #include <string.h>\r
@@ -32,18 +32,25 @@ Abstract:
 #endif\r
 #include <assert.h>\r
 \r
+#include <Guid/FfsSectionAlignmentPadding.h>\r
+\r
 #include "GenFvInternalLib.h"\r
 #include "FvLib.h"\r
 #include "PeCoffLib.h"\r
 #include "WinNtInclude.h"\r
 \r
+#define ARMT_UNCONDITIONAL_JUMP_INSTRUCTION       0xEB000000\r
+#define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION      0x14000000\r
+\r
 BOOLEAN mArm = FALSE;\r
 STATIC UINT32   MaxFfsAlignment = 0;\r
+BOOLEAN VtfFileFlag = FALSE;\r
 \r
-EFI_GUID  mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
+EFI_GUID  mEfiFirmwareVolumeTopFileGuid       = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
 EFI_GUID  mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV];\r
-EFI_GUID  mZeroGuid                 = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};\r
-EFI_GUID  mDefaultCapsuleGuid       = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};\r
+EFI_GUID  mZeroGuid                           = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};\r
+EFI_GUID  mDefaultCapsuleGuid                 = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};\r
+EFI_GUID  mEfiFfsSectionAlignmentPaddingGuid  = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;\r
 \r
 CHAR8      *mFvbAttributeName[] = {\r
   EFI_FVB2_READ_DISABLED_CAP_STRING, \r
@@ -84,7 +91,7 @@ CHAR8      *mFvbAlignmentName[] = {
   EFI_FVB2_ALIGNMENT_64K_STRING, \r
   EFI_FVB2_ALIGNMENT_128K_STRING,\r
   EFI_FVB2_ALIGNMENT_256K_STRING,\r
-  EFI_FVB2_ALIGNMNET_512K_STRING,\r
+  EFI_FVB2_ALIGNMENT_512K_STRING,\r
   EFI_FVB2_ALIGNMENT_1M_STRING,  \r
   EFI_FVB2_ALIGNMENT_2M_STRING,  \r
   EFI_FVB2_ALIGNMENT_4M_STRING,  \r
@@ -158,6 +165,10 @@ UINT8                                   m64kRecoveryStartupApDataArray[SIZEOF_ST
 \r
 FV_INFO                     mFvDataInfo;\r
 CAP_INFO                    mCapDataInfo;\r
+BOOLEAN                     mIsLargeFfs = FALSE;\r
+\r
+EFI_PHYSICAL_ADDRESS mFvBaseAddress[0x10];\r
+UINT32               mFvBaseAddressNumber = 0;\r
 \r
 EFI_STATUS\r
 ParseFvInf (\r
@@ -182,9 +193,10 @@ Returns:
   EFI_NOT_FOUND     A required string was not found in the INF file.\r
 --*/\r
 {\r
-  CHAR8       Value[_MAX_PATH];\r
+  CHAR8       Value[MAX_LONG_FILE_PATH];\r
   UINT64      Value64;\r
-  UINTN       Index, Number, Index1;\r
+  UINTN       Index;\r
+  UINTN       Number;\r
   EFI_STATUS  Status;\r
   EFI_GUID    GuidValue;\r
 \r
@@ -205,6 +217,7 @@ Returns:
       DebugMsg (NULL, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);\r
 \r
       FvInfo->BaseAddress = Value64;\r
+      FvInfo->BaseAddressSet = TRUE;\r
     }\r
   }\r
 \r
@@ -228,22 +241,11 @@ Returns:
   }\r
 \r
   //\r
-  // Read the FV Name Guid\r
+  // Read the FV Extension Header File Name\r
   //\r
-  if (!FvInfo->FvNameGuidSet) {\r
-    Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_NAMEGUID_STRING, 0, Value);\r
-    if (Status == EFI_SUCCESS) {\r
-      //\r
-      // Get the guid value\r
-      //\r
-      Status = StringToGuid (Value, &GuidValue);\r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_NAMEGUID_STRING, Value);\r
-        return EFI_ABORTED;\r
-      }\r
-      memcpy (&FvInfo->FvNameGuid, &GuidValue, sizeof (EFI_GUID));\r
-      FvInfo->FvNameGuidSet = TRUE;\r
-    }\r
+  Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_EXT_HEADER_FILE_NAME, 0, Value);\r
+  if (Status == EFI_SUCCESS) {\r
+    strcpy (FvInfo->FvExtHeaderFile, Value);\r
   }\r
 \r
   //\r
@@ -285,6 +287,19 @@ Returns:
     }\r
   }\r
 \r
+  //\r
+  // Read weak alignment flag\r
+  //\r
+  Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_WEAK_ALIGNMENT_STRING, 0, Value);\r
+  if (Status == EFI_SUCCESS) {\r
+    if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {\r
+      FvInfo->FvAttributes |= EFI_FVB2_WEAK_ALIGNMENT;\r
+    } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {\r
+      Error (NULL, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0.");\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+\r
   //\r
   // Read block maps\r
   //\r
@@ -360,7 +375,7 @@ Returns:
     }\r
   }\r
 \r
-  for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {\r
+  for (Index = 0; Number + Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {\r
     //\r
     // Read the FFS file list\r
     //\r
@@ -371,7 +386,7 @@ Returns:
       // Add the file\r
       //\r
       strcpy (FvInfo->FvFiles[Number + Index], Value);\r
-      DebugMsg (NULL, 0, 9, "FV component file", "the %dth name is %s", Index, Value);\r
+      DebugMsg (NULL, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index, Value);\r
     } else {\r
       break;\r
     }\r
@@ -449,58 +464,98 @@ Returns:
 \r
   case 0:\r
     //\r
-    // 8 byte alignment, mini alignment requirement for FFS file. \r
+    // 1 byte alignment\r
+    //if bit 1 have set, 128K byte alignmnet\r
     //\r
-    *Alignment = 3;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 17;\r
+    } else {\r
+      *Alignment = 0;\r
+    }\r
     break;\r
 \r
   case 1:\r
     //\r
     // 16 byte alignment\r
+    //if bit 1 have set, 256K byte alignment\r
     //\r
-    *Alignment = 4;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 18;\r
+    } else {\r
+      *Alignment = 4;\r
+    }\r
     break;\r
 \r
   case 2:\r
     //\r
     // 128 byte alignment\r
+    //if bit 1 have set, 512K byte alignment\r
     //\r
-    *Alignment = 7;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 19;\r
+    } else {\r
+      *Alignment = 7;\r
+    }\r
     break;\r
 \r
   case 3:\r
     //\r
     // 512 byte alignment\r
+    //if bit 1 have set, 1M byte alignment\r
     //\r
-    *Alignment = 9;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 20;\r
+    } else {\r
+      *Alignment = 9;\r
+    }\r
     break;\r
 \r
   case 4:\r
     //\r
     // 1K byte alignment\r
+    //if bit 1 have set, 2M byte alignment\r
     //\r
-    *Alignment = 10;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 21;\r
+    } else {\r
+      *Alignment = 10;\r
+    }\r
     break;\r
 \r
   case 5:\r
     //\r
     // 4K byte alignment\r
+    //if bit 1 have set, 4M byte alignment\r
     //\r
-    *Alignment = 12;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 22;\r
+    } else {\r
+      *Alignment = 12;\r
+    }\r
     break;\r
 \r
   case 6:\r
     //\r
     // 32K byte alignment\r
+    //if bit 1 have set , 8M byte alignment\r
     //\r
-    *Alignment = 15;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 23;\r
+    } else {\r
+      *Alignment = 15;\r
+    }\r
     break;\r
 \r
   case 7:\r
     //\r
     // 64K byte alignment\r
+    //if bit 1 have set, 16M alignment\r
     //\r
-    *Alignment = 16;\r
+    if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) {\r
+      *Alignment = 24;\r
+    } else {\r
+      *Alignment = 16;\r
+    }\r
     break;\r
 \r
   default:\r
@@ -514,7 +569,9 @@ EFI_STATUS
 AddPadFile (\r
   IN OUT MEMORY_FILE  *FvImage,\r
   IN UINT32           DataAlignment,\r
-  IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader\r
+  IN VOID             *FvEnd,\r
+  IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader,\r
+  IN UINT32           NextFfsSize\r
   )\r
 /*++\r
 \r
@@ -525,9 +582,10 @@ Routine Description:
 \r
 Arguments:\r
 \r
-  FvImage         The memory image of the FV to add it to.  The current offset\r
-                  must be valid.\r
+  FvImage         The memory image of the FV to add it to.\r
+                  The current offset must be valid.\r
   DataAlignment   The data alignment of the next FFS file.\r
+  FvEnd           End of the empty data in FvImage.\r
   ExtHeader       PI FvExtHeader Optional \r
 \r
 Returns:\r
@@ -541,7 +599,12 @@ Returns:
 {\r
   EFI_FFS_FILE_HEADER *PadFile;\r
   UINTN               PadFileSize;\r
+  UINT32              NextFfsHeaderSize;\r
+  UINT32              CurFfsHeaderSize;\r
+  UINT32              Index;\r
 \r
+  Index = 0;\r
+  CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
   //\r
   // Verify input parameters.\r
   //\r
@@ -550,71 +613,76 @@ Returns:
   }\r
 \r
   //\r
-  // Check if a pad file is necessary\r
-  //\r
-  if ((ExtHeader == NULL) && (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0)) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  //\r
-  // Write pad file header\r
+  // Calculate the pad file size\r
   //\r
-  PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
 \r
   //\r
-  // Verify that we have enough space for the file header\r
+  // Append extension header size\r
   //\r
   if (ExtHeader != NULL) {\r
-    if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER) + ExtHeader->ExtHeaderSize) >= (UINTN) FvImage->Eof) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }    \r
+    PadFileSize = ExtHeader->ExtHeaderSize;\r
+    if (PadFileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {\r
+      CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
+    }\r
+    PadFileSize += CurFfsHeaderSize;\r
   } else {\r
-    if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) {\r
-      return EFI_OUT_OF_RESOURCES;\r
+    NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
+    if (NextFfsSize >= MAX_FFS_SIZE) {\r
+      NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
+    }\r
+    //\r
+    // Check if a pad file is necessary\r
+    //\r
+    if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + NextFfsHeaderSize) % DataAlignment == 0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER) + NextFfsHeaderSize;\r
+    //\r
+    // Add whatever it takes to get to the next aligned address\r
+    //\r
+    while ((PadFileSize % DataAlignment) != 0) {\r
+      PadFileSize++;\r
     }\r
+    //\r
+    // Subtract the next file header size\r
+    //\r
+    PadFileSize -= NextFfsHeaderSize;\r
+    //\r
+    // Subtract the starting offset to get size\r
+    //\r
+    PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;\r
   }\r
 \r
   //\r
-  // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.\r
-  //\r
-  PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
-  PadFile->Attributes = 0;\r
-\r
-  //\r
-  // Calculate the pad file size\r
-  //\r
-  //\r
-  // This is the earliest possible valid offset (current plus pad file header\r
-  // plus the next file header)\r
+  // Verify that we have enough space for the file header\r
   //\r
-  if (ExtHeader != NULL) {\r
-    PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2) + ExtHeader->ExtHeaderSize;\r
-  } else {\r
-    PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2);\r
+  if (((UINTN) FvImage->CurrentFilePointer + PadFileSize) > (UINTN) FvEnd) {\r
+    return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   //\r
-  // Add whatever it takes to get to the next aligned address\r
-  //\r
-  while ((PadFileSize % DataAlignment) != 0) {\r
-    PadFileSize++;\r
-  }\r
-  //\r
-  // Subtract the next file header size\r
+  // Write pad file header\r
   //\r
-  PadFileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
+  PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
 \r
   //\r
-  // Subtract the starting offset to get size\r
+  // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.\r
   //\r
-  PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;\r
-  \r
+  PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
+  PadFile->Attributes = 0;\r
+\r
   //\r
   // Write pad file size (calculated size minus next file header size)\r
   //\r
-  PadFile->Size[0]  = (UINT8) (PadFileSize & 0xFF);\r
-  PadFile->Size[1]  = (UINT8) ((PadFileSize >> 8) & 0xFF);\r
-  PadFile->Size[2]  = (UINT8) ((PadFileSize >> 16) & 0xFF);\r
+  if (PadFileSize >= MAX_FFS_SIZE) {\r
+    memset(PadFile->Size, 0, sizeof(UINT8) * 3);\r
+    ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;\r
+    PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;\r
+  } else {\r
+    PadFile->Size[0]  = (UINT8) (PadFileSize & 0xFF);\r
+    PadFile->Size[1]  = (UINT8) ((PadFileSize >> 8) & 0xFF);\r
+    PadFile->Size[2]  = (UINT8) ((PadFileSize >> 16) & 0xFF);\r
+  }\r
 \r
   //\r
   // Fill in checksums and state, they must be 0 for checksumming.\r
@@ -622,7 +690,7 @@ Returns:
   PadFile->IntegrityCheck.Checksum.Header = 0;\r
   PadFile->IntegrityCheck.Checksum.File   = 0;\r
   PadFile->State                          = 0;\r
-  PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
+  PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, CurFfsHeaderSize);\r
   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;\r
 \r
   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
@@ -630,26 +698,39 @@ Returns:
     (EFI_FFS_FILE_HEADER *) PadFile,\r
     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
     );\r
-  \r
-  if (ExtHeader != NULL) {\r
-    //\r
-    // Copy Fv Extension Header and Set Fv Extension header offset\r
-    //\r
-    memcpy (PadFile + 1, ExtHeader, ExtHeader->ExtHeaderSize);\r
-    ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) (PadFile + 1) - (UINTN) FvImage->FileImage);\r
-  }\r
 \r
-  //\r
-  // Verify that we have enough space (including the padding)\r
-  //\r
-  if (((UINTN)PadFile + PadFileSize) >= (UINTN) FvImage->Eof) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
   //\r
   // Update the current FV pointer\r
   //\r
   FvImage->CurrentFilePointer += PadFileSize;\r
 \r
+  if (ExtHeader != NULL) {\r
+    //\r
+    // Copy Fv Extension Header and Set Fv Extension header offset\r
+    //\r
+    if (ExtHeader->ExtHeaderSize > sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER)) {\r
+      for (Index = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER); Index < ExtHeader->ExtHeaderSize;) {\r
+        if (((EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtHeader + Index))-> ExtEntryType == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {\r
+          if (VtfFileFlag) {\r
+            ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)((UINT8 *)ExtHeader + Index))->UsedSize = mFvTotalSize;\r
+          } else {\r
+            ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)((UINT8 *)ExtHeader + Index))->UsedSize = mFvTakenSize;\r
+          }\r
+          break;\r
+        }\r
+        Index += ((EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtHeader + Index))-> ExtEntrySize;\r
+      }\r
+    }\r
+    memcpy ((UINT8 *)PadFile + CurFfsHeaderSize, ExtHeader, ExtHeader->ExtHeaderSize);\r
+    ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) ((UINT8 *)PadFile + CurFfsHeaderSize) - (UINTN) FvImage->FileImage);\r
+         //\r
+         // Make next file start at QWord Boundry\r
+         //\r
+         while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {\r
+           FvImage->CurrentFilePointer++;\r
+         }\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -685,7 +766,7 @@ EFI_STATUS
 WriteMapFile (\r
   IN OUT FILE                  *FvMapFile,\r
   IN     CHAR8                 *FileName,\r
-  IN     EFI_GUID              *FileGuidPtr\r
+  IN     EFI_FFS_FILE_HEADER   *FfsFile\r
   IN     EFI_PHYSICAL_ADDRESS  ImageBaseAddress,\r
   IN     PE_COFF_LOADER_IMAGE_CONTEXT *pImageContext\r
   )\r
@@ -700,7 +781,7 @@ Arguments:
 \r
   FvMapFile             A pointer to FvMap File\r
   FileName              Ffs File PathName\r
-  FileGuidPtr           Guid Value of Ffs file\r
+  FfsFile               A pointer to Ffs file image.\r
   ImageBaseAddress      PeImage Base Address.\r
   pImageContext         Image Context Information.\r
 \r
@@ -710,7 +791,7 @@ Returns:
 \r
 --*/\r
 {\r
-  CHAR8                               PeMapFileName [_MAX_PATH];\r
+  CHAR8                               PeMapFileName [MAX_LONG_FILE_PATH];\r
   CHAR8                               *Cptr, *Cptr2;\r
   CHAR8                               FileGuidName [MAX_LINE_LEN];\r
   FILE                                *PeMapFile;\r
@@ -726,7 +807,11 @@ Returns:
   EFI_IMAGE_OPTIONAL_HEADER_UNION     *ImgHdr;\r
   EFI_TE_IMAGE_HEADER                 *TEImageHeader;\r
   EFI_IMAGE_SECTION_HEADER            *SectionHeader;\r
-  \r
+  long long                           TempLongAddress;\r
+  UINT32                              TextVirtualAddress;\r
+  UINT32                              DataVirtualAddress;\r
+  EFI_PHYSICAL_ADDRESS                LinkTimeBaseAddress;\r
+\r
   //\r
   // Init local variable\r
   //\r
@@ -734,7 +819,7 @@ Returns:
   //\r
   // Print FileGuid to string buffer. \r
   //\r
-  PrintGuidToBuffer (FileGuidPtr, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);\r
+  PrintGuidToBuffer (&FfsFile->Name, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);\r
   \r
   //\r
   // Construct Map file Name \r
@@ -800,34 +885,49 @@ Returns:
     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
     Index = TEImageHeader->NumberOfSections;\r
   }\r
-  \r
+\r
   //\r
   // module information output\r
   //\r
   if (ImageBaseAddress == 0) {\r
     fprintf (FvMapFile, "%s (dummy) (", KeyWord);\r
-    fprintf (FvMapFile, "BaseAddress=%08lx, ", ImageBaseAddress);\r
+    fprintf (FvMapFile, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress);\r
+  } else {\r
+    fprintf (FvMapFile, "%s (Fixed Flash Address, ", KeyWord);\r
+    fprintf (FvMapFile, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress + Offset));\r
+  }\r
+\r
+  if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && pImageContext->Machine == EFI_IMAGE_MACHINE_IA64) {\r
+    //\r
+    // Process IPF PLABEL to get the real address after the image has been rebased. \r
+    // PLABEL structure is got by AddressOfEntryPoint offset to ImageBuffer stored in pImageContext->Handle.\r
+    //\r
+    fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (*(UINT64 *)((UINTN) pImageContext->Handle + (UINTN) AddressOfEntryPoint)));\r
   } else {\r
-    fprintf (FvMapFile, "%s (", KeyWord);\r
-    fprintf (FvMapFile, "BaseAddress=%08lx, ", ImageBaseAddress + Offset);\r
+    fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint));\r
   }\r
-  fprintf (FvMapFile, "EntryPoint=%08lx, ", ImageBaseAddress + AddressOfEntryPoint);\r
-  fprintf (FvMapFile, "GUID=%s", FileGuidName);\r
   fprintf (FvMapFile, ")\n"); \r
   \r
+  fprintf (FvMapFile, "(GUID=%s", FileGuidName);\r
+  TextVirtualAddress = 0;\r
+  DataVirtualAddress = 0;\r
   for (; Index > 0; Index --, SectionHeader ++) {\r
-        if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {\r
-               fprintf (FvMapFile, ".textbaseaddress=%08lx ",ImageBaseAddress + SectionHeader->VirtualAddress);\r
+    if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {\r
+               TextVirtualAddress = SectionHeader->VirtualAddress;\r
        } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {\r
-         fprintf (FvMapFile, ".databaseaddress=%08lx ",ImageBaseAddress + SectionHeader->VirtualAddress);\r
+         DataVirtualAddress = SectionHeader->VirtualAddress;\r
+       } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".sdata") == 0) {\r
+         DataVirtualAddress = SectionHeader->VirtualAddress;\r
        }\r
   }\r
-  fprintf (FvMapFile, "\n\n"); \r
+  fprintf (FvMapFile, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + TextVirtualAddress));\r
+  fprintf (FvMapFile, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + DataVirtualAddress));\r
+  fprintf (FvMapFile, ")\n\n");\r
    \r
   //\r
   // Open PeMapFile\r
   //\r
-  PeMapFile = fopen (PeMapFileName, "r");\r
+  PeMapFile = fopen (LongFilePath (PeMapFileName), "r");\r
   if (PeMapFile == NULL) {\r
     // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);\r
     return EFI_ABORTED;\r
@@ -837,6 +937,7 @@ Returns:
   //\r
   // Output Functions information into Fv Map file\r
   //\r
+  LinkTimeBaseAddress = 0;\r
   while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {\r
     //\r
     // Skip blank line\r
@@ -862,6 +963,9 @@ Returns:
         //\r
         FunctionType = 2;\r
         fgets (Line, MAX_LINE_LEN, PeMapFile);\r
+      } else if (stricmp (KeyWord, "Preferred") ==0) {\r
+        sscanf (Line + strlen (" Preferred load address is"), "%llx", &TempLongAddress);\r
+        LinkTimeBaseAddress = (UINT64) TempLongAddress;\r
       }\r
       continue;\r
     }\r
@@ -869,25 +973,17 @@ Returns:
     // Printf Function Information\r
     //\r
     if (FunctionType == 1) {\r
-      sscanf (Line, "%s %s %lx %s", KeyWord, FunctionName, &FunctionAddress, FunctionTypeName);\r
+      sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
+      FunctionAddress = (UINT64) TempLongAddress;\r
       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
-        fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
-        fprintf (FvMapFile, "(%08lx) F  ", FunctionAddress - Offset);\r
-        fprintf (FvMapFile, "%s\n", FunctionName);\r
-    } else {\r
-        fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
-        fprintf (FvMapFile, "(%08lx)    ", FunctionAddress - Offset);\r
+        fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));\r
         fprintf (FvMapFile, "%s\n", FunctionName);\r
       }\r
     } else if (FunctionType == 2) {\r
-      sscanf (Line, "%s %s %lx %s", KeyWord, FunctionName, &FunctionAddress, FunctionTypeName);\r
+      sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
+      FunctionAddress = (UINT64) TempLongAddress;\r
       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
-        fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
-        fprintf (FvMapFile, "(%08lx) FS ", FunctionAddress - Offset);\r
-        fprintf (FvMapFile, "%s\n", FunctionName);\r
-      } else {\r
-        fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
-        fprintf (FvMapFile, "(%08lx)    ", FunctionAddress - Offset);\r
+        fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));\r
         fprintf (FvMapFile, "%s\n", FunctionName);\r
       }\r
     }\r
@@ -901,13 +997,161 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+STATIC\r
+BOOLEAN\r
+AdjustInternalFfsPadding (\r
+  IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
+  IN OUT  MEMORY_FILE           *FvImage,\r
+  IN      UINTN                 Alignment,\r
+  IN OUT  UINTN                 *FileSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function looks for a dedicated alignment padding section in the FFS, and\r
+  shrinks it to the size required to line up subsequent sections correctly.\r
+\r
+Arguments:\r
+\r
+  FfsFile               A pointer to Ffs file image.\r
+  FvImage               The memory image of the FV to adjust it to.\r
+  Alignment             Current file alignment\r
+  FileSize              Reference to a variable holding the size of the FFS file\r
+\r
+Returns:\r
+\r
+  TRUE                  Padding section was found and updated successfully\r
+  FALSE                 Otherwise\r
+\r
+--*/\r
+{\r
+  EFI_FILE_SECTION_POINTER  PadSection;\r
+  UINT8                     *Remainder;\r
+  EFI_STATUS                Status;\r
+  UINT32                    FfsHeaderLength;\r
+  UINT32                    FfsFileLength;\r
+  UINT32                    PadSize;\r
+  UINTN                     Misalignment;\r
+  EFI_FFS_INTEGRITY_CHECK   *IntegrityCheck;\r
+\r
+  //\r
+  // Figure out the misalignment: all FFS sections are aligned relative to the\r
+  // start of the FFS payload, so use that as the base of the misalignment\r
+  // computation.\r
+  //\r
+  FfsHeaderLength = GetFfsHeaderLength(FfsFile);\r
+  Misalignment = (UINTN) FvImage->CurrentFilePointer -\r
+                 (UINTN) FvImage->FileImage + FfsHeaderLength;\r
+  Misalignment &= Alignment - 1;\r
+  if (Misalignment == 0) {\r
+    // Nothing to do, return success\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // We only apply this optimization to FFS files with the FIXED attribute set,\r
+  // since the FFS will not be loadable at arbitrary offsets anymore after\r
+  // we adjust the size of the padding section.\r
+  //\r
+  if ((FfsFile->Attributes & FFS_ATTRIB_FIXED) == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Look for a dedicated padding section that we can adjust to compensate\r
+  // for the misalignment. If such a padding section exists, it precedes all\r
+  // sections with alignment requirements, and so the adjustment will correct\r
+  // all of them.\r
+  //\r
+  Status = GetSectionByType (FfsFile, EFI_SECTION_FREEFORM_SUBTYPE_GUID, 1,\r
+             &PadSection);\r
+  if (EFI_ERROR (Status) ||\r
+      CompareGuid (&PadSection.FreeformSubtypeSection->SubTypeGuid,\r
+        &mEfiFfsSectionAlignmentPaddingGuid) != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Find out if the size of the padding section is sufficient to compensate\r
+  // for the misalignment.\r
+  //\r
+  PadSize = GetSectionFileLength (PadSection.CommonHeader);\r
+  if (Misalignment > PadSize - sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Move the remainder of the FFS file towards the front, and adjust the\r
+  // file size output parameter.\r
+  //\r
+  Remainder = (UINT8 *) PadSection.CommonHeader + PadSize;\r
+  memmove (Remainder - Misalignment, Remainder,\r
+           *FileSize - (UINTN) (Remainder - (UINTN) FfsFile));\r
+  *FileSize -= Misalignment;\r
+\r
+  //\r
+  // Update the padding section's length with the new values. Note that the\r
+  // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2\r
+  // ExtendedSize.\r
+  //\r
+  PadSize -= Misalignment;\r
+  PadSection.CommonHeader->Size[0] = (UINT8) (PadSize & 0xff);\r
+  PadSection.CommonHeader->Size[1] = (UINT8) ((PadSize & 0xff00) >> 8);\r
+  PadSection.CommonHeader->Size[2] = (UINT8) ((PadSize & 0xff0000) >> 16);\r
+\r
+  //\r
+  // Update the FFS header with the new overall length\r
+  //\r
+  FfsFileLength = GetFfsFileLength (FfsFile) - Misalignment;\r
+  if (FfsHeaderLength > sizeof(EFI_FFS_FILE_HEADER)) {\r
+    ((EFI_FFS_FILE_HEADER2 *)FfsFile)->ExtendedSize = FfsFileLength;\r
+  } else {\r
+    FfsFile->Size[0] = (UINT8) (FfsFileLength & 0x000000FF);\r
+    FfsFile->Size[1] = (UINT8) ((FfsFileLength & 0x0000FF00) >> 8);\r
+    FfsFile->Size[2] = (UINT8) ((FfsFileLength & 0x00FF0000) >> 16);\r
+  }\r
+\r
+  //\r
+  // Clear the alignment bits: these have become meaningless now that we have\r
+  // adjusted the padding section.\r
+  //\r
+  FfsFile->Attributes &= ~(FFS_ATTRIB_DATA_ALIGNMENT | FFS_ATTRIB_DATA_ALIGNMENT2);\r
+\r
+  //\r
+  // Recalculate the FFS header checksum. Instead of setting Header and State\r
+  // both to zero, set Header to (UINT8)(-State) so State preserves its original\r
+  // value\r
+  //\r
+  IntegrityCheck = &FfsFile->IntegrityCheck;\r
+  IntegrityCheck->Checksum.Header = (UINT8) (0x100 - FfsFile->State);\r
+  IntegrityCheck->Checksum.File = 0;\r
+\r
+  IntegrityCheck->Checksum.Header = CalculateChecksum8 (\r
+                                      (UINT8 *) FfsFile, FfsHeaderLength);\r
+\r
+  if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
+    //\r
+    // Ffs header checksum = zero, so only need to calculate ffs body.\r
+    //\r
+    IntegrityCheck->Checksum.File = CalculateChecksum8 (\r
+                                      (UINT8 *) FfsFile + FfsHeaderLength,\r
+                                      FfsFileLength - FfsHeaderLength);\r
+  } else {\r
+    IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
 EFI_STATUS\r
 AddFile (\r
   IN OUT MEMORY_FILE          *FvImage,\r
   IN FV_INFO                  *FvInfo,\r
   IN UINTN                    Index,\r
   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage,\r
-  IN FILE                     *FvMapFile  \r
+  IN FILE                     *FvMapFile,\r
+  IN FILE                     *FvReportFile\r
   )\r
 /*++\r
 \r
@@ -925,6 +1169,7 @@ Arguments:
   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal\r
                 to the end of the FvImage then no VTF previously found.\r
   FvMapFile     Pointer to FvMap File\r
+  FvReportFile  Pointer to FvReport File\r
 \r
 Returns:\r
 \r
@@ -942,6 +1187,7 @@ Returns:
   UINT32                CurrentFileAlignment;\r
   EFI_STATUS            Status;\r
   UINTN                 Index1;\r
+  UINT8                 FileGuidString[PRINTED_GUID_BUFFER_SIZE];\r
   \r
   Index1 = 0;\r
   //\r
@@ -954,7 +1200,7 @@ Returns:
   //\r
   // Read the file to add\r
   //\r
-  NewFile = fopen (FvInfo->FvFiles[Index], "rb");\r
+  NewFile = fopen (LongFilePath (FvInfo->FvFiles[Index]), "rb");\r
 \r
   if (NewFile == NULL) {\r
     Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);\r
@@ -971,6 +1217,7 @@ Returns:
   //\r
   FileBuffer = malloc (FileSize);\r
   if (FileBuffer == NULL) {\r
+    fclose (NewFile);\r
     Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -1010,7 +1257,7 @@ Returns:
   Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);\r
   if (EFI_ERROR (Status)) {\r
     free (FileBuffer);\r
-    Error (NULL, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo->FvFiles[Index]);\r
+    Error (NULL, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo->FvFiles[Index]);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -1028,8 +1275,9 @@ Returns:
   //\r
   for (Index1 = 0; Index1 < Index; Index1 ++) {\r
     if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {\r
-      Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %dth file have the same file GUID.", Index1 + 1, Index + 1);\r
+      Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);\r
       PrintGuid ((EFI_GUID *) FileBuffer);\r
+      free (FileBuffer);\r
       return EFI_INVALID_PARAMETER;\r
     }\r
   }\r
@@ -1066,8 +1314,8 @@ Returns:
       //\r
       // Sanity check. The file MUST align appropriately\r
       //\r
-      if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
-        Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %d-byte boundary.", 1 << CurrentFileAlignment);\r
+      if (((UINTN) *VtfFileImage + GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)FileBuffer) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
+        Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));\r
         free (FileBuffer);\r
         return EFI_ABORTED;\r
       }\r
@@ -1075,11 +1323,19 @@ Returns:
       // Rebase the PE or TE image in FileBuffer of FFS file for XIP \r
       // Rebase for the debug genfvmap tool\r
       //\r
-      FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);\r
+      Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);\r
+      if (EFI_ERROR (Status)) {\r
+        Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]);\r
+        return Status;\r
+      }          \r
       //\r
       // copy VTF File\r
       //\r
       memcpy (*VtfFileImage, FileBuffer, FileSize);\r
+      \r
+      PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); \r
+      fprintf (FvReportFile, "0x%08X %s\n", (unsigned)(UINTN) (((UINT8 *)*VtfFileImage) - (UINTN)FvImage->FileImage), FileGuidString);\r
+\r
       free (FileBuffer);\r
       DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);\r
       return EFI_SUCCESS;\r
@@ -1096,25 +1352,34 @@ Returns:
   //\r
   // Add pad file if necessary\r
   //\r
-  Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, NULL);\r
-  if (EFI_ERROR (Status)) {\r
-    Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
-    free (FileBuffer);\r
-    return EFI_ABORTED;\r
+  if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER *) FileBuffer, FvImage,\r
+         1 << CurrentFileAlignment, &FileSize)) {\r
+    Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL, FileSize);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
+      free (FileBuffer);\r
+      return EFI_ABORTED;\r
+    }\r
   }\r
   //\r
   // Add file\r
   //\r
-  if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) {\r
+  if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) {\r
     //\r
     // Rebase the PE or TE image in FileBuffer of FFS file for XIP. \r
     // Rebase Bs and Rt drivers for the debug genfvmap tool.\r
     //\r
-    FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);\r
+    Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);\r
+       if (EFI_ERROR (Status)) {\r
+         Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]);\r
+         return Status;\r
+       }               \r
     //\r
     // Copy the file\r
     //\r
     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
+    PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); \r
+    fprintf (FvReportFile, "0x%08X %s\n", (unsigned) (FvImage->CurrentFilePointer - FvImage->FileImage), FileGuidString);\r
     FvImage->CurrentFilePointer += FileSize;\r
   } else {\r
     Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);\r
@@ -1164,6 +1429,7 @@ Returns:
 {\r
   EFI_FFS_FILE_HEADER *PadFile;\r
   UINTN               FileSize;\r
+  UINT32              FfsHeaderSize;\r
 \r
   //\r
   // If there is no VTF or the VTF naturally follows the previous file without a\r
@@ -1174,6 +1440,10 @@ Returns:
     return EFI_SUCCESS;\r
   }\r
 \r
+  if ((UINTN) VtfFileImage < (UINTN) FvImage->CurrentFilePointer) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   //\r
   // Pad file starts at beginning of free space\r
   //\r
@@ -1189,9 +1459,18 @@ Returns:
   // FileSize includes the EFI_FFS_FILE_HEADER\r
   //\r
   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
-  PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
-  PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
-  PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
+  if (FileSize >= MAX_FFS_SIZE) {\r
+    PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;\r
+    memset(PadFile->Size, 0, sizeof(UINT8) * 3);\r
+    ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = FileSize;\r
+    FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
+    mIsLargeFfs = TRUE;\r
+  } else {\r
+    PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
+    PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
+    PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
+    FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
+  }\r
 \r
   //\r
   // Fill in checksums and state, must be zero during checksum calculation.\r
@@ -1199,7 +1478,7 @@ Returns:
   PadFile->IntegrityCheck.Checksum.Header = 0;\r
   PadFile->IntegrityCheck.Checksum.File   = 0;\r
   PadFile->State                          = 0;\r
-  PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
+  PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, FfsHeaderSize);\r
   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;\r
 \r
   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
@@ -1261,11 +1540,14 @@ Returns:
   UINT8                     *BytePointer2;\r
   UINT16                    *WordPointer;\r
   UINT16                    CheckSum;\r
+  UINT32                    IpiVector;\r
   UINTN                     Index;\r
   EFI_FFS_FILE_STATE        SavedState;\r
   UINT64                    FitAddress;\r
   FIT_TABLE                 *FitTablePtr;\r
-  UINT32                    IpiVector;\r
+  BOOLEAN                   Vtf0Detected;\r
+  UINT32                    FfsHeaderSize;\r
+  UINT32                    SecHeaderSize;\r
 \r
   //\r
   // Verify input parameters\r
@@ -1286,11 +1568,32 @@ Returns:
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (\r
+      (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >=\r
+        IA32_X64_VTF_SIGNATURE_OFFSET) &&\r
+      (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof -\r
+                                  IA32_X64_VTF_SIGNATURE_OFFSET) ==\r
+        IA32_X64_VTF0_SIGNATURE)\r
+     ) {\r
+    Vtf0Detected = TRUE;\r
+  } else {\r
+    Vtf0Detected = FALSE;\r
+  }\r
+\r
   //\r
   // Find the Sec Core\r
   //\r
   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
+    if (Vtf0Detected) {\r
+      //\r
+      // If the SEC core file is not found, but the VTF-0 signature\r
+      // is found, we'll treat it as a VTF-0 'Volume Top File'.\r
+      // This means no modifications are required to the VTF.\r
+      //\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
     Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");\r
     return EFI_ABORTED;\r
   }\r
@@ -1307,8 +1610,9 @@ Returns:
     return EFI_ABORTED;\r
   }\r
 \r
+  SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader);\r
   Status = GetPe32Info (\r
-            (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
+            (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize),\r
             &EntryPoint,\r
             &BaseOfCode,\r
             &MachineType\r
@@ -1319,13 +1623,26 @@ Returns:
     return EFI_ABORTED;\r
   }  \r
 \r
+  if (\r
+       Vtf0Detected &&\r
+       (MachineType == EFI_IMAGE_MACHINE_IA32 ||\r
+        MachineType == EFI_IMAGE_MACHINE_X64)\r
+     ) {\r
+    //\r
+    // If the SEC core code is IA32 or X64 and the VTF-0 signature\r
+    // is found, we'll treat it as a VTF-0 'Volume Top File'.\r
+    // This means no modifications are required to the VTF.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   //\r
   // Physical address is FV base + offset of PE32 + offset of the entry point\r
   //\r
   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
-  SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
+  SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage;\r
   SecCorePhysicalAddress += EntryPoint;\r
-  DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%X", SecCorePhysicalAddress); \r
+  DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); \r
 \r
   //\r
   // Find the PEI Core\r
@@ -1348,8 +1665,9 @@ Returns:
     return EFI_ABORTED;\r
   }\r
 \r
+  SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader);\r
   Status = GetPe32Info (\r
-            (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
+            (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize),\r
             &EntryPoint,\r
             &BaseOfCode,\r
             &MachineType\r
@@ -1363,9 +1681,9 @@ Returns:
   // Physical address is FV base + offset of PE32 + offset of the entry point\r
   //\r
   PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
-  PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
+  PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage;\r
   PeiCorePhysicalAddress += EntryPoint;\r
-  DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%X", PeiCorePhysicalAddress);\r
+  DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
 \r
   if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
     //\r
@@ -1381,8 +1699,8 @@ Returns:
     //\r
     if (PeiCorePhysicalAddress & 0xF) {\r
       Error (NULL, 0, 3000, "Invalid",\r
-        "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
-        PeiCorePhysicalAddress\r
+        "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",\r
+        (unsigned long long) PeiCorePhysicalAddress\r
         );\r
       return EFI_ABORTED;\r
     }\r
@@ -1411,8 +1729,8 @@ Returns:
     //\r
     if (SecCorePhysicalAddress & 0xF) {\r
       Error (NULL, 0, 3000, "Invalid",\r
-        "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
-        SecCorePhysicalAddress\r
+        "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",\r
+        (unsigned long long) SecCorePhysicalAddress\r
         );\r
       return EFI_ABORTED;\r
     }\r
@@ -1422,16 +1740,6 @@ Returns:
     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
 \r
-  } else if (\r
-    (MachineType == EFI_IMAGE_MACHINE_IA32 ||\r
-     MachineType == EFI_IMAGE_MACHINE_X64) &&\r
-    (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >= IA32_X64_VTF_SIGNATURE_OFFSET) &&\r
-    (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof - IA32_X64_VTF_SIGNATURE_OFFSET) ==\r
-      IA32_X64_VTF0_SIGNATURE)\r
-    ) {\r
-    //\r
-    // If VTF-0 signature is found, then no modifications are needed.\r
-    //\r
   } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {\r
     //\r
     // Get the location to update\r
@@ -1448,7 +1756,7 @@ Returns:
     // \r
     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);\r
     \r
-    Ia32SecEntryOffset   = SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2);\r
+    Ia32SecEntryOffset   = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));\r
     if (Ia32SecEntryOffset <= -65536) {\r
       Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");\r
       return STATUS_ERROR;\r
@@ -1461,7 +1769,7 @@ Returns:
     //\r
     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);\r
-    DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%X.", FvInfo->BaseAddress);\r
+    DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);\r
 \r
     //\r
     // Update the Startup AP in the FVH header block ZeroVector region.\r
@@ -1481,7 +1789,7 @@ Returns:
       //\r
       Status = FindApResetVectorPosition (FvImage, &BytePointer);\r
       if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");\r
+        Error (NULL, 0, 3000, "Invalid", "FV image does not have enough space to place AP reset vector. The FV image needs to reserve at least 4KB of unused space.");\r
         return EFI_ABORTED;\r
       }\r
     }\r
@@ -1507,9 +1815,9 @@ Returns:
     //\r
     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. \r
     //\r
-    IpiVector  = FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer);\r
-    DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", IpiVector);\r
-    if (IpiVector & 0xFFF != 0) {\r
+    IpiVector  = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));\r
+    DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);\r
+    if ((IpiVector & 0xFFF) != 0) {\r
       Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");\r
       return EFI_ABORTED;\r
     }\r
@@ -1526,8 +1834,13 @@ Returns:
     // Since the ARM reset vector is in the FV Header you really don't need a\r
     // Volume Top File, but if you have one for some reason don't crash...\r
     //\r
+  } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) {\r
+    //\r
+    // Since the AArch64 reset vector is in the FV Header you really don't need a\r
+    // Volume Top File, but if you have one for some reason don't crash...\r
+    //\r
   } else {\r
-    Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", (UINT32) MachineType);\r
+    Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);\r
     return EFI_ABORTED;\r
   }\r
 \r
@@ -1538,9 +1851,10 @@ Returns:
   VtfFile->IntegrityCheck.Checksum.File = 0;\r
   VtfFile->State                        = 0;\r
   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
+    FfsHeaderSize = GetFfsHeaderLength(VtfFile);\r
     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
-                                              (UINT8 *) VtfFile,\r
-                                              GetLength (VtfFile->Size)\r
+                                              (UINT8 *) ((UINT8 *)VtfFile + FfsHeaderSize),\r
+                                              GetFfsFileLength (VtfFile) - FfsHeaderSize\r
                                               );\r
   } else {\r
     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
@@ -1551,254 +1865,474 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 EFI_STATUS\r
-UpdateArmResetVectorIfNeeded (\r
-  IN MEMORY_FILE            *FvImage,\r
-  IN FV_INFO                *FvInfo\r
+FindCorePeSection(\r
+  IN VOID                       *FvImageBuffer,\r
+  IN UINT64                     FvSize,\r
+  IN EFI_FV_FILETYPE            FileType,\r
+  OUT EFI_FILE_SECTION_POINTER  *Pe32Section\r
   )\r
 /*++\r
 \r
 Routine Description:\r
-  This parses the FV looking for SEC and patches that address into the \r
-  beginning of the FV header.\r
-\r
-  For ARM the reset vector is at 0x00000000 or 0xFFFF0000.\r
-  This would commonly map to the first entry in the ROM. \r
-  ARM Exceptions:\r
-  Reset            +0    \r
-  Undefined        +4\r
-  SWI              +8\r
-  Prefetch Abort   +12\r
-  Data Abort       +16\r
-  IRQ              +20\r
-  FIQ              +24\r
-\r
-  We support two schemes on ARM.\r
-  1) Begining of the FV is the reset vector\r
-  2) Reset vector is data bytes FDF file and that code branches to reset vector \r
-    in the beginning of the FV (fixed size offset).\r
-\r
 \r
-  Need to have the jump for the reset vector at location zero.\r
-  We also need to store the address or PEI (if it exists).\r
-  We stub out a return from interrupt in case the debugger \r
-   is using SWI.\r
-  The optional entry to the common exception handler is \r
-   to support full featured exception handling from ROM and is currently \r
-    not support by this tool.\r
+  Recursively searches the FV for the FFS file of specified type (typically\r
+  SEC or PEI core) and extracts the PE32 section for further processing.\r
 \r
 Arguments:\r
-  FvImage       Memory file for the FV memory image\r
-  FvInfo        Information read from INF file.\r
+\r
+  FvImageBuffer   Buffer containing FV data\r
+  FvSize          Size of the FV\r
+  FileType        Type of FFS file to search for\r
+  Pe32Section     PE32 section pointer when FFS file is found.\r
 \r
 Returns:\r
 \r
   EFI_SUCCESS             Function Completed successfully.\r
   EFI_ABORTED             Error encountered.\r
   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
-  EFI_NOT_FOUND           PEI Core file not found.\r
+  EFI_NOT_FOUND           Core file not found.\r
 \r
 --*/\r
 {\r
-  EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
-  EFI_FFS_FILE_HEADER       *SecCoreFile;\r
-  EFI_STATUS                Status;\r
-  EFI_FILE_SECTION_POINTER  Pe32Section;\r
-  UINT32                    EntryPoint;\r
-  UINT32                    BaseOfCode;\r
-  UINT16                    MachineType;\r
-  EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
-  EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
-  INT32                     ResetVector[4]; // 0 - is branch relative to SEC entry point\r
-                                            // 1 - PEI Entry Point\r
-                                            // 2 - movs pc,lr for a SWI handler\r
-                                            // 3 - Place holder for Common Exception Handler\r
-\r
-  //\r
-  // Verify input parameters\r
-  //\r
-  if (FvImage == NULL || FvInfo == NULL) {\r
+  EFI_STATUS                  Status;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *OrigFvHeader;\r
+  UINT32                      OrigFvLength;\r
+  EFI_FFS_FILE_HEADER         *CoreFfsFile;\r
+  UINTN                       FvImageFileCount;\r
+  EFI_FFS_FILE_HEADER         *FvImageFile;\r
+  UINTN                       EncapFvSectionCount;\r
+  EFI_FILE_SECTION_POINTER    EncapFvSection;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *EncapsulatedFvHeader;\r
+\r
+  if (Pe32Section == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+\r
   //\r
-  // Initialize FV library\r
+  // Initialize FV library, saving previous values\r
   //\r
-  InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
+  OrigFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NULL;\r
+  GetFvHeader (&OrigFvHeader, &OrigFvLength);\r
+  InitializeFvLib(FvImageBuffer, (UINT32)FvSize);\r
 \r
   //\r
-  // Find the Sec Core\r
+  // First see if we can obtain the file directly in outer FV\r
   //\r
-  Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
-  if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
+  Status = GetFileByType(FileType, 1, &CoreFfsFile);\r
+  if (!EFI_ERROR(Status) && (CoreFfsFile != NULL) ) {\r
+\r
     //\r
-    // Maybe hardware does SEC job and we only have PEI Core?\r
+    // Core found, now find PE32 or TE section\r
     //\r
+    Status = GetSectionByType(CoreFfsFile, EFI_SECTION_PE32, 1, Pe32Section);\r
+    if (EFI_ERROR(Status)) {\r
+      Status = GetSectionByType(CoreFfsFile, EFI_SECTION_TE, 1, Pe32Section);\r
+    }\r
+\r
+    if (EFI_ERROR(Status)) {\r
+      Error(NULL, 0, 3000, "Invalid", "could not find a PE32 section in the core file.");\r
+      return EFI_ABORTED;\r
+    }\r
 \r
     //\r
-    // Find the PEI Core. It may not exist if SEC loads DXE core directly\r
+    // Core PE/TE section, found, return\r
     //\r
-    PeiCorePhysicalAddress = 0;\r
-    Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
-    if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {\r
-      //\r
-      // PEI Core found, now find PE32 or TE section\r
-      //\r
-      Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
-      if (Status == EFI_NOT_FOUND) {\r
-        Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
-      }\r
-    \r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");\r
-        return EFI_ABORTED;\r
-      }\r
-    \r
-      Status = GetPe32Info (\r
-                (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
-                &EntryPoint,\r
-                &BaseOfCode,\r
-                &MachineType\r
-                );\r
-    \r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");\r
-        return EFI_ABORTED;\r
+    Status = EFI_SUCCESS;\r
+    goto EarlyExit;\r
+  }\r
+\r
+  //\r
+  // File was not found, look for FV Image file\r
+  //\r
+\r
+  // iterate through all FV image files in outer FV\r
+  for (FvImageFileCount = 1;; FvImageFileCount++) {\r
+\r
+    Status = GetFileByType(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, FvImageFileCount, &FvImageFile);\r
+\r
+    if (EFI_ERROR(Status) || (FvImageFile == NULL) ) {\r
+      // exit FV image file loop, no more found\r
+      break;\r
+    }\r
+\r
+    // Found an fv image file, look for an FV image section.  The PI spec does not\r
+    // preclude multiple FV image sections so we loop accordingly.\r
+    for (EncapFvSectionCount = 1;; EncapFvSectionCount++) {\r
+\r
+      // Look for the next FV image section.  The section search code will\r
+      // iterate into encapsulation sections.  For example, it will iterate\r
+      // into an EFI_SECTION_GUID_DEFINED encapsulation section to find the\r
+      // EFI_SECTION_FIRMWARE_VOLUME_IMAGE sections contained therein.\r
+      Status = GetSectionByType(FvImageFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EncapFvSectionCount, &EncapFvSection);\r
+\r
+      if (EFI_ERROR(Status)) {\r
+        // exit section inner loop, no more found\r
+        break;\r
       }\r
-      //\r
-      // Physical address is FV base + offset of PE32 + offset of the entry point\r
-      //\r
-      PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
-      PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
-      PeiCorePhysicalAddress += EntryPoint;\r
-      DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%X", PeiCorePhysicalAddress);\r
-\r
-      if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\r
-        memset (ResetVector, 0, sizeof (ResetVector));\r
-        // Address of PEI Core, if we have one\r
-        ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
+\r
+      EncapsulatedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)EncapFvSection.FVImageSection + GetSectionHeaderLength(EncapFvSection.FVImageSection));\r
+\r
+      // recurse to search the encapsulated FV for this core file type\r
+      Status = FindCorePeSection(EncapsulatedFvHeader, EncapsulatedFvHeader->FvLength, FileType, Pe32Section);\r
+\r
+      if (!EFI_ERROR(Status)) {\r
+        // we found the core in the capsulated image, success\r
+        goto EarlyExit;\r
       }\r
-      \r
-      //\r
-      // Copy to the beginning of the FV \r
-      //\r
-      memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
 \r
-    }\r
+    } // end encapsulated fv image section loop\r
+  } // end fv image file loop\r
 \r
-    return EFI_SUCCESS;\r
+  // core was not found\r
+  Status = EFI_NOT_FOUND;\r
+\r
+EarlyExit:\r
+\r
+  // restore FV lib values\r
+  if(OrigFvHeader != NULL) {\r
+    InitializeFvLib(OrigFvHeader, OrigFvLength);\r
   }\r
-  \r
-  //\r
-  // Sec Core found, now find PE32 section\r
-  //\r
-  Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
-  if (Status == EFI_NOT_FOUND) {\r
-    Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+GetCoreMachineType(\r
+  IN  EFI_FILE_SECTION_POINTER     Pe32Section,\r
+  OUT UINT16                      *CoreMachineType\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Returns the machine type of a P32 image, typically SEC or PEI core.\r
+\r
+Arguments:\r
+\r
+  Pe32Section       PE32 section data\r
+  CoreMachineType   The extracted machine type\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS             Function Completed successfully.\r
+  EFI_ABORTED             Error encountered.\r
+  EFI_INVALID_PARAMETER   A required parameter was NULL.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT32                      EntryPoint;\r
+  UINT32                      BaseOfCode;\r
+\r
+  if (CoreMachineType == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
+  Status = GetPe32Info(\r
+    (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),\r
+    &EntryPoint,\r
+    &BaseOfCode,\r
+    CoreMachineType\r
+    );\r
+  if (EFI_ERROR(Status)) {\r
+    Error(NULL, 0, 3000, "Invalid", "could not get the PE32 machine type for the core.");\r
     return EFI_ABORTED;\r
   }\r
 \r
-  Status = GetPe32Info (\r
-            (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
-            &EntryPoint,\r
-            &BaseOfCode,\r
-            &MachineType\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");\r
-    return EFI_ABORTED;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetCoreEntryPointAddress(\r
+  IN VOID                         *FvImageBuffer,\r
+  IN FV_INFO                      *FvInfo,\r
+  IN  EFI_FILE_SECTION_POINTER     Pe32Section,\r
+  OUT EFI_PHYSICAL_ADDRESS        *CoreEntryAddress\r
+)\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Returns the physical address of the core (SEC or PEI) entry point.\r
+\r
+Arguments:\r
+\r
+  FvImageBuffer     Pointer to buffer containing FV data\r
+  FvInfo            Info for the parent FV\r
+  Pe32Section       PE32 section data\r
+  CoreEntryAddress  The extracted core entry physical address\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS             Function Completed successfully.\r
+  EFI_ABORTED             Error encountered.\r
+  EFI_INVALID_PARAMETER   A required parameter was NULL.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT32                      EntryPoint;\r
+  UINT32                      BaseOfCode;\r
+  UINT16                      MachineType;\r
+  EFI_PHYSICAL_ADDRESS        EntryPhysicalAddress;\r
+\r
+  if (CoreEntryAddress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
-  if (MachineType != EFI_IMAGE_MACHINE_ARMT) {\r
-    //\r
-    // If SEC is not ARM we have nothing to do\r
-    //\r
-    return EFI_SUCCESS;\r
+\r
+  Status = GetPe32Info(\r
+    (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),\r
+    &EntryPoint,\r
+    &BaseOfCode,\r
+    &MachineType\r
+    );\r
+  if (EFI_ERROR(Status)) {\r
+    Error(NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the core.");\r
+    return EFI_ABORTED;\r
   }\r
-  \r
+\r
   //\r
   // Physical address is FV base + offset of PE32 + offset of the entry point\r
   //\r
-  SecCorePhysicalAddress = FvInfo->BaseAddress;\r
-  SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
-  SecCorePhysicalAddress += EntryPoint;\r
-  DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%X", SecCorePhysicalAddress); \r
+  EntryPhysicalAddress = FvInfo->BaseAddress;\r
+  EntryPhysicalAddress += (UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN)FvImageBuffer;\r
+  EntryPhysicalAddress += EntryPoint;\r
+\r
+  *CoreEntryAddress = EntryPhysicalAddress;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+UpdateArmResetVectorIfNeeded (\r
+  IN MEMORY_FILE            *FvImage,\r
+  IN FV_INFO                *FvInfo\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  This parses the FV looking for SEC and patches that address into the \r
+  beginning of the FV header.\r
+\r
+  For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.\r
+  For AArch64 the reset vector is at 0x00000000.\r
+\r
+  This would commonly map to the first entry in the ROM. \r
+  ARM32 Exceptions:\r
+  Reset            +0    \r
+  Undefined        +4\r
+  SWI              +8\r
+  Prefetch Abort   +12\r
+  Data Abort       +16\r
+  IRQ              +20\r
+  FIQ              +24\r
+\r
+  We support two schemes on ARM.\r
+  1) Beginning of the FV is the reset vector\r
+  2) Reset vector is data bytes FDF file and that code branches to reset vector \r
+    in the beginning of the FV (fixed size offset).\r
+\r
+  Need to have the jump for the reset vector at location zero.\r
+  We also need to store the address or PEI (if it exists).\r
+  We stub out a return from interrupt in case the debugger \r
+   is using SWI (not done for AArch64, not enough space in struct).\r
+  The optional entry to the common exception handler is \r
+   to support full featured exception handling from ROM and is currently \r
+    not support by this tool.\r
+\r
+Arguments:\r
+  FvImage       Memory file for the FV memory image\r
+  FvInfo        Information read from INF file.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS             Function Completed successfully.\r
+  EFI_ABORTED             Error encountered.\r
+  EFI_INVALID_PARAMETER   A required parameter was NULL.\r
+  EFI_NOT_FOUND           PEI Core file not found.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_FILE_SECTION_POINTER    SecPe32;\r
+  EFI_FILE_SECTION_POINTER    PeiPe32;\r
+  BOOLEAN                     UpdateVectorSec = FALSE;\r
+  BOOLEAN                     UpdateVectorPei = FALSE;\r
+  UINT16                      MachineType = 0;\r
+  EFI_PHYSICAL_ADDRESS        SecCoreEntryAddress = 0;\r
+  UINT16                      PeiMachineType = 0;\r
+  EFI_PHYSICAL_ADDRESS        PeiCoreEntryAddress = 0;\r
 \r
   //\r
-  // Find the PEI Core. It may not exist if SEC loads DXE core directly\r
+  // Verify input parameters\r
   //\r
-  PeiCorePhysicalAddress = 0;\r
-  Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
-  if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {\r
-    //\r
-    // PEI Core found, now find PE32 or TE section\r
-    //\r
-    Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
-    if (Status == EFI_NOT_FOUND) {\r
-      Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
-    }\r
-  \r
-    if (EFI_ERROR (Status)) {\r
-      Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");\r
+  if (FvImage == NULL || FvInfo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Locate an SEC Core instance and if found extract the machine type and entry point address\r
+  //\r
+  Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_SECURITY_CORE, &SecPe32);\r
+  if (!EFI_ERROR(Status)) {\r
+\r
+    Status = GetCoreMachineType(SecPe32, &MachineType);\r
+    if (EFI_ERROR(Status)) {\r
+      Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC Core.");\r
       return EFI_ABORTED;\r
     }\r
-  \r
-    Status = GetPe32Info (\r
-              (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
-              &EntryPoint,\r
-              &BaseOfCode,\r
-              &MachineType\r
-              );\r
-  \r
-    if (EFI_ERROR (Status)) {\r
-      Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");\r
+\r
+    Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, SecPe32, &SecCoreEntryAddress);\r
+    if (EFI_ERROR(Status)) {\r
+      Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core.");\r
       return EFI_ABORTED;\r
     }\r
-    //\r
-    // Physical address is FV base + offset of PE32 + offset of the entry point\r
-    //\r
-    PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
-    PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
-    PeiCorePhysicalAddress += EntryPoint;\r
-    DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%X", PeiCorePhysicalAddress);\r
-  }\r
-  \r
-  \r
-  // B SecEntryPoint - signed_immed_24 part +/-32MB offset\r
-  // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8\r
-  ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2;\r
-  \r
-  if (ResetVector[0] > 0x00FFFFFF) {\r
-    Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");\r
-    return EFI_ABORTED;    \r
+\r
+    VerboseMsg("UpdateArmResetVectorIfNeeded found SEC core entry at 0x%llx", (unsigned long long)SecCoreEntryAddress);\r
+    UpdateVectorSec = TRUE;\r
   }\r
-  \r
-  // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint\r
-  ResetVector[0] |= 0xEA000000;\r
-  \r
-  \r
-  // Address of PEI Core, if we have one\r
-  ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
-  \r
-  // SWI handler movs   pc,lr. Just in case a debugger uses SWI\r
-  ResetVector[2] = 0xE1B0F07E;\r
-  \r
-  // Place holder to support a common interrupt handler from ROM. \r
-  // Currently not suppprted. For this to be used the reset vector would not be in this FV\r
-  // and the exception vectors would be hard coded in the ROM and just through this address \r
-  // to find a common handler in the a module in the FV.\r
-  ResetVector[3] = 0;\r
 \r
   //\r
-  // Copy to the beginning of the FV \r
+  // Locate a PEI Core instance and if found extract the machine type and entry point address\r
   //\r
-  memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
+  Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_PEI_CORE, &PeiPe32);\r
+  if (!EFI_ERROR(Status)) {\r
+\r
+    Status = GetCoreMachineType(PeiPe32, &PeiMachineType);\r
+    if (EFI_ERROR(Status)) {\r
+      Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for PEI Core.");\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, PeiPe32, &PeiCoreEntryAddress);\r
+    if (EFI_ERROR(Status)) {\r
+      Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for PEI Core.");\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    VerboseMsg("UpdateArmResetVectorIfNeeded found PEI core entry at 0x%llx", (unsigned long long)PeiCoreEntryAddress);\r
+\r
+    // if we previously found an SEC Core make sure machine types match\r
+    if (UpdateVectorSec && (MachineType != PeiMachineType)) {\r
+      Error(NULL, 0, 3000, "Invalid", "SEC and PEI machine types do not match, can't update reset vector");\r
+      return EFI_ABORTED;\r
+    }\r
+    else {\r
+      MachineType = PeiMachineType;\r
+    }\r
+\r
+    UpdateVectorPei = TRUE;\r
+  }\r
+\r
+  if (!UpdateVectorSec && !UpdateVectorPei) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\r
+    // ARM: Array of 4 UINT32s:\r
+    // 0 - is branch relative to SEC entry point\r
+    // 1 - PEI Entry Point\r
+    // 2 - movs pc,lr for a SWI handler\r
+    // 3 - Place holder for Common Exception Handler\r
+    UINT32                      ResetVector[4]; \r
+\r
+    memset(ResetVector, 0, sizeof (ResetVector));\r
+\r
+    // if we found an SEC core entry point then generate a branch instruction\r
+    // to it and populate a debugger SWI entry as well\r
+    if (UpdateVectorSec) {\r
+\r
+      VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM SEC vector");\r
+\r
+      // B SecEntryPoint - signed_immed_24 part +/-32MB offset\r
+      // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8\r
+      ResetVector[0] = (INT32)(SecCoreEntryAddress - FvInfo->BaseAddress - 8) >> 2;\r
+\r
+      if (ResetVector[0] > 0x00FFFFFF) {\r
+        Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      // Add opcode for an uncondional branch with no link. i.e.: " B SecEntryPoint"\r
+      ResetVector[0] |= ARMT_UNCONDITIONAL_JUMP_INSTRUCTION;\r
+\r
+      // SWI handler movs   pc,lr. Just in case a debugger uses SWI\r
+      ResetVector[2] = 0xE1B0F07E;\r
+\r
+      // Place holder to support a common interrupt handler from ROM.\r
+      // Currently not suppprted. For this to be used the reset vector would not be in this FV\r
+      // and the exception vectors would be hard coded in the ROM and just through this address\r
+      // to find a common handler in the a module in the FV.\r
+      ResetVector[3] = 0;\r
+    }\r
+\r
+    // if a PEI core entry was found place its address in the vector area\r
+    if (UpdateVectorPei) {\r
+\r
+      VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM PEI address");\r
+\r
+      // Address of PEI Core, if we have one\r
+      ResetVector[1] = (UINT32)PeiCoreEntryAddress;\r
+    }\r
+\r
+    //\r
+    // Copy to the beginning of the FV\r
+    //\r
+    memcpy(FvImage->FileImage, ResetVector, sizeof (ResetVector));\r
 \r
-  DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);\r
+  } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) {\r
+    // AArch64: Used as UINT64 ResetVector[2]\r
+    // 0 - is branch relative to SEC entry point\r
+    // 1 - PEI Entry Point\r
+    UINT64                      ResetVector[2];\r
+\r
+    memset(ResetVector, 0, sizeof (ResetVector));\r
+\r
+    /* NOTE:\r
+    ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector\r
+    array at the moment, for AArch64, does not allow us space for this as the header only\r
+    allows for a fixed amount of bytes at the start. If we are sure that UEFI will live\r
+    within the first 4GB of addressable RAM we could potensioally adopt the same ResetVector\r
+    layout as above. But for the moment we replace the four 32bit vectors with two 64bit\r
+    vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit\r
+    base.\r
+    */\r
+\r
+    // if we found an SEC core entry point then generate a branch instruction to it\r
+    if (UpdateVectorSec) {\r
+\r
+      VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 SEC vector");\r
+\r
+      ResetVector[0] = (UINT64)(SecCoreEntryAddress - FvInfo->BaseAddress) >> 2;\r
+\r
+      // B SecEntryPoint - signed_immed_26 part +/-128MB offset\r
+      if (ResetVector[0] > 0x03FFFFFF) {\r
+        Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");\r
+        return EFI_ABORTED;\r
+      }\r
+      // Add opcode for an uncondional branch with no link. i.e.: " B SecEntryPoint"\r
+      ResetVector[0] |= ARM64_UNCONDITIONAL_JUMP_INSTRUCTION;\r
+    }\r
+\r
+    // if a PEI core entry was found place its address in the vector area\r
+    if (UpdateVectorPei) {\r
+\r
+      VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 PEI address");\r
+\r
+      // Address of PEI Core, if we have one\r
+      ResetVector[1] = (UINT64)PeiCoreEntryAddress;\r
+    }\r
+\r
+    //\r
+    // Copy to the beginning of the FV\r
+    //\r
+    memcpy(FvImage->FileImage, ResetVector, sizeof (ResetVector));\r
+\r
+  } else {\r
+    Error(NULL, 0, 3000, "Invalid", "Unknown machine type");\r
+    return EFI_ABORTED;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -1880,7 +2414,7 @@ Returns:
     // Verify NT header is expected\r
     //\r
     if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
-      Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", ImgHdr->Pe32.Signature);\r
+      Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);\r
       return EFI_UNSUPPORTED;\r
     }\r
     //\r
@@ -1894,8 +2428,8 @@ Returns:
   //\r
   // Verify machine type is supported\r
   //\r
-  if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC && \r
-      *MachineType != EFI_IMAGE_MACHINE_ARMT) {\r
+  if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_IA64) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) && \r
+      (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {\r
     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");\r
     return EFI_UNSUPPORTED;\r
   }\r
@@ -1932,23 +2466,30 @@ Returns:
 \r
 --*/\r
 {\r
-  EFI_STATUS                  Status;\r
-  MEMORY_FILE                 InfMemoryFile;\r
-  MEMORY_FILE                 FvImageMemoryFile;\r
-  UINTN                       Index;\r
-  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
-  EFI_FFS_FILE_HEADER         *VtfFileImage;\r
-  UINT8                       *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
-  UINT8                       *FvImage;\r
-  UINTN                       FvImageSize;\r
-  FILE                        *FvFile;\r
-  CHAR8                       FvMapName [_MAX_PATH];\r
-  FILE                        *FvMapFile;\r
-  EFI_FIRMWARE_VOLUME_EXT_HEADER FvExtHeader;\r
+  EFI_STATUS                      Status;\r
+  MEMORY_FILE                     InfMemoryFile;\r
+  MEMORY_FILE                     FvImageMemoryFile;\r
+  UINTN                           Index;\r
+  EFI_FIRMWARE_VOLUME_HEADER      *FvHeader;\r
+  EFI_FFS_FILE_HEADER             *VtfFileImage;\r
+  UINT8                           *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
+  UINT8                           *FvImage;\r
+  UINTN                           FvImageSize;\r
+  FILE                            *FvFile;\r
+  CHAR8                           *FvMapName;\r
+  FILE                            *FvMapFile;\r
+  EFI_FIRMWARE_VOLUME_EXT_HEADER  *FvExtHeader;\r
+  FILE                            *FvExtHeaderFile;\r
+  UINTN                           FileSize;\r
+  CHAR8                           *FvReportName;\r
+  FILE                            *FvReportFile;\r
 \r
   FvBufferHeader = NULL;\r
   FvFile         = NULL;\r
+  FvMapName      = NULL;\r
   FvMapFile      = NULL;\r
+  FvReportName   = NULL;\r
+  FvReportFile   = NULL;\r
 \r
   if (InfFileImage != NULL) {\r
     //\r
@@ -1990,7 +2531,7 @@ Returns:
   //\r
   if (mFvDataInfo.FvFileSystemGuidSet) {\r
     DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
-                  mFvDataInfo.FvFileSystemGuid.Data1,\r
+                  (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,\r
                   mFvDataInfo.FvFileSystemGuid.Data2,\r
                   mFvDataInfo.FvFileSystemGuid.Data3,\r
                   mFvDataInfo.FvFileSystemGuid.Data4[0],\r
@@ -2002,12 +2543,68 @@ Returns:
                   mFvDataInfo.FvFileSystemGuid.Data4[6],\r
                   mFvDataInfo.FvFileSystemGuid.Data4[7]);\r
   }\r
+\r
+  //\r
+  // Add PI FV extension header\r
+  //\r
+  FvExtHeader = NULL;\r
+  FvExtHeaderFile = NULL;\r
+  if (mFvDataInfo.FvExtHeaderFile[0] != 0) {\r
+    //\r
+    // Open the FV Extension Header file\r
+    //\r
+    FvExtHeaderFile = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");\r
+    if (FvExtHeaderFile == NULL) {\r
+      Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    //\r
+    // Get the file size\r
+    //\r
+    FileSize = _filelength (fileno (FvExtHeaderFile));\r
+\r
+    //\r
+    // Allocate a buffer for the FV Extension Header\r
+    //\r
+    FvExtHeader = malloc(FileSize);\r
+    if (FvExtHeader == NULL) {\r
+      fclose (FvExtHeaderFile);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Read the FV Extension Header\r
+    //\r
+    fread (FvExtHeader, sizeof (UINT8), FileSize, FvExtHeaderFile);\r
+    fclose (FvExtHeaderFile);\r
+\r
+    //\r
+    // See if there is an override for the FV Name GUID\r
+    //\r
+    if (mFvDataInfo.FvNameGuidSet) {\r
+      memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));\r
+    }\r
+    memcpy (&mFvDataInfo.FvNameGuid, &FvExtHeader->FvName, sizeof (EFI_GUID));\r
+    mFvDataInfo.FvNameGuidSet = TRUE;\r
+  } else if (mFvDataInfo.FvNameGuidSet) {\r
+    //\r
+    // Allocate a buffer for the FV Extension Header\r
+    //\r
+    FvExtHeader = malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));\r
+    if (FvExtHeader == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));\r
+    FvExtHeader->ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
+  }\r
+\r
   //\r
   // Debug message Fv Name Guid\r
   //\r
   if (mFvDataInfo.FvNameGuidSet) {\r
       DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
-                  mFvDataInfo.FvNameGuid.Data1,\r
+                  (unsigned) mFvDataInfo.FvNameGuid.Data1,\r
                   mFvDataInfo.FvNameGuid.Data2,\r
                   mFvDataInfo.FvNameGuid.Data3,\r
                   mFvDataInfo.FvNameGuid.Data4[0],\r
@@ -2020,7 +2617,8 @@ Returns:
                   mFvDataInfo.FvNameGuid.Data4[7]);\r
   }\r
 \r
-  if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {\r
+  if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0 ||\r
+    CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem3Guid) == 0) {\r
     mFvDataInfo.IsPiFvImage = TRUE;\r
   }\r
 \r
@@ -2028,22 +2626,67 @@ Returns:
   // FvMap file to log the function address of all modules in one Fvimage\r
   //\r
   if (MapFileName != NULL) {\r
+    if (strlen (MapFileName) > MAX_LONG_FILE_PATH - 1) {\r
+      Error (NULL, 0, 1003, "Invalid option value", "MapFileName %s is too long!", MapFileName);\r
+      Status = EFI_ABORTED;\r
+      goto Finish;\r
+    }\r
+\r
+    FvMapName = malloc (strlen (MapFileName) + 1);\r
+    if (FvMapName == NULL) {\r
+      Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Finish;\r
+    }\r
+\r
     strcpy (FvMapName, MapFileName);\r
   } else {\r
+    if (strlen (FvFileName) + strlen (".map") > MAX_LONG_FILE_PATH - 1) {\r
+      Error (NULL, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName);\r
+      Status = EFI_ABORTED;\r
+      goto Finish;\r
+    }\r
+\r
+    FvMapName = malloc (strlen (FvFileName) + strlen (".map") + 1);\r
+    if (FvMapName == NULL) {\r
+      Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Finish;\r
+    }\r
+\r
     strcpy (FvMapName, FvFileName);\r
     strcat (FvMapName, ".map");\r
   }\r
   VerboseMsg ("FV Map file name is %s", FvMapName);\r
 \r
+  //\r
+  // FvReport file to log the FV information in one Fvimage\r
+  //\r
+  if (strlen (FvFileName) + strlen (".txt") > MAX_LONG_FILE_PATH - 1) {\r
+    Error (NULL, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName);\r
+    Status = EFI_ABORTED;\r
+    goto Finish;\r
+  }\r
+\r
+  FvReportName = malloc (strlen (FvFileName) + strlen (".txt") + 1);\r
+  if (FvReportName == NULL) {\r
+    Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Finish;\r
+  }\r
+\r
+  strcpy (FvReportName, FvFileName);\r
+  strcat (FvReportName, ".txt");\r
+\r
   //\r
   // Calculate the FV size and Update Fv Size based on the actual FFS files.\r
   // And Update mFvDataInfo data.\r
   //\r
   Status = CalculateFvSize (&mFvDataInfo);\r
   if (EFI_ERROR (Status)) {\r
-    return Status;    \r
+    goto Finish;\r
   }\r
-  VerboseMsg ("the generated FV image size is %d bytes", mFvDataInfo.Size);\r
+  VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);\r
   \r
   //\r
   // support fv image and empty fv image\r
@@ -2055,7 +2698,8 @@ Returns:
   //\r
   FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));\r
   if (FvBufferHeader == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Finish;\r
   }\r
   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);\r
 \r
@@ -2120,7 +2764,7 @@ Returns:
   //\r
   // If there is no FFS file, generate one empty FV\r
   //\r
-  if (mFvDataInfo.FvFiles[0][0] == 0) {\r
+  if (mFvDataInfo.FvFiles[0][0] == 0 && !mFvDataInfo.FvNameGuidSet) {\r
     goto WriteFile;\r
   }\r
 \r
@@ -2142,37 +2786,55 @@ Returns:
   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
 \r
   //\r
-  // Open FvMap file\r
+  // Open FvMap file\r
+  //\r
+  FvMapFile = fopen (LongFilePath (FvMapName), "w");\r
+  if (FvMapFile == NULL) {\r
+    Error (NULL, 0, 0001, "Error opening file", FvMapName);\r
+    Status = EFI_ABORTED;\r
+    goto Finish;\r
+  }\r
+  \r
+  //\r
+  // Open FvReport file\r
   //\r
-  FvMapFile = fopen (FvMapName, "w");\r
-  if (FvMapFile == NULL) {\r
-    Error (NULL, 0, 0001, "Error opening file", FvMapName);\r
-    return EFI_ABORTED;\r
+  FvReportFile = fopen (LongFilePath (FvReportName), "w");\r
+  if (FvReportFile == NULL) {\r
+    Error (NULL, 0, 0001, "Error opening file", FvReportName);\r
+    Status = EFI_ABORTED;\r
+    goto Finish;\r
   }\r
-  \r
   //\r
   // record FV size information into FvMap file.\r
   //\r
   if (mFvTotalSize != 0) {\r
     fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);\r
-    fprintf (FvMapFile, " = 0x%x\n", mFvTotalSize);\r
+    fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);\r
   }\r
   if (mFvTakenSize != 0) {\r
     fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);\r
-    fprintf (FvMapFile, " = 0x%x\n", mFvTakenSize);\r
+    fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);\r
   }\r
   if (mFvTotalSize != 0 && mFvTakenSize != 0) {\r
     fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);\r
-    fprintf (FvMapFile, " = 0x%x\n\n", mFvTotalSize - mFvTakenSize);\r
+    fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));\r
   }\r
 \r
   //\r
-  // Set PI FV extension header\r
+  // record FV size information to FvReportFile.\r
   //\r
-  if (mFvDataInfo.FvNameGuidSet) {\r
-    memcpy (&FvExtHeader.FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));\r
-    FvExtHeader.ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
-    AddPadFile (&FvImageMemoryFile, 8, &FvExtHeader);\r
+  fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING, (unsigned) mFvTotalSize);\r
+  fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING, (unsigned) mFvTakenSize);\r
+\r
+  //\r
+  // Add PI FV extension header\r
+  //\r
+  if (FvExtHeader != NULL) {\r
+    //\r
+    // Add FV Extended Header contents to the FV as a PAD file\r
+    //\r
+    AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader, 0);\r
+\r
     //\r
     // Fv Extension header change update Fv Header Check sum\r
     //\r
@@ -2187,7 +2849,7 @@ Returns:
     //\r
     // Add the file\r
     //\r
-    Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile);\r
+    Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile, FvReportFile);\r
 \r
     //\r
     // Exit if error detected while adding the file\r
@@ -2214,11 +2876,13 @@ Returns:
       //\r
       // Update reset vector (SALE_ENTRY for IPF)\r
       // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
-      // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the   \r
-      // reset vector. If the PEI Core is found, the VTF file will probably get  \r
-      // corrupted by updating the entry point.                                  \r
+      // EndAddress of 0xFFFFFFFF (unless the section was rebased).\r
+      // Thus, only this type fv needs to update the  reset vector.\r
+      // If the PEI Core is found, the VTF file will probably get\r
+      // corrupted by updating the entry point.\r
       //\r
-      if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
+      if (mFvDataInfo.ForceRebase == 1 ||\r
+          (mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {\r
         Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);\r
         if (EFI_ERROR(Status)) {                                               \r
           Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
@@ -2246,7 +2910,8 @@ Returns:
   //\r
   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
   //\r
-  if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
+  if (((FvHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) &&\r
+      (((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));\r
     //\r
     // Update Checksum for FvHeader\r
@@ -2255,11 +2920,20 @@ Returns:
     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
   }\r
 \r
+  //\r
+  // If there are large FFS in FV, the file system GUID should set to system 3 GUID.\r
+  //\r
+  if (mIsLargeFfs && CompareGuid (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {\r
+    memcpy (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem3Guid, sizeof (EFI_GUID));\r
+    FvHeader->Checksum      = 0;\r
+    FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
+  }\r
+\r
 WriteFile: \r
   //\r
   // Write fv file\r
   //\r
-  FvFile = fopen (FvFileName, "wb");\r
+  FvFile = fopen (LongFilePath (FvFileName), "wb");\r
   if (FvFile == NULL) {\r
     Error (NULL, 0, 0001, "Error opening file", FvFileName);\r
     Status = EFI_ABORTED;\r
@@ -2276,15 +2950,33 @@ Finish:
   if (FvBufferHeader != NULL) {\r
     free (FvBufferHeader);\r
   }\r
+\r
+  if (FvExtHeader != NULL) {\r
+    free (FvExtHeader);\r
+  }\r
+\r
+  if (FvMapName != NULL) {\r
+    free (FvMapName);\r
+  }\r
+\r
+  if (FvReportName != NULL) {\r
+    free (FvReportName);\r
+  }\r
   \r
   if (FvFile != NULL) {\r
+    fflush (FvFile);\r
     fclose (FvFile);\r
   }\r
   \r
   if (FvMapFile != NULL) {\r
+    fflush (FvMapFile);\r
     fclose (FvMapFile);\r
   }\r
 \r
+  if (FvReportFile != NULL) {\r
+    fflush (FvReportFile);\r
+    fclose (FvReportFile);\r
+  }\r
   return Status;\r
 }\r
 \r
@@ -2379,11 +3071,14 @@ Returns:
   UINTN               Index;\r
   FILE                *fpin;\r
   UINTN               FfsFileSize;\r
+  UINTN               FvExtendHeaderSize;\r
   UINT32              FfsAlignment;\r
+  UINT32              FfsHeaderSize;\r
   EFI_FFS_FILE_HEADER FfsHeader;\r
-  BOOLEAN             VtfFileFlag;\r
+  UINTN               VtfFileSize;\r
   \r
-  VtfFileFlag = FALSE;\r
+  FvExtendHeaderSize = 0;\r
+  VtfFileSize = 0;\r
   fpin  = NULL;\r
   Index = 0;\r
 \r
@@ -2396,7 +3091,7 @@ Returns:
   }\r
   \r
   //\r
-  // Caculate the required sizes for all FFS files.\r
+  // Calculate the required sizes for all FFS files.\r
   //\r
   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
   \r
@@ -2410,7 +3105,22 @@ Returns:
   //\r
   // Calculate PI extension header\r
   //\r
-  if (CompareGuid (&mFvDataInfo.FvNameGuid, &mZeroGuid) != 0) {\r
+  if (mFvDataInfo.FvExtHeaderFile[0] != '\0') {\r
+    fpin = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");\r
+    if (fpin == NULL) {\r
+      Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);\r
+      return EFI_ABORTED;\r
+    }\r
+    FvExtendHeaderSize = _filelength (fileno (fpin));\r
+    fclose (fpin);\r
+    if (sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize >= MAX_FFS_SIZE) {\r
+      CurrentOffset += sizeof (EFI_FFS_FILE_HEADER2) + FvExtendHeaderSize;\r
+      mIsLargeFfs = TRUE;\r
+    } else {\r
+      CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize;\r
+    }\r
+    CurrentOffset = (CurrentOffset + 7) & (~7);\r
+  } else if (mFvDataInfo.FvNameGuidSet) {\r
     CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
     CurrentOffset = (CurrentOffset + 7) & (~7);\r
   }\r
@@ -2423,7 +3133,7 @@ Returns:
     // Open FFS file\r
     //\r
     fpin = NULL;\r
-    fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");\r
+    fpin = fopen (LongFilePath (FvInfoPtr->FvFiles[Index]), "rb");\r
     if (fpin == NULL) {\r
       Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);\r
       return EFI_ABORTED;\r
@@ -2432,6 +3142,12 @@ Returns:
     // Get the file size\r
     //\r
     FfsFileSize = _filelength (fileno (fpin));\r
+    if (FfsFileSize >= MAX_FFS_SIZE) {\r
+      FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
+      mIsLargeFfs = TRUE;\r
+    } else {\r
+      FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
+    }\r
     //\r
     // Read Ffs File header\r
     //\r
@@ -2442,35 +3158,37 @@ Returns:
     fclose (fpin);\r
     \r
     if (FvInfoPtr->IsPiFvImage) {\r
-           //\r
-           // Check whether this ffs file is vtf file\r
-           //\r
-           if (IsVtfFile (&FfsHeader)) {\r
-             if (VtfFileFlag) {\r
-               //\r
-               // One Fv image can't have two vtf files.\r
-               //\r
-               return EFI_ABORTED;\r
-             }\r
-             VtfFileFlag = TRUE;\r
-             //\r
-             // The space between Vft File and the latest file must be able to contain \r
-             // one ffs file header in order to add one pad file.\r
-             //\r
-             CurrentOffset += sizeof (EFI_FFS_FILE_HEADER);\r
-           }\r
-           //\r
-           // Get the alignment of FFS file \r
-           //\r
-           ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
-           FfsAlignment = 1 << FfsAlignment;\r
-           //\r
-           // Add Pad file\r
-           //\r
-           if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {\r
-             CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
-             CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);\r
-           }\r
+        //\r
+        // Check whether this ffs file is vtf file\r
+        //\r
+        if (IsVtfFile (&FfsHeader)) {\r
+          if (VtfFileFlag) {\r
+            //\r
+            // One Fv image can't have two vtf files.\r
+            //\r
+            Error (NULL, 0, 3000,"Invalid", "One Fv image can't have two vtf files.");\r
+            return EFI_ABORTED;\r
+          }\r
+          VtfFileFlag = TRUE;\r
+        VtfFileSize = FfsFileSize;\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Get the alignment of FFS file \r
+      //\r
+      ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
+      FfsAlignment = 1 << FfsAlignment;\r
+      //\r
+      // Add Pad file\r
+      //\r
+      if (((CurrentOffset + FfsHeaderSize) % FfsAlignment) != 0) {\r
+        //\r
+        // Only EFI_FFS_FILE_HEADER is needed for a pad section.\r
+        //\r
+        CurrentOffset = (CurrentOffset + FfsHeaderSize + sizeof(EFI_FFS_FILE_HEADER) + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
+        CurrentOffset -= FfsHeaderSize;\r
+      }\r
          }\r
 \r
     //\r
@@ -2489,8 +3207,8 @@ Returns:
        CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
     }\r
   }\r
-  \r
-  DebugMsg (NULL, 0, 9, "FvImage size", "The caculated fv image size is 0x%x and the current set fv image size is 0x%x", CurrentOffset, FvInfoPtr->Size);\r
+  CurrentOffset += VtfFileSize;\r
+  DebugMsg (NULL, 0, 9, "FvImage size", "The calculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);\r
   \r
   if (FvInfoPtr->Size == 0) { \r
     //\r
@@ -2504,7 +3222,7 @@ Returns:
     //\r
     // Not invalid\r
     //\r
-    Error (NULL, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", CurrentOffset, FvInfoPtr->Size);\r
+    Error (NULL, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
   \r
@@ -2560,6 +3278,80 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+EFI_STATUS\r
+GetChildFvFromFfs (\r
+  IN      FV_INFO               *FvInfo, \r
+  IN      EFI_FFS_FILE_HEADER   *FfsFile,\r
+  IN      UINTN                 XipOffset\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function gets all child FvImages in the input FfsFile, and records\r
+  their base address to the parent image.\r
+\r
+Arguments:\r
+  FvInfo            A pointer to FV_INFO struture.\r
+  FfsFile           A pointer to Ffs file image that may contain FvImage.\r
+  XipOffset         The offset address to the parent FvImage base.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS        Base address of child Fv image is recorded.\r
+--*/\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINTN                               Index;\r
+  EFI_FILE_SECTION_POINTER            SubFvSection;\r
+  EFI_FIRMWARE_VOLUME_HEADER          *SubFvImageHeader;\r
+  EFI_PHYSICAL_ADDRESS                SubFvBaseAddress;\r
+  EFI_FILE_SECTION_POINTER            CorePe32;\r
+  UINT16                              MachineType;\r
+\r
+  for (Index = 1;; Index++) {\r
+    //\r
+    // Find FV section \r
+    //\r
+    Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));\r
+\r
+    //\r
+    // See if there's an SEC core in the child FV\r
+    Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_SECURITY_CORE, &CorePe32);\r
+\r
+    // if we couldn't find the SEC core, look for a PEI core\r
+    if (EFI_ERROR(Status)) {\r
+      Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_PEI_CORE, &CorePe32);\r
+    }\r
+\r
+    if (!EFI_ERROR(Status)) {\r
+      Status = GetCoreMachineType(CorePe32, &MachineType);\r
+      if (EFI_ERROR(Status)) {\r
+        Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC/PEI Core.");\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      // machine type is ARM, set a flag so ARM reset vector procesing occurs\r
+      if ((MachineType == EFI_IMAGE_MACHINE_ARMT) || (MachineType == EFI_IMAGE_MACHINE_AARCH64)) {\r
+        VerboseMsg("Located ARM/AArch64 SEC/PEI core in child FV");\r
+        mArm = TRUE;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Rebase on Flash\r
+    //\r
+    SubFvBaseAddress = FvInfo->BaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;\r
+    mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 EFI_STATUS\r
 FfsRebase ( \r
   IN OUT  FV_INFO               *FvInfo, \r
@@ -2598,25 +3390,24 @@ Returns:
   PE_COFF_LOADER_IMAGE_CONTEXT          OrigImageContext;  \r
   EFI_PHYSICAL_ADDRESS                  XipBase;\r
   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;\r
-  EFI_PHYSICAL_ADDRESS                  *BaseToUpdate;\r
   UINTN                                 Index;\r
   EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
   EFI_FFS_FILE_STATE                    SavedState;\r
   EFI_IMAGE_OPTIONAL_HEADER_UNION       *ImgHdr;\r
   EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
-  UINT8                                 Flags;\r
   UINT8                                 *MemoryImagePointer;\r
   EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
-  CHAR8                                 PeFileName [_MAX_PATH];\r
+  CHAR8                                 PeFileName [MAX_LONG_FILE_PATH];\r
   CHAR8                                 *Cptr;\r
   FILE                                  *PeFile;\r
   UINT8                                 *PeFileBuffer;\r
   UINT32                                PeFileSize;\r
   CHAR8                                 *PdbPointer;\r
+  UINT32                                FfsHeaderSize;\r
+  UINT32                                CurSecHdrSize;\r
 \r
   Index              = 0;  \r
   MemoryImagePointer = NULL;\r
-  BaseToUpdate       = NULL;\r
   TEImageHeader      = NULL;\r
   ImgHdr             = NULL;\r
   SectionHeader      = NULL;\r
@@ -2625,26 +3416,21 @@ Returns:
   PeFileBuffer       = NULL;\r
 \r
   //\r
-  // Check XipAddress, BootAddress and RuntimeAddress\r
+  // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.\r
   //\r
-  Flags = 0;\r
-\r
-  if (FvInfo->BaseAddress != 0) {\r
-    Flags  |= REBASE_XIP_FILE;\r
-    XipBase = FvInfo->BaseAddress + XipOffset;\r
-  }\r
-  if (FvInfo->BootBaseAddress != 0) {\r
-    Flags  |= REBASE_BOOTTIME_FILE;\r
-  }\r
-  if (FvInfo->RuntimeBaseAddress != 0) {\r
-    Flags  |= REBASE_RUNTIME_FILE;\r
+  if ((FvInfo->BaseAddress == 0) && (FvInfo->ForceRebase == -1)) {\r
+    return EFI_SUCCESS;\r
   }\r
-\r
+  \r
   //\r
-  //  Don't Rebase this FFS.\r
-  //  Only copy the original map file into the FvMap file \r
-  //  for the image that is not required to be relocated.\r
+  // If ForceRebase Flag specified to FALSE, will always not take rebase action.\r
   //\r
+  if (FvInfo->ForceRebase == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+\r
+  XipBase = FvInfo->BaseAddress + XipOffset;\r
 \r
   //\r
   // We only process files potentially containing PE32 sections.\r
@@ -2657,9 +3443,21 @@ Returns:
     case EFI_FV_FILETYPE_DRIVER:\r
     case EFI_FV_FILETYPE_DXE_CORE:\r
       break;\r
+    case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:\r
+      //\r
+      // Rebase the inside FvImage.\r
+      //\r
+      GetChildFvFromFfs (FvInfo, FfsFile, XipOffset);\r
+\r
+      //\r
+      // Search PE/TE section in FV sectin.\r
+      //\r
+      break;\r
     default:\r
       return EFI_SUCCESS;\r
   }\r
+\r
+  FfsHeaderSize = GetFfsHeaderLength(FfsFile);\r
   //\r
   // Rebase each PE32 section\r
   //\r
@@ -2677,20 +3475,22 @@ Returns:
     if (EFI_ERROR (Status)) {\r
       break;\r
     }\r
+    CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);\r
 \r
     //\r
     // Initialize context\r
     //\r
     memset (&ImageContext, 0, sizeof (ImageContext));\r
-    ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
+    ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize);\r
     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
     if (EFI_ERROR (Status)) {\r
-      Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, Status);\r
+      Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
       return Status;\r
     }\r
 \r
-    if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {\r
+    if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||\r
+         (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {\r
       mArm = TRUE;\r
     }\r
 \r
@@ -2707,7 +3507,7 @@ Returns:
     //\r
     // Get PeHeader pointer\r
     //\r
-    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset);\r
+    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);\r
 \r
     //\r
     // Calculate the PE32 base address, based on file type\r
@@ -2717,13 +3517,6 @@ Returns:
       case EFI_FV_FILETYPE_PEI_CORE:\r
       case EFI_FV_FILETYPE_PEIM:\r
       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
-        if ((Flags & REBASE_XIP_FILE) == 0) {\r
-          //\r
-          // We aren't relocating XIP code, so skip it.\r
-          //\r
-          goto WritePeMap;\r
-        }\r
-        \r
         //\r
         // Check if section-alignment and file-alignment match or not\r
         //\r
@@ -2755,7 +3548,7 @@ Returns:
             *(Cptr + 3) = 'i';\r
             *(Cptr + 4) = '\0';\r
           }\r
-          PeFile = fopen (PeFileName, "rb");\r
+          PeFile = fopen (LongFilePath (PeFileName), "rb");\r
           if (PeFile == NULL) {\r
             Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
             //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
@@ -2768,6 +3561,7 @@ Returns:
           PeFileSize = _filelength (fileno (PeFile));\r
           PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
           if (PeFileBuffer == NULL) {\r
+            fclose (PeFile);\r
             Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
             return EFI_OUT_OF_RESOURCES;\r
           }\r
@@ -2785,82 +3579,28 @@ Returns:
           ImageContext.Handle = PeFileBuffer;\r
           Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
           if (EFI_ERROR (Status)) {\r
-            Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, Status);\r
+            Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
             return Status;\r
           }\r
           ImageContext.RelocationsStripped = FALSE;\r
         }\r
 \r
-        NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
-        BaseToUpdate = &XipBase;\r
+        NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;\r
         break;\r
 \r
       case EFI_FV_FILETYPE_DRIVER:\r
       case EFI_FV_FILETYPE_DXE_CORE:\r
-        switch (ImgHdr->Pe32.OptionalHeader.Subsystem) {\r
-          case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
-                                               if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {\r
-                               //\r
-                               // Check if section-alignment and file-alignment match or not\r
-                               //\r
-                               if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
-                                 //\r
-                                 // Xip module has the same section alignment and file alignment.\r
-                                 //\r
-                                 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
-                                 return EFI_ABORTED;\r
-                               }\r
-                               NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
-                               BaseToUpdate = &XipBase;                        \r
-                 } else if ((Flags & REBASE_RUNTIME_FILE) == REBASE_RUNTIME_FILE) {\r
-                   //\r
-                   // make sure image base address at the section alignment\r
-                   //\r
-                   FvInfo->RuntimeBaseAddress = (FvInfo->RuntimeBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
-                   FvInfo->RuntimeBaseAddress = FvInfo->RuntimeBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
-                   NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;\r
-                   BaseToUpdate = &(FvInfo->RuntimeBaseAddress);\r
-                 } else {\r
-              //\r
-              // RT drivers aren't supposed to be relocated\r
-              //\r
-              goto WritePeMap;\r
-            }\r
-            break;\r
-\r
-          default:\r
-            //\r
-            // We treat all other subsystems the same as BS_DRIVER\r
-            //\r
-                                               if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {\r
-                               //\r
-                               // Check if section-alignment and file-alignment match or not\r
-                               //\r
-                               if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
-                                 //\r
-                                 // Xip module has the same section alignment and file alignment.\r
-                                 //\r
-                                 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
-                                 return EFI_ABORTED;\r
-                               }\r
-                               NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
-                               BaseToUpdate = &XipBase;                        \r
-                 } else if ((Flags & REBASE_BOOTTIME_FILE) == REBASE_BOOTTIME_FILE) {\r
-                   //\r
-                   // make sure image base address at the Section and Page alignment\r
-                   //\r
-                   FvInfo->BootBaseAddress = (FvInfo->BootBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
-                   FvInfo->BootBaseAddress = FvInfo->BootBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
-                   NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
-                   BaseToUpdate = &(FvInfo->BootBaseAddress);\r
-                 } else {\r
-              //\r
-              // Skip all BS_DRIVER's\r
-              //\r
-              goto WritePeMap;\r
-            }\r
-            break;\r
+        //\r
+        // Check if section-alignment and file-alignment match or not\r
+        //\r
+        if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
+          //\r
+          // Xip module has the same section alignment and file alignment.\r
+          //\r
+          Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
+          return EFI_ABORTED;\r
         }\r
+        NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;\r
         break;\r
 \r
       default:\r
@@ -2871,81 +3611,82 @@ Returns:
     }\r
     \r
     //\r
-    // Relocation exist and rebase\r
+    // Relocation doesn't exist\r
     //\r
-    if (!ImageContext.RelocationsStripped) {  \r
-      //\r
-      // Load and Relocate Image Data\r
-      //\r
-      MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
-      if (MemoryImagePointer == NULL) {\r
-        Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-      memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
-      ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
-      \r
-      Status =  PeCoffLoaderLoadImage (&ImageContext);\r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
-        free ((VOID *) MemoryImagePointer);\r
-        return Status;\r
-      }\r
-           \r
-      ImageContext.DestinationAddress = NewPe32BaseAddress;\r
-      Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
-        free ((VOID *) MemoryImagePointer);\r
-        return Status;\r
-      }\r
+    if (ImageContext.RelocationsStripped) {\r
+      Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
+      continue;\r
+    }\r
 \r
-      //\r
-      // Copy Relocated data to raw image file.\r
-      //\r
-      SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
-                         (UINTN) ImgHdr +\r
-                         sizeof (UINT32) + \r
-                         sizeof (EFI_IMAGE_FILE_HEADER) +  \r
-                         ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
-                         );\r
-      \r
-      for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
-        CopyMem (\r
-          (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData, \r
-          (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
-          SectionHeader->SizeOfRawData\r
-          );\r
-      }\r
-  \r
+    //\r
+    // Relocation exist and rebase\r
+    //\r
+    //\r
+    // Load and Relocate Image Data\r
+    //\r
+    MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+    if (MemoryImagePointer == NULL) {\r
+      Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+    ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));\r
+    \r
+    Status =  PeCoffLoaderLoadImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
       free ((VOID *) MemoryImagePointer);\r
-      MemoryImagePointer = NULL;\r
-      if (PeFileBuffer != NULL) {\r
-        free (PeFileBuffer);\r
-        PeFileBuffer = NULL;\r
-      }\r
+      return Status;\r
+    }\r
+         \r
+    ImageContext.DestinationAddress = NewPe32BaseAddress;\r
+    Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
+      free ((VOID *) MemoryImagePointer);\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Copy Relocated data to raw image file.\r
+    //\r
+    SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
+                       (UINTN) ImgHdr +\r
+                       sizeof (UINT32) + \r
+                       sizeof (EFI_IMAGE_FILE_HEADER) +  \r
+                       ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+                       );\r
+    \r
+    for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+      CopyMem (\r
+        (UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData, \r
+        (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
+        SectionHeader->SizeOfRawData\r
+        );\r
+    }\r
+\r
+    free ((VOID *) MemoryImagePointer);\r
+    MemoryImagePointer = NULL;\r
+    if (PeFileBuffer != NULL) {\r
+      free (PeFileBuffer);\r
+      PeFileBuffer = NULL;\r
     }\r
     \r
     //\r
     // Update Image Base Address\r
     //\r
     if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-      ImgHdr->Pe32.OptionalHeader.ImageBase     = (UINT32) NewPe32BaseAddress;\r
+      ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;\r
     } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
-      ImgHdr->Pe32Plus.OptionalHeader.ImageBase     = NewPe32BaseAddress;\r
+      ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;\r
     } else {\r
       Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
-        (UINT32) ImgHdr->Pe32.OptionalHeader.Magic,\r
+        ImgHdr->Pe32.OptionalHeader.Magic,\r
         FileName\r
         );\r
       return EFI_ABORTED;\r
     }\r
 \r
-    //\r
-    // Update BASE address by add one page size.\r
-    //\r
-    *BaseToUpdate -= EFI_PAGE_SIZE;\r
-\r
     //\r
     // Now update file checksum\r
     //\r
@@ -2953,22 +3694,17 @@ Returns:
       SavedState  = FfsFile->State;\r
       FfsFile->IntegrityCheck.Checksum.File = 0;\r
       FfsFile->State                        = 0;\r
-      if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
-        FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
-                                                  (UINT8 *) FfsFile,\r
-                                                  GetLength (FfsFile->Size)\r
-                                                  );\r
-      } else {\r
-        FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
-      }\r
-\r
+      FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
+                                                (UINT8 *) ((UINT8 *)FfsFile + FfsHeaderSize),\r
+                                                GetFfsFileLength (FfsFile) - FfsHeaderSize\r
+                                                );\r
       FfsFile->State = SavedState;\r
     }\r
 \r
     //\r
     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
     //\r
-WritePeMap:\r
+\r
     //\r
     // Default use FileName as map file path\r
     //\r
@@ -2976,13 +3712,14 @@ WritePeMap:
       PdbPointer = FileName;\r
     }\r
 \r
-    WriteMapFile (FvMapFile, PdbPointer, (EFI_GUID *) FfsFile, NewPe32BaseAddress, &OrigImageContext);\r
+    WriteMapFile (FvMapFile, PdbPointer, FfsFile, NewPe32BaseAddress, &OrigImageContext);\r
   }\r
 \r
   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
-      FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
+      FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&\r
+      FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
       ) {\r
     //\r
     // Only Peim code may have a TE section\r
@@ -3003,12 +3740,14 @@ WritePeMap:
     if (EFI_ERROR (Status)) {\r
       break;\r
     }\r
+\r
+    CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);\r
     \r
     //\r
     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
     // by GenTEImage\r
     //\r
-    TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
+    TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize);\r
 \r
     //\r
     // Initialize context, load image info.\r
@@ -3018,11 +3757,12 @@ WritePeMap:
     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
     if (EFI_ERROR (Status)) {\r
-      Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, Status);\r
+      Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
       return Status;\r
     }\r
 \r
-    if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {\r
+    if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||\r
+         (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {\r
       mArm = TRUE;\r
     }\r
 \r
@@ -3035,13 +3775,6 @@ WritePeMap:
     // Get File PdbPointer\r
     //\r
     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
-    \r
-    if ((Flags & REBASE_XIP_FILE) == 0) {\r
-      //\r
-      // For none XIP PEIM module, their map info also are collected.\r
-      //\r
-      goto WriteTeMap;\r
-    }\r
 \r
     //\r
     // Set new rebased address.\r
@@ -3052,7 +3785,7 @@ WritePeMap:
     //\r
     // if reloc is stripped, try to get the original efi image to get reloc info.\r
     //\r
-    if (ImageContext.RelocationsStripped == TRUE) {\r
+    if (ImageContext.RelocationsStripped) {\r
       //\r
       // Construct the original efi file name \r
       //\r
@@ -3072,7 +3805,7 @@ WritePeMap:
         *(Cptr + 4) = '\0';\r
       }\r
 \r
-      PeFile = fopen (PeFileName, "rb");\r
+      PeFile = fopen (LongFilePath (PeFileName), "rb");\r
       if (PeFile == NULL) {\r
         Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
         //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
@@ -3084,6 +3817,7 @@ WritePeMap:
         PeFileSize = _filelength (fileno (PeFile));\r
         PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
         if (PeFileBuffer == NULL) {\r
+          fclose (PeFile);\r
           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
           return EFI_OUT_OF_RESOURCES;\r
         }\r
@@ -3101,76 +3835,81 @@ WritePeMap:
         ImageContext.Handle = PeFileBuffer;\r
         Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
         if (EFI_ERROR (Status)) {\r
-          Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, Status);\r
+          Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
           return Status;\r
         }\r
         ImageContext.RelocationsStripped = FALSE;\r
       }\r
     }\r
+    //\r
+    // Relocation doesn't exist\r
+    //\r
+    if (ImageContext.RelocationsStripped) {\r
+      Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
+      continue;\r
+    }\r
 \r
     //\r
     // Relocation exist and rebase\r
     //\r
-    if (!ImageContext.RelocationsStripped) {\r
-      //\r
-      // Load and Relocate Image Data\r
-      //\r
-      MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
-      if (MemoryImagePointer == NULL) {\r
-        Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-      memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
-      ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
-  \r
-      Status =  PeCoffLoaderLoadImage (&ImageContext);\r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
-        free ((VOID *) MemoryImagePointer);\r
-        return Status;\r
-      }\r
-      //\r
-      // Reloacate TeImage\r
-      // \r
-      ImageContext.DestinationAddress = NewPe32BaseAddress;\r
-      Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
-      if (EFI_ERROR (Status)) {\r
-        Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
-        free ((VOID *) MemoryImagePointer);\r
-        return Status;\r
-      }\r
-      \r
-      //\r
-      // Copy the relocated image into raw image file.\r
-      //\r
-      SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
-      for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {\r
-        if (!ImageContext.IsTeImage) {\r
-          CopyMem (\r
-            (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
-            (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
-            SectionHeader->SizeOfRawData\r
-            );\r
-        } else {\r
-          CopyMem (\r
-            (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
-            (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), \r
-            SectionHeader->SizeOfRawData\r
-            );\r
-        }\r
-      }\r
-      \r
-      //\r
-      // Free the allocated memory resource\r
-      //\r
+    //\r
+    // Load and Relocate Image Data\r
+    //\r
+    MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+    if (MemoryImagePointer == NULL) {\r
+      Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+    ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));\r
+\r
+    Status =  PeCoffLoaderLoadImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
+      free ((VOID *) MemoryImagePointer);\r
+      return Status;\r
+    }\r
+    //\r
+    // Reloacate TeImage\r
+    // \r
+    ImageContext.DestinationAddress = NewPe32BaseAddress;\r
+    Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
       free ((VOID *) MemoryImagePointer);\r
-      MemoryImagePointer = NULL;\r
-      if (PeFileBuffer != NULL) {\r
-        free (PeFileBuffer);\r
-        PeFileBuffer = NULL;\r
+      return Status;\r
+    }\r
+    \r
+    //\r
+    // Copy the relocated image into raw image file.\r
+    //\r
+    SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
+    for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {\r
+      if (!ImageContext.IsTeImage) {\r
+        CopyMem (\r
+          (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
+          (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
+          SectionHeader->SizeOfRawData\r
+          );\r
+      } else {\r
+        CopyMem (\r
+          (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
+          (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), \r
+          SectionHeader->SizeOfRawData\r
+          );\r
       }\r
     }\r
     \r
+    //\r
+    // Free the allocated memory resource\r
+    //\r
+    free ((VOID *) MemoryImagePointer);\r
+    MemoryImagePointer = NULL;\r
+    if (PeFileBuffer != NULL) {\r
+      free (PeFileBuffer);\r
+      PeFileBuffer = NULL;\r
+    }\r
+    \r
     //\r
     // Update Image Base Address\r
     //\r
@@ -3183,21 +3922,16 @@ WritePeMap:
       SavedState  = FfsFile->State;\r
       FfsFile->IntegrityCheck.Checksum.File = 0;\r
       FfsFile->State                        = 0;\r
-      if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
-        FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
-                                                  (UINT8 *) FfsFile,\r
-                                                  GetLength (FfsFile->Size)\r
-                                                  );\r
-      } else {\r
-        FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
-      }\r
-\r
+      FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
+                                                (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),\r
+                                                GetFfsFileLength (FfsFile) - FfsHeaderSize\r
+                                                );\r
       FfsFile->State = SavedState;\r
     }\r
     //\r
     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
     //\r
-WriteTeMap:\r
+\r
     //\r
     // Default use FileName as map file path\r
     //\r
@@ -3208,7 +3942,7 @@ WriteTeMap:
     WriteMapFile (\r
       FvMapFile, \r
       PdbPointer, \r
-      (EFI_GUID *) FfsFile,\r
+      FfsFile,\r
       NewPe32BaseAddress, \r
       &OrigImageContext\r
       );\r
@@ -3260,12 +3994,12 @@ Returns:
     //\r
     // Get Pad file size.\r
     //\r
-    FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;\r
+    FileLength = GetFfsFileLength(PadFile);\r
     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); \r
     //\r
     // FixPoint must be align on 0x1000 relative to FvImage Header\r
     //\r
-    FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);\r
+    FixPoint = (UINT8*) PadFile + GetFfsHeaderLength(PadFile);\r
     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);\r
     //\r
     // FixPoint be larger at the last place of one fv image.\r
@@ -3275,7 +4009,7 @@ Returns:
     }\r
     FixPoint -= 0x1000;\r
     \r
-    if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {\r
+    if ((UINTN) FixPoint < ((UINTN) PadFile + GetFfsHeaderLength(PadFile))) {\r
       //\r
       // No alignment FixPoint in this Pad File.\r
       //\r
@@ -3317,7 +4051,7 @@ Returns:
   EFI_NOT_FOUND     A required string was not found in the INF file.\r
 --*/\r
 {\r
-  CHAR8       Value[_MAX_PATH];\r
+  CHAR8       Value[MAX_LONG_FILE_PATH];\r
   UINT64      Value64;\r
   UINTN       Index, Number;\r
   EFI_STATUS  Status;\r
@@ -3365,8 +4099,14 @@ Returns:
   if (Status == EFI_SUCCESS) {\r
     if (strstr (Value, "PopulateSystemTable") != NULL) {\r
       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;\r
+      if (strstr (Value, "InitiateReset") != NULL) {\r
+        CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;\r
+      }\r
     } else if (strstr (Value, "PersistAcrossReset") != NULL) {\r
       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET; \r
+      if (strstr (Value, "InitiateReset") != NULL) {\r
+        CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;\r
+      }\r
     } else {\r
       Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);\r
       return EFI_ABORTED;\r
@@ -3374,6 +4114,19 @@ Returns:
     DebugMsg (NULL, 0, 9, "Capsule Flag", Value);\r
   }\r
 \r
+  Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_OEM_CAPSULE_FLAGS_STRING, 0, Value);\r
+  if (Status == EFI_SUCCESS) {\r
+    Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
+    if (EFI_ERROR (Status) || Value64 > 0xffff) {\r
+      Error (NULL, 0, 2000, "Invalid parameter",\r
+        "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",\r
+        EFI_OEM_CAPSULE_FLAGS_STRING);\r
+      return EFI_ABORTED;\r
+    }\r
+    CapInfo->Flags |= Value64;\r
+    DebugMsg (NULL, 0, 9, "Capsule Extend Flag", Value);\r
+  }\r
+\r
   //\r
   // Read Capsule File name\r
   //\r
@@ -3403,7 +4156,7 @@ Returns:
       // Add the file\r
       //\r
       strcpy (CapInfo->CapFiles[Index], Value);\r
-      DebugMsg (NULL, 0, 9, "Capsule component file", "the %dth file name is %s", Index, CapInfo->CapFiles[Index]); \r
+      DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]); \r
     } else {\r
       break;\r
     }\r
@@ -3504,7 +4257,7 @@ Returns:
   FileSize = 0;\r
   CapSize  = mCapDataInfo.HeaderSize;\r
   while (mCapDataInfo.CapFiles [Index][0] != '\0') {\r
-    fpin = fopen (mCapDataInfo.CapFiles[Index], "rb");\r
+    fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");\r
     if (fpin == NULL) {\r
       Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);\r
       return EFI_ABORTED;\r
@@ -3542,7 +4295,7 @@ Returns:
   FileSize = 0;\r
   CapSize  = CapsuleHeader->HeaderSize;\r
   while (mCapDataInfo.CapFiles [Index][0] != '\0') {\r
-    fpin = fopen (mCapDataInfo.CapFiles[Index], "rb");\r
+    fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");\r
     if (fpin == NULL) {\r
       Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);\r
       free (CapBuffer);\r
@@ -3558,7 +4311,7 @@ Returns:
   //\r
   // write capsule data into the output file\r
   //\r
-  fpout = fopen (CapFileName, "wb");\r
+  fpout = fopen (LongFilePath (CapFileName), "wb");\r
   if (fpout == NULL) {\r
     Error (NULL, 0, 0001, "Error opening file", CapFileName);\r
     free (CapBuffer);\r
@@ -3567,8 +4320,9 @@ Returns:
 \r
   fwrite (CapBuffer, 1, CapSize, fpout);\r
   fclose (fpout);\r
+  free (CapBuffer);\r
   \r
-  VerboseMsg ("The size of the generated capsule image is %d bytes", CapSize);\r
+  VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize);\r
 \r
   return EFI_SUCCESS;\r
 }\r