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>
This commit is contained in:
committed by
Liming Gao
parent
3c59d94637
commit
080981d72d
846
BaseTools/Source/C/FMMT/Rebase.c
Normal file
846
BaseTools/Source/C/FMMT/Rebase.c
Normal file
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user