summaryrefslogtreecommitdiffstats
path: root/BaseTools/Source/C/FMMT/Rebase.c
diff options
context:
space:
mode:
authorShenglei Zhang <shenglei.zhang@intel.com>2019-05-28 11:01:47 +0800
committerLiming Gao <liming.gao@intel.com>2019-07-04 11:34:57 +0800
commit080981d72dcbb782ad73716c439639324b0aa4dd (patch)
treefeea5c7a4658f428a48975b10be8d1ebcae86155 /BaseTools/Source/C/FMMT/Rebase.c
parent3c59d94637adbfdd497b5a2c16073c7dc62b669c (diff)
downloadedk2-080981d72dcbb782ad73716c439639324b0aa4dd.tar.gz
edk2-080981d72dcbb782ad73716c439639324b0aa4dd.tar.bz2
edk2-080981d72dcbb782ad73716c439639324b0aa4dd.zip
BaseTools/FMMT: Add a tool FMMT
FMMT is a tool to enable removal, addition and replacement of FFS files in FD image binaries. https://bugzilla.tianocore.org/show_bug.cgi?id=1847 Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
Diffstat (limited to 'BaseTools/Source/C/FMMT/Rebase.c')
-rw-r--r--BaseTools/Source/C/FMMT/Rebase.c846
1 files changed, 846 insertions, 0 deletions
diff --git a/BaseTools/Source/C/FMMT/Rebase.c b/BaseTools/Source/C/FMMT/Rebase.c
new file mode 100644
index 0000000000..d32217d18c
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Rebase.c
@@ -0,0 +1,846 @@
+/** @file
+
+ Library to rebase PE image.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Rebase.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <PeCoffLib.h>
+#include <CommonLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <FvLib.h>
+#include "EfiUtilityMsgs.h"
+
+static
+EFI_STATUS
+FfsRebaseImageRead(
+IN VOID *FileHandle,
+IN UINTN FileOffset,
+IN OUT UINT32 *ReadSize,
+OUT VOID *Buffer
+);
+
+EFI_STATUS
+RebaseFfs(
+IN OUT UINT64 BaseAddress,
+IN CHAR8 *FileName,
+IN OUT EFI_FFS_FILE_HEADER *FfsFile,
+IN UINTN XipOffset
+)
+/*++
+
+Routine Description:
+
+This function determines if a file is XIP and should be rebased. It will
+rebase any PE32 sections found in the file using the base address.
+
+Arguments:
+
+FvInfo A pointer to FV_INFO struture.
+FileName Ffs File PathName
+FfsFile A pointer to Ffs file image.
+XipOffset The offset address to use for rebasing the XIP file image.
+
+Returns:
+
+EFI_SUCCESS The image was properly rebased.
+EFI_INVALID_PARAMETER An input parameter is invalid.
+EFI_ABORTED An error occurred while rebasing the input file image.
+EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+EFI_NOT_FOUND No compressed sections could be found.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;
+ EFI_PHYSICAL_ADDRESS XipBase;
+ EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;
+ UINTN Index;
+ EFI_FILE_SECTION_POINTER CurrentPe32Section;
+ EFI_FFS_FILE_STATE SavedState;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_TE_IMAGE_HEADER *TEImageHeader;
+ UINT8 *MemoryImagePointer;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ CHAR8 PeFileName[MAX_LONG_FILE_PATH];
+ CHAR8 *Cptr;
+ FILE *PeFile;
+ UINT8 *PeFileBuffer;
+ UINT32 PeFileSize;
+ CHAR8 *PdbPointer;
+ UINT32 FfsHeaderSize;
+ UINT32 CurSecHdrSize;
+ CHAR8 *LongFilePathName;
+
+ Index = 0;
+ MemoryImagePointer = NULL;
+ TEImageHeader = NULL;
+ ImgHdr = NULL;
+ SectionHeader = NULL;
+ Cptr = NULL;
+ PeFile = NULL;
+ PeFileBuffer = NULL;
+
+ //
+ // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
+ //
+ if (BaseAddress == 0) {
+ return EFI_SUCCESS;
+ }
+
+ XipBase = BaseAddress + XipOffset;
+
+ //
+ // We only process files potentially containing PE32 sections.
+ //
+ switch (FfsFile->Type) {
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+ case EFI_FV_FILETYPE_DRIVER:
+ case EFI_FV_FILETYPE_DXE_CORE:
+ break;
+ case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
+ //
+ // Rebase the inside FvImage.
+ //
+ GetChildFvFromFfs (BaseAddress, FfsFile, XipOffset);
+
+ //
+ // Search PE/TE section in FV sectin.
+ //
+ break;
+ default:
+ return EFI_SUCCESS;
+ }
+
+ FfsHeaderSize = GetFfsHeaderLength(FfsFile);
+ //
+ // Rebase each PE32 section
+ //
+ Status = EFI_SUCCESS;
+ for (Index = 1;; Index++) {
+ //
+ // Init Value
+ //
+ NewPe32BaseAddress = 0;
+
+ //
+ // Find Pe Image
+ //
+ Status = GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+ //
+ // Initialize context
+ //
+ memset(&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+
+ //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+ // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ // mArm = TRUE;
+ //}
+
+ //
+ // Keep Image Context for PE image in FV
+ //
+ memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+ //
+ // Get File PdbPointer
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+ if (PdbPointer == NULL) {
+ PdbPointer = FileName;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Calculate the PE32 base address, based on file type
+ //
+ switch (FfsFile->Type) {
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+ //
+ // Check if section-alignment and file-alignment match or not
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+ //
+ // Xip module has the same section alignment and file alignment.
+ //
+ Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+ return EFI_ABORTED;
+ }
+ //
+ // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
+ //
+ if (ImageContext.RelocationsStripped) {
+ //
+ // Construct the original efi file Name
+ //
+ if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+ Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+ return EFI_ABORTED;
+ }
+ strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+ PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+ Cptr = PeFileName + strlen(PeFileName);
+ while (*Cptr != '.') {
+ Cptr--;
+ }
+ if (*Cptr != '.') {
+ Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ return EFI_ABORTED;
+ }
+ else {
+ *(Cptr + 1) = 'e';
+ *(Cptr + 2) = 'f';
+ *(Cptr + 3) = 'i';
+ *(Cptr + 4) = '\0';
+ }
+ LongFilePathName = LongFilePath(PeFileName);
+ if (LongFilePathName == NULL) {
+ Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+ return EFI_ABORTED;
+ }
+ PeFile = fopen(LongFilePathName, "rb");
+ if (PeFile == NULL) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ //return EFI_ABORTED;
+ break;
+ }
+ //
+ // Get the file size
+ //
+ PeFileSize = _filelength(fileno(PeFile));
+ PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+ if (PeFileBuffer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ fclose(PeFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read Pe File
+ //
+ fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+ //
+ // close file
+ //
+ fclose(PeFile);
+ //
+ // Handle pointer to the original efi image.
+ //
+ ImageContext.Handle = PeFileBuffer;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+ ImageContext.RelocationsStripped = FALSE;
+ }
+
+ NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+ break;
+
+ case EFI_FV_FILETYPE_DRIVER:
+ case EFI_FV_FILETYPE_DXE_CORE:
+ //
+ // Check if section-alignment and file-alignment match or not
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+ //
+ // Xip module has the same section alignment and file alignment.
+ //
+ Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+ return EFI_ABORTED;
+ }
+ NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+ break;
+
+ default:
+ //
+ // Not supported file type
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Relocation doesn't exist
+ //
+ if (ImageContext.RelocationsStripped) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ continue;
+ }
+
+ //
+ // Relocation exist and rebase
+ //
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy Relocated data to raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(
+ (UINTN)ImgHdr +
+ sizeof (UINT32)+
+ sizeof (EFI_IMAGE_FILE_HEADER)+
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
+ CopyMem(
+ (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+
+ free((VOID *)MemoryImagePointer);
+ MemoryImagePointer = NULL;
+ if (PeFileBuffer != NULL) {
+ free(PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+
+ //
+ // Update Image Base Address
+ //
+ if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32)NewPe32BaseAddress;
+ }
+ else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
+ }
+ else {
+ Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
+ ImgHdr->Pe32.OptionalHeader.Magic,
+ FileName
+ );
+ return EFI_ABORTED;
+ }
+
+ //
+ // Now update file checksum
+ //
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ SavedState = FfsFile->State;
+ FfsFile->IntegrityCheck.Checksum.File = 0;
+ FfsFile->State = 0;
+ FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+ (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+ GetFfsFileLength(FfsFile) - FfsHeaderSize
+ );
+ FfsFile->State = SavedState;
+ }
+
+ }
+
+ if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
+ FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
+ FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
+ FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&
+ FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ ) {
+ //
+ // Only Peim code may have a TE section
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Now process TE sections
+ //
+ for (Index = 1;; Index++) {
+ NewPe32BaseAddress = 0;
+
+ //
+ // Find Te Image
+ //
+ Status = GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+ //
+ // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
+ // by GenTEImage
+ //
+ TEImageHeader = (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+
+ //
+ // Initialize context, load image info.
+ //
+ memset(&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *)TEImageHeader;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+
+ //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+ // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ // mArm = TRUE;
+ //}
+
+ //
+ // Keep Image Context for TE image in FV
+ //
+ memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+ //
+ // Get File PdbPointer
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+ if (PdbPointer == NULL) {
+ PdbPointer = FileName;
+ }
+ //
+ // Set new rebased address.
+ //
+ NewPe32BaseAddress = XipBase + (UINTN)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
+ - TEImageHeader->StrippedSize - (UINTN)FfsFile;
+
+ //
+ // if reloc is stripped, try to get the original efi image to get reloc info.
+ //
+ if (ImageContext.RelocationsStripped) {
+ //
+ // Construct the original efi file name
+ //
+ if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+ Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+ return EFI_ABORTED;
+ }
+ strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+ PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+ Cptr = PeFileName + strlen(PeFileName);
+ while (*Cptr != '.') {
+ Cptr--;
+ }
+
+ if (*Cptr != '.') {
+ Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ return EFI_ABORTED;
+ }
+ else {
+ *(Cptr + 1) = 'e';
+ *(Cptr + 2) = 'f';
+ *(Cptr + 3) = 'i';
+ *(Cptr + 4) = '\0';
+ }
+
+ LongFilePathName = LongFilePath(PeFileName);
+ if (LongFilePathName == NULL) {
+ Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+ return EFI_ABORTED;
+ }
+ PeFile = fopen(LongFilePathName, "rb");
+ if (PeFile == NULL) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ //return EFI_ABORTED;
+ }
+ else {
+ //
+ // Get the file size
+ //
+ PeFileSize = _filelength(fileno(PeFile));
+ PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+ if (PeFileBuffer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ fclose(PeFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read Pe File
+ //
+ fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+ //
+ // close file
+ //
+ fclose(PeFile);
+ //
+ // Append reloc section into TeImage
+ //
+ ImageContext.Handle = PeFileBuffer;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+ ImageContext.RelocationsStripped = FALSE;
+ }
+ }
+ //
+ // Relocation doesn't exist
+ //
+ if (ImageContext.RelocationsStripped) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ continue;
+ }
+
+ //
+ // Relocation exist and rebase
+ //
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+ //
+ // Reloacate TeImage
+ //
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy the relocated image into raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1);
+ for (Index = 0; Index < TEImageHeader->NumberOfSections; Index++, SectionHeader++) {
+ if (!ImageContext.IsTeImage) {
+ CopyMem(
+ (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+ else {
+ CopyMem(
+ (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+ }
+
+ //
+ // Free the allocated memory resource
+ //
+ free((VOID *)MemoryImagePointer);
+ MemoryImagePointer = NULL;
+ if (PeFileBuffer != NULL) {
+ free(PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+
+ //
+ // Update Image Base Address
+ //
+ TEImageHeader->ImageBase = NewPe32BaseAddress;
+
+ //
+ // Now update file checksum
+ //
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ SavedState = FfsFile->State;
+ FfsFile->IntegrityCheck.Checksum.File = 0;
+ FfsFile->State = 0;
+ FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+ (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+ GetFfsFileLength(FfsFile) - FfsHeaderSize
+ );
+ FfsFile->State = SavedState;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FfsRebaseImageRead(
+IN VOID *FileHandle,
+IN UINTN FileOffset,
+IN OUT UINT32 *ReadSize,
+OUT VOID *Buffer
+)
+/*++
+
+Routine Description:
+
+Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+
+FileHandle - The handle to the PE/COFF file
+
+FileOffset - The offset, in bytes, into the file to read
+
+ReadSize - The number of bytes to read from the file starting at FileOffset
+
+Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+
+EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINT32 Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetChildFvFromFfs (
+ IN UINT64 BaseAddress,
+ IN EFI_FFS_FILE_HEADER *FfsFile,
+ IN UINTN XipOffset
+ )
+/*++
+
+Routine Description:
+
+ This function gets all child FvImages in the input FfsFile, and records
+ their base address to the parent image.
+
+Arguments:
+ FvInfo A pointer to FV_INFO struture.
+ FfsFile A pointer to Ffs file image that may contain FvImage.
+ XipOffset The offset address to the parent FvImage base.
+
+Returns:
+
+ EFI_SUCCESS Base address of child Fv image is recorded.
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_FILE_SECTION_POINTER SubFvSection;
+ EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader;
+ EFI_PHYSICAL_ADDRESS SubFvBaseAddress;
+ EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader;
+ UINT32 OrigFvLength;
+ EFI_PHYSICAL_ADDRESS OrigFvBaseAddress;
+ EFI_FFS_FILE_HEADER *CurrentFile;
+
+ //
+ // Initialize FV library, saving previous values
+ //
+ OrigFvHeader = NULL;
+ GetFvHeader (&OrigFvHeader, &OrigFvLength);
+ OrigFvBaseAddress = BaseAddress;
+ for (Index = 1;; Index++) {
+ //
+ // Find FV section
+ //
+ Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));
+
+ //
+ // Rebase on Flash
+ //
+ SubFvBaseAddress = OrigFvBaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;
+ //mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;
+ BaseAddress = SubFvBaseAddress;
+ InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength);
+
+ Status = GetNextFile (NULL, &CurrentFile);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be found");
+ continue;
+ }
+ while (CurrentFile) {
+ RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINTN) SubFvImageHeader);
+ Status = GetNextFile (CurrentFile, &CurrentFile);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ BaseAddress = OrigFvBaseAddress;
+ if (OrigFvHeader != NULL) {
+ InitializeFvLib(OrigFvHeader, OrigFvLength);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPe32Info (
+ IN UINT8 *Pe32,
+ OUT UINT32 *EntryPoint,
+ OUT UINT32 *BaseOfCode,
+ OUT UINT16 *MachineType
+ )
+/*++
+
+Routine Description:
+
+ Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
+ See EfiImage.h for machine types. The entry point offset is from the beginning
+ of the PE32 buffer passed in.
+
+Arguments:
+
+ Pe32 Beginning of the PE32.
+ EntryPoint Offset from the beginning of the PE32 to the image entry point.
+ BaseOfCode Base address of code.
+ MachineType Magic number for the machine type.
+
+Returns:
+
+ EFI_SUCCESS Function completed successfully.
+ EFI_ABORTED Error encountered.
+ EFI_INVALID_PARAMETER A required parameter was NULL.
+ EFI_UNSUPPORTED The operation is unsupported.
+
+--*/
+{
+ EFI_IMAGE_DOS_HEADER *DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_TE_IMAGE_HEADER *TeHeader;
+
+ //
+ // Verify input parameters
+ //
+ if (Pe32 == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // First check whether it is one TE Image.
+ //
+ TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
+ if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ //
+ // By TeImage Header to get output
+ //
+ *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+ *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+ *MachineType = TeHeader->Machine;
+ } else {
+
+ //
+ // Then check whether
+ // First is the DOS header
+ //
+ DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
+
+ //
+ // Verify DOS header is expected
+ //
+ if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Immediately following is the NT header.
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
+
+ //
+ // Verify NT header is expected
+ //
+ if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get output
+ //
+ *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
+ *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
+ *MachineType = ImgHdr->Pe32.FileHeader.Machine;
+ }
+
+ //
+ // Verify machine type is supported
+ //
+ if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&
+ (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
+ Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+