Adding Additional Tools that are needed for Platform Image creation.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@198 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
973
Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.c
Normal file
973
Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.c
Normal file
@ -0,0 +1,973 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1999 - 2005 Intel Corporation. All rights reserved
|
||||
This software and associated documentation (if any) is furnished
|
||||
under a license and may only be used or copied in accordance
|
||||
with the terms of the license. Except as permitted by such
|
||||
license, no part of this software or documentation may be
|
||||
reproduced, stored in a retrieval system, or transmitted in any
|
||||
form or by any means without the express written consent of
|
||||
Intel Corporation.
|
||||
|
||||
|
||||
Module Name:
|
||||
|
||||
PeiRebaseExe.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This contains all code necessary to build the PeiRebase.exe utility.
|
||||
This utility relies heavily on the PeiRebase DLL. Definitions for both
|
||||
can be found in the PEI Rebase Utility Specification, review draft.
|
||||
|
||||
--*/
|
||||
|
||||
#include "PeiRebaseExe.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "CommonLib.h"
|
||||
#include "ParseInf.h"
|
||||
#include EFI_GUID_DEFINITION (PeiPeCoffLoader)
|
||||
#include "FvLib.h"
|
||||
|
||||
#include "EfiUtilityMsgs.h"
|
||||
|
||||
extern EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader;
|
||||
|
||||
EFI_STATUS
|
||||
ReadHeader (
|
||||
IN FILE *InputFile,
|
||||
OUT UINT32 *FvSize,
|
||||
OUT BOOLEAN *ErasePolarity
|
||||
);
|
||||
|
||||
int
|
||||
main (
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This utility relocates PEI XIP PE32s in a FV.
|
||||
|
||||
Arguments:
|
||||
|
||||
argc - Number of command line arguments
|
||||
argv[]:
|
||||
BaseAddress The base address to use for rebasing the FV. The correct
|
||||
format is a hex number preceded by 0x.
|
||||
InputFileName The name of the input FV file.
|
||||
OutputFileName The name of the output FV file.
|
||||
|
||||
Arguments come in pair in any order.
|
||||
-I InputFileName
|
||||
-O OutputFileName
|
||||
-B BaseAddress
|
||||
|
||||
Returns:
|
||||
|
||||
0 No error conditions detected.
|
||||
1 One or more of the input parameters is invalid.
|
||||
2 A resource required by the utility was unavailable.
|
||||
Most commonly this will be memory allocation or file creation.
|
||||
3 PeiRebase.dll could not be loaded.
|
||||
4 Error executing the PEI rebase.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT8 Index;
|
||||
CHAR8 InputFileName[_MAX_PATH];
|
||||
CHAR8 OutputFileName[_MAX_PATH];
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
BOOLEAN BaseAddressSet;
|
||||
EFI_STATUS Status;
|
||||
FILE *InputFile;
|
||||
FILE *OutputFile;
|
||||
UINT64 FvOffset;
|
||||
UINT32 FileCount;
|
||||
int BytesRead;
|
||||
EFI_FIRMWARE_VOLUME_HEADER *FvImage;
|
||||
UINT32 FvSize;
|
||||
EFI_FFS_FILE_HEADER *CurrentFile;
|
||||
BOOLEAN ErasePolarity;
|
||||
EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress;
|
||||
|
||||
ErasePolarity = FALSE;
|
||||
//
|
||||
// Set utility name for error/warning reporting purposes.
|
||||
//
|
||||
SetUtilityName (UTILITY_NAME);
|
||||
//
|
||||
// Verify the correct number of arguments
|
||||
//
|
||||
if (argc != MAX_ARGS) {
|
||||
PrintUsage ();
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
//
|
||||
// Initialize variables
|
||||
//
|
||||
InputFileName[0] = 0;
|
||||
OutputFileName[0] = 0;
|
||||
BaseAddress = 0;
|
||||
BaseAddressSet = FALSE;
|
||||
FvOffset = 0;
|
||||
FileCount = 0;
|
||||
ErasePolarity = FALSE;
|
||||
InputFile = NULL;
|
||||
OutputFile = NULL;
|
||||
FvImage = NULL;
|
||||
//
|
||||
// Parse the command line arguments
|
||||
//
|
||||
for (Index = 1; Index < MAX_ARGS; Index += 2) {
|
||||
//
|
||||
// Make sure argument pair begin with - or /
|
||||
//
|
||||
if (argv[Index][0] != '-' && argv[Index][0] != '/') {
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index], "unrecognized option");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
//
|
||||
// Make sure argument specifier is only one letter
|
||||
//
|
||||
if (argv[Index][2] != 0) {
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index], "unrecognized option");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
//
|
||||
// Determine argument to read
|
||||
//
|
||||
switch (argv[Index][1]) {
|
||||
case 'I':
|
||||
case 'i':
|
||||
if (strlen (InputFileName) == 0) {
|
||||
strcpy (InputFileName, argv[Index + 1]);
|
||||
} else {
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
case 'o':
|
||||
if (strlen (OutputFileName) == 0) {
|
||||
strcpy (OutputFileName, argv[Index + 1]);
|
||||
} else {
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
case 'b':
|
||||
if (!BaseAddressSet) {
|
||||
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BaseAddress);
|
||||
if (EFI_ERROR (Status)) {
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for the base address");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
BaseAddressSet = TRUE;
|
||||
} else {
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index + 1], "-b BaseAddress may only be specified once");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PrintUsage ();
|
||||
Error (NULL, 0, 0, argv[Index], "unrecognized argument");
|
||||
return STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Open the file containing the FV
|
||||
//
|
||||
InputFile = fopen (InputFileName, "rb");
|
||||
if (InputFile == NULL) {
|
||||
Error (NULL, 0, 0, InputFileName, "could not open input file for reading");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
//
|
||||
// Determine size of FV
|
||||
//
|
||||
Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "could not parse the FV header", NULL);
|
||||
goto Finish;
|
||||
}
|
||||
//
|
||||
// Allocate a buffer for the FV image
|
||||
//
|
||||
FvImage = malloc (FvSize);
|
||||
if (FvImage == NULL) {
|
||||
Error (NULL, 0, 0, "application error", "memory allocation failed");
|
||||
goto Finish;
|
||||
}
|
||||
//
|
||||
// Read the entire FV to the buffer
|
||||
//
|
||||
BytesRead = fread (FvImage, 1, FvSize, InputFile);
|
||||
fclose (InputFile);
|
||||
InputFile = NULL;
|
||||
if ((unsigned int) BytesRead != FvSize) {
|
||||
Error (NULL, 0, 0, InputFileName, "failed to read from file");
|
||||
goto Finish;
|
||||
}
|
||||
//
|
||||
// Prepare to walk the FV image
|
||||
//
|
||||
InitializeFvLib (FvImage, FvSize);
|
||||
//
|
||||
// Get the first file
|
||||
//
|
||||
Status = GetNextFile (NULL, &CurrentFile);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL);
|
||||
goto Finish;
|
||||
}
|
||||
//
|
||||
// Check if each file should be rebased
|
||||
//
|
||||
while (CurrentFile != NULL) {
|
||||
//
|
||||
// Rebase this file
|
||||
//
|
||||
CurrentFileBaseAddress = BaseAddress + ((UINTN) CurrentFile - (UINTN) FvImage);
|
||||
Status = FfsRebase (CurrentFile, CurrentFileBaseAddress);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
switch (Status) {
|
||||
|
||||
case EFI_INVALID_PARAMETER:
|
||||
Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL);
|
||||
break;
|
||||
|
||||
case EFI_ABORTED:
|
||||
Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL);
|
||||
break;
|
||||
|
||||
case EFI_OUT_OF_RESOURCES:
|
||||
Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL);
|
||||
break;
|
||||
|
||||
case EFI_NOT_FOUND:
|
||||
Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status);
|
||||
break;
|
||||
}
|
||||
|
||||
goto Finish;
|
||||
}
|
||||
//
|
||||
// Get the next file
|
||||
//
|
||||
Status = GetNextFile (CurrentFile, &CurrentFile);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL);
|
||||
goto Finish;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Open the output file
|
||||
//
|
||||
OutputFile = fopen (OutputFileName, "wb");
|
||||
if (OutputFile == NULL) {
|
||||
Error (NULL, 0, 0, OutputFileName, "failed to open output file");
|
||||
goto Finish;
|
||||
}
|
||||
|
||||
if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) {
|
||||
Error (NULL, 0, 0, "failed to write to output file", 0);
|
||||
goto Finish;
|
||||
}
|
||||
|
||||
Finish:
|
||||
if (InputFile != NULL) {
|
||||
fclose (InputFile);
|
||||
}
|
||||
//
|
||||
// If we created an output file, and there was an error, remove it so
|
||||
// subsequent builds will rebuild it.
|
||||
//
|
||||
if (OutputFile != NULL) {
|
||||
if (GetUtilityStatus () == STATUS_ERROR) {
|
||||
remove (OutputFileName);
|
||||
}
|
||||
|
||||
fclose (OutputFile);
|
||||
}
|
||||
|
||||
if (FvImage != NULL) {
|
||||
free (FvImage);
|
||||
}
|
||||
|
||||
return GetUtilityStatus ();
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
ReadHeader (
|
||||
IN FILE *InputFile,
|
||||
OUT UINT32 *FvSize,
|
||||
OUT BOOLEAN *ErasePolarity
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function determines the size of the FV and the erase polarity. The
|
||||
erase polarity is the FALSE value for file state.
|
||||
|
||||
Arguments:
|
||||
|
||||
InputFile The file that contains the FV image.
|
||||
FvSize The size of the FV.
|
||||
ErasePolarity The FV erase polarity.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS Function completed successfully.
|
||||
EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
|
||||
EFI_ABORTED The function encountered an error.
|
||||
|
||||
--*/
|
||||
{
|
||||
EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;
|
||||
EFI_FV_BLOCK_MAP_ENTRY BlockMap;
|
||||
UINTN Signature[2];
|
||||
UINTN BytesRead;
|
||||
UINT32 Size;
|
||||
|
||||
BytesRead = 0;
|
||||
Size = 0;
|
||||
//
|
||||
// Check input parameters
|
||||
//
|
||||
if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) {
|
||||
Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Read the header
|
||||
//
|
||||
fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
|
||||
BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);
|
||||
Signature[0] = VolumeHeader.Signature;
|
||||
Signature[1] = 0;
|
||||
|
||||
//
|
||||
// Get erase polarity
|
||||
//
|
||||
if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) {
|
||||
*ErasePolarity = TRUE;
|
||||
}
|
||||
|
||||
do {
|
||||
fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
|
||||
BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
|
||||
|
||||
if (BlockMap.NumBlocks != 0) {
|
||||
Size += BlockMap.NumBlocks * BlockMap.BlockLength;
|
||||
}
|
||||
|
||||
} while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0));
|
||||
|
||||
if (VolumeHeader.FvLength != Size) {
|
||||
Error (NULL, 0, 0, "volume size not consistant with block maps", NULL);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
*FvSize = Size;
|
||||
|
||||
rewind (InputFile);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
PrintUtilityInfo (
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Displays the standard utility information to SDTOUT
|
||||
|
||||
Arguments:
|
||||
|
||||
None
|
||||
|
||||
Returns:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
printf (
|
||||
"%s, PEI Rebase Utility. Version %i.%i, %s.\n\n",
|
||||
UTILITY_NAME,
|
||||
UTILITY_MAJOR_VERSION,
|
||||
UTILITY_MINOR_VERSION,
|
||||
UTILITY_DATE
|
||||
);
|
||||
}
|
||||
|
||||
VOID
|
||||
PrintUsage (
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Displays the utility usage syntax to STDOUT
|
||||
|
||||
Arguments:
|
||||
|
||||
None
|
||||
|
||||
Returns:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
printf (
|
||||
"Usage: %s -I InputFileName -O OutputFileName -B BaseAddress\n",
|
||||
UTILITY_NAME
|
||||
);
|
||||
printf (" Where:\n");
|
||||
printf (" InputFileName is the name of the EFI FV file to rebase.\n");
|
||||
printf (" OutputFileName is the desired output file name.\n");
|
||||
printf (" BaseAddress is the FV base address to rebase agains.\n");
|
||||
printf (" Argument pair may be in any order.\n\n");
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
FfsRebase (
|
||||
IN OUT EFI_FFS_FILE_HEADER *FfsFile,
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress
|
||||
)
|
||||
/*++
|
||||
|
||||
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:
|
||||
|
||||
FfsFile A pointer to Ffs file image.
|
||||
BaseAddress The base address to use for rebasing the 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;
|
||||
EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
||||
UINTN MemoryImagePointer;
|
||||
UINTN MemoryImagePointerAligned;
|
||||
EFI_PHYSICAL_ADDRESS ImageAddress;
|
||||
UINT64 ImageSize;
|
||||
EFI_PHYSICAL_ADDRESS EntryPoint;
|
||||
UINT32 Pe32ImageSize;
|
||||
UINT32 NewPe32BaseAddress;
|
||||
UINTN Index;
|
||||
EFI_FILE_SECTION_POINTER CurrentPe32Section;
|
||||
EFI_FFS_FILE_STATE SavedState;
|
||||
EFI_IMAGE_NT_HEADERS *PeHdr;
|
||||
UINT32 *PeHdrSizeOfImage;
|
||||
UINT32 *PeHdrChecksum;
|
||||
UINT32 FoundCount;
|
||||
EFI_TE_IMAGE_HEADER *TEImageHeader;
|
||||
UINT8 *TEBuffer;
|
||||
EFI_IMAGE_DOS_HEADER *DosHeader;
|
||||
UINT8 FileGuidString[80];
|
||||
UINT32 TailSize;
|
||||
EFI_FFS_FILE_TAIL TailValue;
|
||||
|
||||
//
|
||||
// Verify input parameters
|
||||
//
|
||||
if (FfsFile == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Convert the GUID to a string so we can at least report which file
|
||||
// if we find an error.
|
||||
//
|
||||
PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE);
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
|
||||
TailSize = sizeof (EFI_FFS_FILE_TAIL);
|
||||
} else {
|
||||
TailSize = 0;
|
||||
}
|
||||
//
|
||||
// Do some cursory checks on the FFS file contents
|
||||
//
|
||||
Status = VerifyFfsFile (FfsFile);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Check if XIP file type. If not XIP, don't rebase.
|
||||
//
|
||||
if (FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
|
||||
FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
|
||||
FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
|
||||
FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
|
||||
) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
//
|
||||
// Rebase each PE32 section
|
||||
//
|
||||
Status = EFI_SUCCESS;
|
||||
FoundCount = 0;
|
||||
for (Index = 1;; Index++) {
|
||||
Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
|
||||
if (EFI_ERROR (Status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
FoundCount++;
|
||||
|
||||
//
|
||||
// Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section
|
||||
//
|
||||
NewPe32BaseAddress = ((UINT32) BaseAddress) + ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) - (UINTN) FfsFile);
|
||||
|
||||
//
|
||||
// Initialize context
|
||||
//
|
||||
memset (&ImageContext, 0, sizeof (ImageContext));
|
||||
ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));
|
||||
ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
|
||||
|
||||
Status = mPeCoffLoader.GetImageInfo (&mPeCoffLoader, &ImageContext);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// Allocate a buffer for the image to be loaded into.
|
||||
//
|
||||
Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION);
|
||||
MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));
|
||||
if (MemoryImagePointer == 0) {
|
||||
Error (NULL, 0, 0, "memory allocation failure", NULL);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);
|
||||
MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);
|
||||
|
||||
|
||||
ImageContext.ImageAddress = MemoryImagePointerAligned;
|
||||
|
||||
Status = mPeCoffLoader.LoadImage (&mPeCoffLoader, &ImageContext);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "LoadImage() call failed on rebase", FileGuidString);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ImageContext.DestinationAddress = NewPe32BaseAddress;
|
||||
Status = mPeCoffLoader.RelocateImage (&mPeCoffLoader, &ImageContext);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ImageAddress = ImageContext.ImageAddress;
|
||||
ImageSize = ImageContext.ImageSize;
|
||||
EntryPoint = ImageContext.EntryPoint;
|
||||
|
||||
if (ImageSize > Pe32ImageSize) {
|
||||
Error (
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
"rebased image is larger than original PE32 image",
|
||||
"0x%X > 0x%X, file %s",
|
||||
ImageSize,
|
||||
Pe32ImageSize,
|
||||
FileGuidString
|
||||
);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
//
|
||||
// Since we may have updated the Codeview RVA, we need to insure the PE
|
||||
// header indicates the image is large enough to contain the Codeview data
|
||||
// so it will be loaded properly later if the PEIM is reloaded into memory...
|
||||
//
|
||||
PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);
|
||||
if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {
|
||||
PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);
|
||||
PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);
|
||||
} else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {
|
||||
PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);
|
||||
PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);
|
||||
} else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {
|
||||
PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);
|
||||
PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);
|
||||
} else {
|
||||
Error (
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
"unknown machine type in PE32 image",
|
||||
"machine type=0x%X, file=%s",
|
||||
(UINT32) PeHdr->FileHeader.Machine,
|
||||
FileGuidString
|
||||
);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
if (*PeHdrSizeOfImage != ImageContext.ImageSize) {
|
||||
*PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;
|
||||
if (*PeHdrChecksum) {
|
||||
*PeHdrChecksum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (CurrentPe32Section.Pe32Section + 1, (VOID *) MemoryImagePointerAligned, (UINT32) ImageSize);
|
||||
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
|
||||
//
|
||||
// Now update file checksum
|
||||
//
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
|
||||
TailSize = sizeof (EFI_FFS_FILE_TAIL);
|
||||
} else {
|
||||
TailSize = 0;
|
||||
}
|
||||
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
|
||||
SavedState = FfsFile->State;
|
||||
FfsFile->IntegrityCheck.Checksum.File = 0;
|
||||
FfsFile->State = 0;
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
|
||||
FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
|
||||
(UINT8 *) FfsFile,
|
||||
GetLength (FfsFile->Size) - TailSize
|
||||
);
|
||||
} else {
|
||||
FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
|
||||
}
|
||||
|
||||
FfsFile->State = SavedState;
|
||||
}
|
||||
//
|
||||
// Update tail if present
|
||||
//
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
|
||||
TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));
|
||||
*(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Now process TE sections
|
||||
//
|
||||
for (Index = 1;; Index++) {
|
||||
Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
|
||||
if (EFI_ERROR (Status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
FoundCount++;
|
||||
|
||||
//
|
||||
// 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 + sizeof (EFI_COMMON_SECTION_HEADER));
|
||||
|
||||
NewPe32BaseAddress = ((UINT32) BaseAddress) +
|
||||
(
|
||||
(UINTN) CurrentPe32Section.Pe32Section +
|
||||
sizeof (EFI_COMMON_SECTION_HEADER) +
|
||||
sizeof (EFI_TE_IMAGE_HEADER) -
|
||||
TEImageHeader->StrippedSize -
|
||||
(UINTN) FfsFile
|
||||
);
|
||||
|
||||
//
|
||||
// Allocate a buffer to unshrink the image into.
|
||||
//
|
||||
Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -
|
||||
sizeof (EFI_TE_IMAGE_HEADER);
|
||||
Pe32ImageSize += TEImageHeader->StrippedSize;
|
||||
TEBuffer = (UINT8 *) malloc (Pe32ImageSize);
|
||||
if (TEBuffer == NULL) {
|
||||
Error (NULL, 0, 0, "failed to allocate memory", NULL);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Expand the image into our buffer and fill in critical fields in the DOS header
|
||||
// Fill in fields required by the loader.
|
||||
// At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value
|
||||
// itself.
|
||||
//
|
||||
memset (TEBuffer, 0, Pe32ImageSize);
|
||||
DosHeader = (EFI_IMAGE_DOS_HEADER *) TEBuffer;
|
||||
DosHeader->e_magic = EFI_IMAGE_DOS_SIGNATURE;
|
||||
*(UINT32 *) (TEBuffer + 0x3C) = 0x40;
|
||||
PeHdr = (EFI_IMAGE_NT_HEADERS *) (TEBuffer + 0x40);
|
||||
PeHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
|
||||
PeHdr->FileHeader.Machine = TEImageHeader->Machine;
|
||||
PeHdr->FileHeader.NumberOfSections = TEImageHeader->NumberOfSections;
|
||||
|
||||
//
|
||||
// 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
|
||||
// the 0x40 bytes for our DOS header.
|
||||
//
|
||||
PeHdr->FileHeader.SizeOfOptionalHeader = (UINT16) (TEImageHeader->StrippedSize - 0x40 - sizeof (UINT32) - sizeof (EFI_IMAGE_FILE_HEADER));
|
||||
PeHdr->OptionalHeader.ImageBase = (UINTN) (TEImageHeader->ImageBase - TEImageHeader->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));
|
||||
PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;
|
||||
PeHdr->OptionalHeader.Subsystem = TEImageHeader->Subsystem;
|
||||
PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;
|
||||
PeHdr->OptionalHeader.SizeOfHeaders = TEImageHeader->StrippedSize + TEImageHeader->NumberOfSections *
|
||||
sizeof (EFI_IMAGE_SECTION_HEADER) - 12;
|
||||
|
||||
//
|
||||
// Set NumberOfRvaAndSizes in the optional header to what we had available in the original image
|
||||
//
|
||||
if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) ||
|
||||
(TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0)
|
||||
) {
|
||||
PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC + 1;
|
||||
PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
|
||||
PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
|
||||
}
|
||||
|
||||
if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) ||
|
||||
(TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)
|
||||
) {
|
||||
PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
||||
PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
|
||||
if (PeHdr->OptionalHeader.NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1) {
|
||||
PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1;
|
||||
}
|
||||
}
|
||||
//
|
||||
// NOTE: These values are defaults, and should be verified to be correct in the GenTE utility
|
||||
//
|
||||
PeHdr->OptionalHeader.SectionAlignment = 0x10;
|
||||
|
||||
//
|
||||
// Copy the rest of the image to its original offset
|
||||
//
|
||||
memcpy (
|
||||
TEBuffer + TEImageHeader->StrippedSize,
|
||||
(UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + sizeof (EFI_TE_IMAGE_HEADER),
|
||||
GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -
|
||||
sizeof (EFI_TE_IMAGE_HEADER)
|
||||
);
|
||||
|
||||
//
|
||||
// Initialize context
|
||||
//
|
||||
memset (&ImageContext, 0, sizeof (ImageContext));
|
||||
ImageContext.Handle = (VOID *) TEBuffer;
|
||||
ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
|
||||
|
||||
Status = mPeCoffLoader.GetImageInfo (&mPeCoffLoader, &ImageContext);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);
|
||||
free (TEBuffer);
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// Allocate a buffer for the image to be loaded into.
|
||||
//
|
||||
MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));
|
||||
if (MemoryImagePointer == 0) {
|
||||
Error (NULL, 0, 0, "memory allocation error on rebase of TE image", FileGuidString);
|
||||
free (TEBuffer);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);
|
||||
MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);
|
||||
|
||||
|
||||
ImageContext.ImageAddress = MemoryImagePointerAligned;
|
||||
Status = mPeCoffLoader.LoadImage (&mPeCoffLoader, &ImageContext);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString);
|
||||
free (TEBuffer);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ImageContext.DestinationAddress = NewPe32BaseAddress;
|
||||
Status = mPeCoffLoader.RelocateImage (&mPeCoffLoader, &ImageContext);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
free (TEBuffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ImageAddress = ImageContext.ImageAddress;
|
||||
ImageSize = ImageContext.ImageSize;
|
||||
EntryPoint = ImageContext.EntryPoint;
|
||||
|
||||
//
|
||||
// Since we may have updated the Codeview RVA, we need to insure the PE
|
||||
// header indicates the image is large enough to contain the Codeview data
|
||||
// so it will be loaded properly later if the PEIM is reloaded into memory...
|
||||
//
|
||||
PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);
|
||||
if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {
|
||||
PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);
|
||||
PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);
|
||||
} else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {
|
||||
PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);
|
||||
PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);
|
||||
} else {
|
||||
Error (
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
"unknown machine type in TE image",
|
||||
"machine type=0x%X, file=%s",
|
||||
(UINT32) PeHdr->FileHeader.Machine,
|
||||
FileGuidString
|
||||
);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
free (TEBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
if (*PeHdrSizeOfImage != ImageContext.ImageSize) {
|
||||
*PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;
|
||||
if (*PeHdrChecksum) {
|
||||
*PeHdrChecksum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TEImageHeader->ImageBase = (UINT64) (NewPe32BaseAddress + TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
|
||||
memcpy (
|
||||
(UINT8 *) (CurrentPe32Section.Pe32Section + 1) + sizeof (EFI_TE_IMAGE_HEADER),
|
||||
(VOID *) ((UINT8 *) MemoryImagePointerAligned + TEImageHeader->StrippedSize),
|
||||
GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -
|
||||
sizeof (EFI_TE_IMAGE_HEADER)
|
||||
);
|
||||
free ((VOID *) MemoryImagePointer);
|
||||
free (TEBuffer);
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
|
||||
TailSize = sizeof (EFI_FFS_FILE_TAIL);
|
||||
} else {
|
||||
TailSize = 0;
|
||||
}
|
||||
//
|
||||
// Now update file checksum
|
||||
//
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
|
||||
SavedState = FfsFile->State;
|
||||
FfsFile->IntegrityCheck.Checksum.File = 0;
|
||||
FfsFile->State = 0;
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
|
||||
FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
|
||||
(UINT8 *) FfsFile,
|
||||
GetLength (FfsFile->Size) - TailSize
|
||||
);
|
||||
} else {
|
||||
FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
|
||||
}
|
||||
|
||||
FfsFile->State = SavedState;
|
||||
}
|
||||
//
|
||||
// Update tail if present
|
||||
//
|
||||
if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
|
||||
TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));
|
||||
*(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;
|
||||
}
|
||||
}
|
||||
//
|
||||
// If we found no files, then emit an error if no compressed sections either
|
||||
//
|
||||
if (FoundCount == 0) {
|
||||
Status = GetSectionByType (FfsFile, EFI_SECTION_COMPRESSION, Index, &CurrentPe32Section);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Error (NULL, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user