]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/CCode/Source/PeiRebase/PeiRebaseExe.c
More moves for Tool Packages
[mirror_edk2.git] / Tools / CCode / Source / PeiRebase / PeiRebaseExe.c
diff --git a/Tools/CCode/Source/PeiRebase/PeiRebaseExe.c b/Tools/CCode/Source/PeiRebase/PeiRebaseExe.c
new file mode 100644 (file)
index 0000000..27c646e
--- /dev/null
@@ -0,0 +1,1059 @@
+/*++\r
+\r
+Copyright (c)  1999-2006 Intel Corporation. All rights reserved\r
+This program and the accompanying materials are licensed and made available \r
+under the terms and conditions of the BSD License which accompanies this \r
+distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+  PeiRebaseExe.c\r
+\r
+Abstract:\r
+\r
+  This contains all code necessary to build the PeiRebase.exe utility.\r
+  This utility relies heavily on the PeiRebase DLL.  Definitions for both\r
+  can be found in the PEI Rebase Utility Specification, review draft.\r
+\r
+--*/\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include <Common/UefiBaseTypes.h>\r
+#include <Common/FirmwareVolumeImageFormat.h>\r
+#include <Common/FirmwareFileSystem.h>\r
+#include <Library/PeCoffLib.h>\r
+\r
+#include "CommonLib.h"\r
+#include "ParseInf.h"\r
+#include "FvLib.h"\r
+#include "EfiUtilityMsgs.h"\r
+#include "PeiRebaseExe.h"\r
+\r
+EFI_STATUS\r
+ReadHeader (\r
+  IN FILE       *InputFile,\r
+  OUT UINT32    *FvSize,\r
+  OUT BOOLEAN   *ErasePolarity\r
+  );\r
+\r
+int\r
+main (\r
+  int  argc,\r
+  char **argv\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This utility relocates PEI XIP PE32s in a FV.\r
+\r
+Arguments:\r
+\r
+  argc          - Number of command line arguments\r
+  argv[]:\r
+  BaseAddress     The base address to use for rebasing the FV.  The correct \r
+                  format is a hex number preceded by 0x.\r
+  InputFileName   The name of the input FV file.\r
+  OutputFileName  The name of the output FV file.\r
+  MapFileName     The name of the map file of relocation info.\r
+\r
+  Arguments come in pair in any order.\r
+    -I InputFileName \r
+    -O OutputFileName\r
+    -B BaseAddress \r
+    -M MapFileName \r
+\r
+Returns:\r
+\r
+  0   No error conditions detected.\r
+  1   One or more of the input parameters is invalid.\r
+  2   A resource required by the utility was unavailable.  \r
+      Most commonly this will be memory allocation or file creation.\r
+  3   PeiRebase.dll could not be loaded.\r
+  4   Error executing the PEI rebase.\r
+\r
+--*/\r
+{\r
+  UINT8                       Index;\r
+  CHAR8                       InputFileName[_MAX_PATH];\r
+  CHAR8                       OutputFileName[_MAX_PATH];\r
+  CHAR8                       MapFileName[_MAX_PATH];\r
+  EFI_PHYSICAL_ADDRESS        BaseAddress;\r
+  BOOLEAN                     BaseAddressSet;\r
+  EFI_STATUS                  Status;\r
+  FILE                        *InputFile;\r
+  FILE                        *OutputFile;\r
+  FILE                        *MapFile;\r
+  UINT64                      FvOffset;\r
+  UINT32                      FileCount;\r
+  int                         BytesRead;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FvImage;\r
+  UINT32                      FvSize;\r
+  EFI_FFS_FILE_HEADER         *CurrentFile;\r
+  BOOLEAN                     ErasePolarity;\r
+  EFI_PHYSICAL_ADDRESS        CurrentFileBaseAddress;\r
+\r
+  ErasePolarity = FALSE;\r
+  //\r
+  // Set utility name for error/warning reporting purposes.\r
+  //\r
+  SetUtilityName (UTILITY_NAME);\r
+  //\r
+  // Verify the correct number of arguments\r
+  //\r
+  if (argc != MAX_ARGS) {\r
+    PrintUsage ();\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  //\r
+  // Initialize variables\r
+  //\r
+  InputFileName[0]  = 0;\r
+  OutputFileName[0] = 0;\r
+  MapFileName[0]    = 0;\r
+  BaseAddress       = 0;\r
+  BaseAddressSet    = FALSE;\r
+  FvOffset          = 0;\r
+  FileCount         = 0;\r
+  ErasePolarity     = FALSE;\r
+  InputFile         = NULL;\r
+  OutputFile        = NULL;\r
+  MapFile           = NULL;\r
+  FvImage           = NULL;\r
+\r
+  //\r
+  // Parse the command line arguments\r
+  //\r
+  for (Index = 1; Index < MAX_ARGS; Index += 2) {\r
+    //\r
+    // Make sure argument pair begin with - or /\r
+    //\r
+    if (argv[Index][0] != '-' && argv[Index][0] != '/') {\r
+      PrintUsage ();\r
+      Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
+      return STATUS_ERROR;\r
+    }\r
+    //\r
+    // Make sure argument specifier is only one letter\r
+    //\r
+    if (argv[Index][2] != 0) {\r
+      PrintUsage ();\r
+      Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
+      return STATUS_ERROR;\r
+    }    \r
+    //\r
+    // Determine argument to read\r
+    //\r
+    switch (argv[Index][1]) {\r
+    case 'I':\r
+    case 'i':\r
+      if (strlen (InputFileName) == 0) {\r
+        strcpy (InputFileName, argv[Index + 1]);\r
+      } else {\r
+        PrintUsage ();\r
+        Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified");\r
+        return STATUS_ERROR;\r
+      }\r
+      break;\r
+\r
+    case 'O':\r
+    case 'o':\r
+      if (strlen (OutputFileName) == 0) {\r
+        strcpy (OutputFileName, argv[Index + 1]);\r
+      } else {\r
+        PrintUsage ();\r
+        Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified");\r
+        return STATUS_ERROR;\r
+      }\r
+      break;\r
+\r
+    case 'B':\r
+    case 'b':\r
+      if (!BaseAddressSet) {\r
+        Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BaseAddress);\r
+        if (EFI_ERROR (Status)) {\r
+          PrintUsage ();\r
+          Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for the base address");\r
+          return STATUS_ERROR;\r
+        }\r
+\r
+        BaseAddressSet = TRUE;\r
+      } else {\r
+        PrintUsage ();\r
+        Error (NULL, 0, 0, argv[Index + 1], "-b BaseAddress may only be specified once");\r
+        return STATUS_ERROR;\r
+      }\r
+      break;\r
+\r
+    case 'M':\r
+    case 'm':\r
+      if (strlen (MapFileName) == 0) {\r
+        strcpy (MapFileName, argv[Index + 1]);\r
+      } else {\r
+        PrintUsage ();\r
+        Error (NULL, 0, 0, argv[Index + 1], "only one -m MapFileName may be specified");\r
+        return STATUS_ERROR;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      PrintUsage ();\r
+      Error (NULL, 0, 0, argv[Index], "unrecognized argument");\r
+      return STATUS_ERROR;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create the Map file if we need it\r
+  //\r
+  if (strlen (MapFileName) != 0) {\r
+    MapFile = fopen (MapFileName, "w");\r
+    if (MapFile == NULL) {\r
+      Error (NULL, 0, 0, MapFileName, "failed to open map file");\r
+      goto Finish;\r
+    }\r
+  } \r
+\r
+  //\r
+  // Open the file containing the FV\r
+  //\r
+  InputFile = fopen (InputFileName, "rb");\r
+  if (InputFile == NULL) {\r
+    Error (NULL, 0, 0, InputFileName, "could not open input file for reading");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Determine size of FV\r
+  //\r
+  Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);\r
+  if (EFI_ERROR (Status)) {\r
+    Error (NULL, 0, 0, "could not parse the FV header", NULL);\r
+    goto Finish;\r
+  }\r
+  //\r
+  // Allocate a buffer for the FV image\r
+  //\r
+  FvImage = malloc (FvSize);\r
+  if (FvImage == NULL) {\r
+    Error (NULL, 0, 0, "application error", "memory allocation failed");\r
+    goto Finish;\r
+  }\r
+  //\r
+  // Read the entire FV to the buffer\r
+  //\r
+  BytesRead = fread (FvImage, 1, FvSize, InputFile);\r
+  fclose (InputFile);\r
+  InputFile = NULL;\r
+  if ((unsigned int) BytesRead != FvSize) {\r
+    Error (NULL, 0, 0, InputFileName, "failed to read from file");\r
+    goto Finish;\r
+  }\r
+  //\r
+  // Prepare to walk the FV image\r
+  //\r
+  InitializeFvLib (FvImage, FvSize);\r
+  //\r
+  // Get the first file\r
+  //\r
+  Status = GetNextFile (NULL, &CurrentFile);\r
+  if (EFI_ERROR (Status)) {\r
+    Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL);\r
+    goto Finish;\r
+  }\r
+  //\r
+  // Check if each file should be rebased\r
+  //\r
+  while (CurrentFile != NULL) {\r
+    //\r
+    // Rebase this file\r
+    //\r
+    CurrentFileBaseAddress  = BaseAddress + ((UINTN) CurrentFile - (UINTN) FvImage);\r
+    Status                  = FfsRebase (CurrentFile, CurrentFileBaseAddress, MapFile);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      switch (Status) {\r
+\r
+      case EFI_INVALID_PARAMETER:\r
+        Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL);\r
+        break;\r
+\r
+      case EFI_ABORTED:\r
+        Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL);\r
+        break;\r
+\r
+      case EFI_OUT_OF_RESOURCES:\r
+        Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL);\r
+        break;\r
+\r
+      case EFI_NOT_FOUND:\r
+        Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL);\r
+        break;\r
+\r
+      default:\r
+        Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status);\r
+        break;\r
+      }\r
+\r
+      goto Finish;\r
+    }\r
+\r
+    //\r
+    // Get the next file\r
+    //\r
+    Status = GetNextFile (CurrentFile, &CurrentFile);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL);\r
+      goto Finish;\r
+    }\r
+  }\r
+  //\r
+  // Open the output file\r
+  //\r
+  OutputFile = fopen (OutputFileName, "wb");\r
+  if (OutputFile == NULL) {\r
+    Error (NULL, 0, 0, OutputFileName, "failed to open output file");\r
+    goto Finish;\r
+  }\r
+\r
+  if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) {\r
+    Error (NULL, 0, 0, "failed to write to output file", 0);\r
+    goto Finish;\r
+  }\r
+\r
+Finish:\r
+  if (InputFile != NULL) {\r
+    fclose (InputFile);\r
+  }\r
+  //\r
+  // If we created an output file, and there was an error, remove it so\r
+  // subsequent builds will rebuild it.\r
+  //\r
+  if (OutputFile != NULL) {\r
+    if (GetUtilityStatus () == STATUS_ERROR) {\r
+      remove (OutputFileName);\r
+    }\r
+\r
+    fclose (OutputFile);\r
+  }\r
+\r
+  if (MapFile != NULL) {\r
+    fclose (MapFile);\r
+  }\r
+\r
+  if (FvImage != NULL) {\r
+    free (FvImage);\r
+  }\r
+\r
+  return GetUtilityStatus ();\r
+}\r
+\r
+EFI_STATUS\r
+ReadHeader (\r
+  IN FILE       *InputFile,\r
+  OUT UINT32    *FvSize,\r
+  OUT BOOLEAN   *ErasePolarity\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function determines the size of the FV and the erase polarity.  The \r
+  erase polarity is the FALSE value for file state.\r
+\r
+Arguments:\r
+\r
+  InputFile       The file that contains the FV image.\r
+  FvSize          The size of the FV.\r
+  ErasePolarity   The FV erase polarity.\r
+    \r
+Returns:\r
\r
+  EFI_SUCCESS             Function completed successfully.\r
+  EFI_INVALID_PARAMETER   A required parameter was NULL or is out of range.\r
+  EFI_ABORTED             The function encountered an error.\r
+\r
+--*/\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER  VolumeHeader;\r
+  EFI_FV_BLOCK_MAP_ENTRY      BlockMap;\r
+  UINTN                       Signature[2];\r
+  UINTN                       BytesRead;\r
+  UINT32                      Size;\r
+\r
+  BytesRead = 0;\r
+  Size      = 0;\r
+  //\r
+  // Check input parameters\r
+  //\r
+  if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) {\r
+    Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter");\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Read the header\r
+  //\r
+  fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
+  BytesRead     = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
+  Signature[0]  = VolumeHeader.Signature;\r
+  Signature[1]  = 0;\r
+\r
+  //\r
+  // Get erase polarity\r
+  //\r
+  if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) {\r
+    *ErasePolarity = TRUE;\r
+  }\r
+\r
+  do {\r
+    fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
+    BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
+\r
+    if (BlockMap.NumBlocks != 0) {\r
+      Size += BlockMap.NumBlocks * BlockMap.BlockLength;\r
+    }\r
+\r
+  } while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0));\r
+\r
+  if (VolumeHeader.FvLength != Size) {\r
+    Error (NULL, 0, 0, "volume size not consistant with block maps", NULL);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  *FvSize = Size;\r
+\r
+  rewind (InputFile);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+PrintUtilityInfo (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Displays the standard utility information to SDTOUT\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  printf (\r
+    "%s, PEI Rebase Utility. Version %i.%i, %s.\n\n",\r
+    UTILITY_NAME,\r
+    UTILITY_MAJOR_VERSION,\r
+    UTILITY_MINOR_VERSION,\r
+    UTILITY_DATE\r
+    );\r
+}\r
+\r
+VOID\r
+PrintUsage (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Displays the utility usage syntax to STDOUT\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  printf (\r
+    "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-M MapFile]\n",\r
+    UTILITY_NAME\r
+    );\r
+  printf ("  Where:\n");\r
+  printf ("    InputFileName is the name of the EFI FV file to rebase.\n");\r
+  printf ("    OutputFileName is the desired output file name.\n");\r
+  printf ("    BaseAddress is the FV base address to rebase agains.\n");\r
+  printf ("    MapFileName is an optional map file of the relocations\n");\r
+  printf ("  Argument pair may be in any order.\n\n");\r
+}\r
+\r
+EFI_STATUS\r
+FfsRebase (\r
+  IN OUT EFI_FFS_FILE_HEADER    *FfsFile,\r
+  IN EFI_PHYSICAL_ADDRESS       BaseAddress,\r
+  IN FILE                       *MapFile      OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function determines if a file is XIP and should be rebased.  It will \r
+  rebase any PE32 sections found in the file using the base address.\r
+  \r
+Arguments:\r
+\r
+  FfsFile           A pointer to Ffs file image.\r
+  BaseAddress       The base address to use for rebasing the file image.\r
+  MapFile           Optional file to dump relocation information into\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS             The image was properly rebased.\r
+  EFI_INVALID_PARAMETER   An input parameter is invalid.\r
+  EFI_ABORTED             An error occurred while rebasing the input file image.\r
+  EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
+  EFI_NOT_FOUND           No compressed sections could be found.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                            Status;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
+  UINTN                                 MemoryImagePointer;\r
+  UINTN                                 MemoryImagePointerAligned;\r
+  EFI_PHYSICAL_ADDRESS                  ImageAddress;\r
+  UINT64                                ImageSize;\r
+  EFI_PHYSICAL_ADDRESS                  EntryPoint;\r
+  UINT32                                Pe32ImageSize;\r
+  UINT32                                NewPe32BaseAddress;\r
+  UINTN                                 Index;\r
+  EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
+  EFI_FFS_FILE_STATE                    SavedState;\r
+  EFI_IMAGE_NT_HEADERS                  *PeHdr;\r
+  UINT32                                *PeHdrSizeOfImage;\r
+  UINT32                                *PeHdrChecksum;\r
+  UINT32                                FoundCount;\r
+  EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
+  UINT8                                 *TEBuffer;\r
+  EFI_IMAGE_DOS_HEADER                  *DosHeader;\r
+  UINT8                                 FileGuidString[80];\r
+  UINT32                                TailSize;\r
+  EFI_FFS_FILE_TAIL                     TailValue;\r
+\r
+  //\r
+  // Verify input parameters\r
+  //\r
+  if (FfsFile == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Convert the GUID to a string so we can at least report which file\r
+  // if we find an error.\r
+  //\r
+  PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE);\r
+  if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+    TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
+  } else {\r
+    TailSize = 0;\r
+  }\r
+  \r
+  //\r
+  // Do some cursory checks on the FFS file contents\r
+  //\r
+  Status = VerifyFfsFile (FfsFile);\r
+  if (EFI_ERROR (Status)) {\r
+    Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  memset (&ImageContext, 0, sizeof (ImageContext));\r
+\r
+  //\r
+  // Check if XIP file type. If not XIP, don't rebase.\r
+  //\r
+  if (FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
+      FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
+      FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
+      FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
+      ) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Rebase each PE32 section\r
+  //\r
+  Status      = EFI_SUCCESS;\r
+  FoundCount  = 0;\r
+  for (Index = 1;; Index++) {\r
+    Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    FoundCount++;\r
+\r
+    //\r
+    // Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section\r
+    //\r
+    NewPe32BaseAddress = ((UINT32) BaseAddress) + ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) - (UINTN) FfsFile);\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.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
+\r
+    Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);\r
+      return Status;\r
+    }\r
+    //\r
+    // Allocate a buffer for the image to be loaded into.\r
+    //\r
+    Pe32ImageSize       = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION);\r
+    MemoryImagePointer  = (UINTN) (malloc (Pe32ImageSize + 0x1000));\r
+    if (MemoryImagePointer == 0) {\r
+      Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);\r
+    MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);\r
+    \r
+\r
+    ImageContext.ImageAddress = MemoryImagePointerAligned;\r
+\r
+    Status                    = PeCoffLoaderLoadImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 0, "LoadImage() call failed on rebase", FileGuidString);\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, 0, "RelocateImage() call failed on rebase", FileGuidString);\r
+      free ((VOID *) MemoryImagePointer);\r
+      return Status;\r
+    }\r
+\r
+    ImageAddress  = ImageContext.ImageAddress;\r
+    ImageSize     = ImageContext.ImageSize;\r
+    EntryPoint    = ImageContext.EntryPoint;\r
+\r
+    if (ImageSize > Pe32ImageSize) {\r
+      Error (\r
+        NULL,\r
+        0,\r
+        0,\r
+        "rebased image is larger than original PE32 image",\r
+        "0x%X > 0x%X, file %s",\r
+        ImageSize,\r
+        Pe32ImageSize,\r
+        FileGuidString\r
+        );\r
+      free ((VOID *) MemoryImagePointer);\r
+      return EFI_ABORTED;\r
+    }\r
+    //\r
+    // Since we may have updated the Codeview RVA, we need to insure the PE\r
+    // header indicates the image is large enough to contain the Codeview data\r
+    // so it will be loaded properly later if the PEIM is reloaded into memory...\r
+    //\r
+    PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);\r
+    if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
+      PeHdrSizeOfImage     = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);\r
+      PeHdrChecksum        = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);\r
+    } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
+      PeHdrSizeOfImage     = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);\r
+      PeHdrChecksum        = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);\r
+    } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
+      PeHdrSizeOfImage     = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);\r
+      PeHdrChecksum        = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);\r
+    } else {\r
+      Error (\r
+        NULL,\r
+        0,\r
+        0,\r
+        "unknown machine type in PE32 image",\r
+        "machine type=0x%X, file=%s",\r
+        (UINT32) PeHdr->FileHeader.Machine,\r
+        FileGuidString\r
+        );\r
+      free ((VOID *) MemoryImagePointer);\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    if (*PeHdrSizeOfImage != ImageContext.ImageSize) {\r
+      *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;\r
+      if (*PeHdrChecksum) {\r
+        *PeHdrChecksum = 0;\r
+      }\r
+    }\r
+\r
+    memcpy (CurrentPe32Section.Pe32Section + 1, (VOID *) MemoryImagePointerAligned, (UINT32) ImageSize);\r
+    \r
+    //\r
+    // Get EntryPoint in Flash Region.\r
+    //\r
+    EntryPoint = NewPe32BaseAddress + EntryPoint - ImageAddress;\r
+\r
+    //\r
+    // If a map file was selected output mapping information for any file that\r
+    // was rebased.\r
+    //\r
+    if (MapFile != NULL) {\r
+      fprintf (MapFile, "PE32 File: %s Base:%08lx", FileGuidString, BaseAddress);\r
+      fprintf (MapFile, " EntryPoint:%08lx", EntryPoint);\r
+      if (ImageContext.PdbPointer != NULL) {\r
+        fprintf (MapFile, " FileName: %s", ImageContext.PdbPointer);\r
+      }\r
+      fprintf (MapFile, "\n");\r
+    }\r
+\r
+    free ((VOID *) MemoryImagePointer);\r
+\r
+    //\r
+    // Now update file checksum\r
+    //\r
+    if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+      TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
+    } else {\r
+      TailSize = 0;\r
+    }\r
+\r
+    if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
+      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) - TailSize\r
+                                                  );\r
+      } else {\r
+        FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+      }\r
+\r
+      FfsFile->State = SavedState;\r
+    }\r
+    //\r
+    // Update tail if present\r
+    //\r
+    if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+      TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
+      *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
+    }\r
+  }\r
+  //\r
+  // Now process TE sections\r
+  //\r
+  for (Index = 1;; Index++) {\r
+    Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    FoundCount++;\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
+\r
+    NewPe32BaseAddress = ((UINT32) BaseAddress) +\r
+      (\r
+        (UINTN) CurrentPe32Section.Pe32Section +\r
+        sizeof (EFI_COMMON_SECTION_HEADER) +\r
+        sizeof (EFI_TE_IMAGE_HEADER) -\r
+        TEImageHeader->StrippedSize -\r
+        (UINTN) FfsFile\r
+      );\r
+\r
+    //\r
+    // Allocate a buffer to unshrink the image into.\r
+    //\r
+    Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -\r
+    sizeof (EFI_TE_IMAGE_HEADER);\r
+    Pe32ImageSize += TEImageHeader->StrippedSize;\r
+    TEBuffer = (UINT8 *) malloc (Pe32ImageSize);\r
+    if (TEBuffer == NULL) {\r
+      Error (NULL, 0, 0, "failed to allocate memory", NULL);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Expand the image into our buffer and fill in critical fields in the DOS header\r
+    // Fill in fields required by the loader.\r
+    // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value\r
+    // itself.\r
+    //\r
+    memset (TEBuffer, 0, Pe32ImageSize);\r
+    DosHeader = (EFI_IMAGE_DOS_HEADER *) TEBuffer;\r
+    DosHeader->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
+    *(UINT32 *) (TEBuffer + 0x3C) = 0x40;\r
+    PeHdr = (EFI_IMAGE_NT_HEADERS *) (TEBuffer + 0x40);\r
+    PeHdr->Signature = EFI_IMAGE_NT_SIGNATURE;\r
+    PeHdr->FileHeader.Machine = TEImageHeader->Machine;\r
+    PeHdr->FileHeader.NumberOfSections = TEImageHeader->NumberOfSections;\r
+\r
+    //\r
+    // Say the size of the optional header is the total we stripped off less the size of a PE file header and PE signature and\r
+    // the 0x40 bytes for our DOS header.\r
+    //\r
+    PeHdr->FileHeader.SizeOfOptionalHeader = (UINT16) (TEImageHeader->StrippedSize - 0x40 - sizeof (UINT32) - sizeof (EFI_IMAGE_FILE_HEADER));\r
+    PeHdr->OptionalHeader.ImageBase = (UINTN) (TEImageHeader->ImageBase - TEImageHeader->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));\r
+    PeHdr->OptionalHeader.AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint;\r
+    PeHdr->OptionalHeader.BaseOfCode  = TEImageHeader->BaseOfCode;\r
+    PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;\r
+    PeHdr->OptionalHeader.Subsystem   = TEImageHeader->Subsystem;\r
+    PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;\r
+    PeHdr->OptionalHeader.SizeOfHeaders = TEImageHeader->StrippedSize + TEImageHeader->NumberOfSections *\r
+    sizeof (EFI_IMAGE_SECTION_HEADER) - 12;\r
+\r
+    //\r
+    // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image\r
+    //\r
+    if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) ||\r
+        (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0)\r
+        ) {\r
+      PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC + 1;\r
+      PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
+      PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
+    }\r
+\r
+    if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) ||\r
+        (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)\r
+        ) {\r
+      PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
+      PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
+      if (PeHdr->OptionalHeader.NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1) {\r
+        PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1;\r
+      }\r
+    }\r
+    //\r
+    // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility\r
+    //\r
+    PeHdr->OptionalHeader.SectionAlignment = 0x10;\r
+\r
+    //\r
+    // Copy the rest of the image to its original offset\r
+    //\r
+    memcpy (\r
+      TEBuffer + TEImageHeader->StrippedSize,\r
+      (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + sizeof (EFI_TE_IMAGE_HEADER),\r
+      GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -\r
+      sizeof (EFI_TE_IMAGE_HEADER)\r
+      );\r
+\r
+    //\r
+    // Initialize context\r
+    //\r
+    memset (&ImageContext, 0, sizeof (ImageContext));\r
+    ImageContext.Handle     = (VOID *) TEBuffer;\r
+    ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
+\r
+    Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);\r
+      free (TEBuffer);\r
+      return Status;\r
+    }\r
+    //\r
+    // Allocate a buffer for the image to be loaded into.\r
+    //\r
+    MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));\r
+    if (MemoryImagePointer == 0) {\r
+      Error (NULL, 0, 0, "memory allocation error on rebase of TE image", FileGuidString);\r
+      free (TEBuffer);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);\r
+    MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);\r
+    \r
+\r
+    ImageContext.ImageAddress = MemoryImagePointerAligned;\r
+    Status                    = PeCoffLoaderLoadImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString);\r
+      free (TEBuffer);\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, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);\r
+      free ((VOID *) MemoryImagePointer);\r
+      free (TEBuffer);\r
+      return Status;\r
+    }\r
+\r
+    ImageAddress  = ImageContext.ImageAddress;\r
+    ImageSize     = ImageContext.ImageSize;\r
+    EntryPoint    = ImageContext.EntryPoint;\r
+\r
+    //\r
+    // Since we may have updated the Codeview RVA, we need to insure the PE\r
+    // header indicates the image is large enough to contain the Codeview data\r
+    // so it will be loaded properly later if the PEIM is reloaded into memory...\r
+    //\r
+    PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);\r
+    if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
+      PeHdrSizeOfImage     = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);\r
+      PeHdrChecksum        = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);\r
+    } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
+      PeHdrSizeOfImage     = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);\r
+      PeHdrChecksum        = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);\r
+    } else {\r
+      Error (\r
+        NULL,\r
+        0,\r
+        0,\r
+        "unknown machine type in TE image",\r
+        "machine type=0x%X, file=%s",\r
+        (UINT32) PeHdr->FileHeader.Machine,\r
+        FileGuidString\r
+        );\r
+      free ((VOID *) MemoryImagePointer);\r
+      free (TEBuffer);\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    if (*PeHdrSizeOfImage != ImageContext.ImageSize) {\r
+      *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;\r
+      if (*PeHdrChecksum) {\r
+        *PeHdrChecksum = 0;\r
+      }\r
+    }\r
+\r
+    TEImageHeader->ImageBase = (UINT64) (NewPe32BaseAddress + TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
+    memcpy (\r
+      (UINT8 *) (CurrentPe32Section.Pe32Section + 1) + sizeof (EFI_TE_IMAGE_HEADER),\r
+      (VOID *) ((UINT8 *) MemoryImagePointerAligned + TEImageHeader->StrippedSize),\r
+      GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -\r
+      sizeof (EFI_TE_IMAGE_HEADER)\r
+      );\r
+    \r
+    //\r
+    // Get EntryPoint in Flash Region.\r
+    //\r
+    EntryPoint = NewPe32BaseAddress + EntryPoint - ImageAddress;\r
+\r
+    //\r
+    // If a map file was selected output mapping information for any file that\r
+    // was rebased.\r
+    //\r
+    if (MapFile != NULL) {\r
+      fprintf (MapFile, "TE   File: %s Base:%08lx", FileGuidString, BaseAddress);\r
+      fprintf (MapFile, " EntryPoint:%08lx", EntryPoint);\r
+      if (ImageContext.PdbPointer != NULL) {\r
+        fprintf (MapFile, " FileName: %s", ImageContext.PdbPointer);\r
+      }\r
+      fprintf (MapFile, "\n");\r
+    }\r
+\r
+    free ((VOID *) MemoryImagePointer);\r
+    free (TEBuffer);\r
+    if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+      TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
+    } else {\r
+      TailSize = 0;\r
+    }\r
+    //\r
+    // Now update file checksum\r
+    //\r
+    if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
+      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) - TailSize\r
+                                                  );\r
+      } else {\r
+        FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+      }\r
+\r
+      FfsFile->State = SavedState;\r
+    }\r
+    //\r
+    // Update tail if present\r
+    //\r
+    if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+      TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
+      *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
+    }\r
+  }\r
+  //\r
+  // If we found no files, then emit an error if no compressed sections either\r
+  //\r
+  if (FoundCount == 0) {\r
+    Status = GetSectionByType (FfsFile, EFI_SECTION_COMPRESSION, Index, &CurrentPe32Section);\r
+    if (EFI_ERROR (Status)) {\r
+      Error (NULL, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString);\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FfsRebaseImageRead (\r
+  IN     VOID    *FileHandle,\r
+  IN     UINTN   FileOffset,\r
+  IN OUT UINT32  *ReadSize,\r
+  OUT    VOID    *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
+\r
+Arguments:\r
+\r
+  FileHandle - The handle to the PE/COFF file\r
+\r
+  FileOffset - The offset, in bytes, into the file to read\r
+\r
+  ReadSize   - The number of bytes to read from the file starting at FileOffset\r
+\r
+  Buffer     - A pointer to the buffer to read the data into.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+--*/\r
+{\r
+  CHAR8   *Destination8;\r
+  CHAR8   *Source8;\r
+  UINT32  Length;\r
+\r
+  Destination8  = Buffer;\r
+  Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
+  Length        = *ReadSize;\r
+  while (Length--) {\r
+    *(Destination8++) = *(Source8++);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r