]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFv/GenFvInternalLib.c
BaseTools/GenFv: Account for rebase of FV section containing VTF file
[mirror_edk2.git] / BaseTools / Source / C / GenFv / GenFvInternalLib.c
index 005098508b26023c14e0fa5b9dba306d3a9321c6..123e3550dd97d027685ba33d3d6a2649b98509a4 100644 (file)
@@ -3,6 +3,7 @@ This file contains the internal functions required to generate a Firmware Volume
 \r
 Copyright (c) 2004 - 2014, 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
@@ -31,18 +32,24 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #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
 \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
@@ -934,6 +941,153 @@ 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;\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
@@ -1140,11 +1294,14 @@ Returns:
   //\r
   // Add pad file if necessary\r
   //\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
+  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
@@ -1650,6 +1807,244 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+EFI_STATUS\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
+\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
+\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           Core file not found.\r
+\r
+--*/\r
+{\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, saving previous values\r
+  //\r
+  OrigFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NULL;\r
+  GetFvHeader (&OrigFvHeader, &OrigFvLength);\r
+  InitializeFvLib(FvImageBuffer, (UINT32)FvSize);\r
+\r
+  //\r
+  // First see if we can obtain the file directly in outer FV\r
+  //\r
+  Status = GetFileByType(FileType, 1, &CoreFfsFile);\r
+  if (!EFI_ERROR(Status) && (CoreFfsFile != NULL) ) {\r
+\r
+    //\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
+    // Core PE/TE section, found, return\r
+    //\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
+      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
+    } // end encapsulated fv image section loop\r
+  } // end fv image file loop\r
+\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
+  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
+  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
+  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
+  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
+  // Physical address is FV base + offset of PE32 + offset of the entry point\r
+  //\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
@@ -1701,23 +2096,15 @@ Returns:
 \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]; // ARM32:\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
-                                            // AArch64: Used as UINT64 ResetVector[2]\r
-                                            // 0 - is branch relative to SEC entry point\r
-                                            // 1 - PEI Entry Point\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
   // Verify input parameters\r
@@ -1725,180 +2112,126 @@ Returns:
   if (FvImage == NULL || FvInfo == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  //\r
-  // Initialize FV library\r
-  //\r
-  InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
 \r
   //\r
-  // Find the Sec Core\r
+  // Locate an SEC Core instance and if found extract the machine type and entry point address\r
   //\r
-  Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
-  if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
-    //\r
-    // Maybe hardware does SEC job and we only have PEI Core?\r
-    //\r
-\r
-    //\r
-    // Find the PEI Core. It may not exist if SEC loads DXE core directly\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 + GetSectionHeaderLength(Pe32Section.CommonHeader)),\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
-      }\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 + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN) FvImage->FileImage;\r
-      PeiCorePhysicalAddress += EntryPoint;\r
-      DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
-\r
-      if (MachineType == EFI_IMAGE_MACHINE_ARMT || MachineType == EFI_IMAGE_MACHINE_AARCH64) {\r
-        memset (ResetVector, 0, sizeof (ResetVector));\r
-        // Address of PEI Core, if we have one\r
-        ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
-      }\r
-      \r
-      //\r
-      // Copy to the beginning of the FV \r
-      //\r
-      memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\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
-    return EFI_SUCCESS;\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
+    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
-  if (EFI_ERROR (Status)) {\r
-    Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
-    return EFI_ABORTED;\r
+    VerboseMsg("UpdateArmResetVectorIfNeeded found SEC core entry at 0x%llx", (unsigned long long)SecCoreEntryAddress);\r
+    UpdateVectorSec = TRUE;\r
   }\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 SEC core.");\r
-    return EFI_ABORTED;\r
-  }\r
-  \r
-  if ((MachineType != EFI_IMAGE_MACHINE_ARMT) && (MachineType != EFI_IMAGE_MACHINE_AARCH64)) {\r
-    //\r
-    // If SEC is not ARM we have nothing to do\r
-    //\r
-    return EFI_SUCCESS;\r
-  }\r
-  \r
   //\r
-  // Physical address is FV base + offset of PE32 + offset of the entry point\r
+  // Locate a PEI Core instance and if found extract the machine type and entry point address\r
   //\r
-  SecCorePhysicalAddress = FvInfo->BaseAddress;\r
-  SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN) FvImage->FileImage;\r
-  SecCorePhysicalAddress += EntryPoint;\r
-  DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); \r
+  Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_PEI_CORE, &PeiPe32);\r
+  if (!EFI_ERROR(Status)) {\r
 \r
-  //\r
-  // Find the PEI Core. It may not exist if SEC loads DXE core directly\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
+    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
-    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
+\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
-    Status = GetPe32Info (\r
-              (VOID *) ((UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),\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
+    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
-    //\r
-    // Physical address is FV base + offset of PE32 + offset of the entry point\r
-    //\r
-    PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
-    PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN) FvImage->FileImage;\r
-    PeiCorePhysicalAddress += EntryPoint;\r
-    DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
+    else {\r
+      MachineType = PeiMachineType;\r
+    }\r
+\r
+    UpdateVectorPei = TRUE;\r
   }\r
-  \r
+\r
+  if (!UpdateVectorSec && !UpdateVectorPei) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\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
+    // 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
-    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
+    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
-    // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint\r
-    ResetVector[0] |= 0xEB000000;\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
+    // 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
   } 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
+    /* 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
@@ -1906,33 +2239,43 @@ Returns:
     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
 \r
-    ((UINT64*)ResetVector)[0] = (UINT64)(SecCorePhysicalAddress - FvInfo->BaseAddress) >> 2;\r
+    // if we found an SEC core entry point then generate a branch instruction to it\r
+    if (UpdateVectorSec) {\r
 \r
-    // B SecEntryPoint - signed_immed_26 part +/-128MB offset\r
-    if ( ((UINT64*)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
+      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
-    // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint\r
-    ((UINT64*)ResetVector)[0] |= 0x14000000;\r
 \r
-    // Address of PEI Core, if we have one\r
-    ((UINT64*)ResetVector)[1] = (UINT64)PeiCorePhysicalAddress;\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 ARM machine type");\r
+    Error(NULL, 0, 3000, "Invalid", "Unknown machine type");\r
     return EFI_ABORTED;\r
   }\r
 \r
-  //\r
-  // Copy to the beginning of the FV \r
-  //\r
-  memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
-\r
-  DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);\r
-\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -2427,11 +2770,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).
+      // Thus, only this type fv needs to update the  reset vector.
+      // If the PEI Core is found, the VTF file will probably get
+      // corrupted by updating the entry point.
       //\r
-      if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
+      if (mFvDataInfo.ForceRebase == 1 ||
+          (mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {
         Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);\r
         if (EFI_ERROR(Status)) {                                               \r
           Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
@@ -2634,7 +2979,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
@@ -2701,17 +3046,18 @@ 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
+        // 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
@@ -2750,7 +3096,7 @@ Returns:
     }\r
   }\r
   CurrentOffset += VtfFileSize;\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", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);\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
@@ -2848,6 +3194,8 @@ Returns:
   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
@@ -2858,6 +3206,30 @@ Returns:
       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