--- /dev/null
+/*++\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