mirror of https://github.com/acidanthera/audk.git
1018 lines
28 KiB
C
1018 lines
28 KiB
C
/*++
|
|
|
|
Copyright (c) 1999-2006 Intel Corporation. All rights reserved
|
|
This program and the accompanying materials are licensed and made available
|
|
under the terms and conditions of the BSD License which accompanies this
|
|
distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
|
|
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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <Common/UefiBaseTypes.h>
|
|
#include <Common/FirmwareVolumeImageFormat.h>
|
|
#include <Common/FirmwareFileSystem.h>
|
|
#include <Library/PeCoffLib.h>
|
|
|
|
#include "CommonLib.h"
|
|
#include "ParseInf.h"
|
|
#include "FvLib.h"
|
|
#include "EfiUtilityMsgs.h"
|
|
#include "PeiRebaseExe.h"
|
|
|
|
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;
|
|
EFI_PHYSICAL_ADDRESS XipBase, BsBase, RtBase;
|
|
UINT32 BaseTypes;
|
|
EFI_STATUS Status;
|
|
FILE *InputFile;
|
|
FILE *OutputFile;
|
|
FILE *LogFile;
|
|
UINT64 FvOffset;
|
|
UINT32 FileCount;
|
|
int BytesRead;
|
|
EFI_FIRMWARE_VOLUME_HEADER *FvImage;
|
|
UINT32 FvSize;
|
|
EFI_FFS_FILE_HEADER *CurrentFile;
|
|
BOOLEAN ErasePolarity;
|
|
MEMORY_FILE InfMemoryFile;
|
|
CHAR8 StringBuffer[0x100];
|
|
|
|
ErasePolarity = FALSE;
|
|
//
|
|
// Set utility name for error/warning reporting purposes.
|
|
//
|
|
SetUtilityName (UTILITY_NAME);
|
|
|
|
if (argc == 1) {
|
|
Usage();
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
|
|
(strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
|
|
Usage();
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
|
|
Version();
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
//
|
|
// Verify the correct number of arguments
|
|
//
|
|
if (argc != MAX_ARGS) {
|
|
Usage ();
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
//
|
|
// Initialize variables
|
|
//
|
|
InputFileName[0] = '\0';
|
|
OutputFileName = NULL;
|
|
XipBase = BsBase = RtBase = 0;
|
|
BaseTypes = 0;
|
|
FvOffset = 0;
|
|
FileCount = 0;
|
|
ErasePolarity = FALSE;
|
|
InputFile = NULL;
|
|
OutputFile = NULL;
|
|
LogFile = 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] != '/') {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index], "unrecognized option");
|
|
return STATUS_ERROR;
|
|
}
|
|
//
|
|
// Make sure argument specifier is only one letter
|
|
//
|
|
if (argv[Index][2] != 0) {
|
|
Usage ();
|
|
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 {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified");
|
|
return STATUS_ERROR;
|
|
}
|
|
break;
|
|
|
|
case 'O':
|
|
case 'o':
|
|
if (OutputFileName == NULL) {
|
|
OutputFileName = argv[Index + 1];
|
|
} else {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified");
|
|
return STATUS_ERROR;
|
|
}
|
|
break;
|
|
|
|
case 'F':
|
|
case 'f':
|
|
//
|
|
// Load INF file into memory & initialize MEMORY_FILE structure
|
|
//
|
|
Status = GetFileImage (argv[Index + 1], &InfMemoryFile.FileImage, (UINT32*)&InfMemoryFile.Eof);
|
|
InfMemoryFile.Eof = InfMemoryFile.FileImage + (UINT32)(UINTN)InfMemoryFile.Eof;
|
|
InfMemoryFile.CurrentFilePointer = InfMemoryFile.FileImage;
|
|
if (EFI_ERROR (Status)) {
|
|
Error (NULL, 0, 0, argv[Index + 1], "Error opening FvInfFile");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
//
|
|
// Read BaseAddress from fv.inf file
|
|
//
|
|
FindToken (&InfMemoryFile, "[options]", "EFI_BASE_ADDRESS", 0, StringBuffer);
|
|
|
|
//
|
|
// Free INF file image
|
|
//
|
|
free (InfMemoryFile.FileImage);
|
|
|
|
//
|
|
// Point argv[Index + 1] to StringBuffer so that it could be processed as "-b"
|
|
//
|
|
argv[Index + 1] = StringBuffer;
|
|
|
|
case 'B':
|
|
case 'b':
|
|
if (BaseTypes & 1) {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "XipBaseAddress may be specified only once by either -b or -f");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &XipBase);
|
|
if (EFI_ERROR (Status)) {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for XIP base address");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
BaseTypes |= 1;
|
|
break;
|
|
|
|
case 'D':
|
|
case 'd':
|
|
if (BaseTypes & 2) {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "-d BsBaseAddress may be specified only once");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BsBase);
|
|
if (EFI_ERROR (Status)) {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for BS_DRIVER base address");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
BaseTypes |= 2;
|
|
break;
|
|
|
|
case 'R':
|
|
case 'r':
|
|
if (BaseTypes & 4) {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "-r RtBaseAddress may be specified only once");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &RtBase);
|
|
if (EFI_ERROR (Status)) {
|
|
Usage ();
|
|
Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for RT_DRIVER base address");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
BaseTypes |= 4;
|
|
break;
|
|
|
|
default:
|
|
Usage ();
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Open the log file
|
|
//
|
|
strcat (InputFileName, ".log");
|
|
LogFile = fopen (InputFileName, "a");
|
|
if (LogFile == NULL) {
|
|
Error (NULL, 0, 0, InputFileName, "could not append to log file");
|
|
}
|
|
|
|
//
|
|
// 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
|
|
//
|
|
FfsRebase (
|
|
CurrentFile,
|
|
BaseTypes,
|
|
XipBase + (UINTN)CurrentFile - (UINTN)FvImage,
|
|
&BsBase,
|
|
&RtBase,
|
|
LogFile
|
|
);
|
|
|
|
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 (LogFile != NULL) {
|
|
fclose (LogFile);
|
|
}
|
|
|
|
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
|
|
Version (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the standard utility information to SDTOUT
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
printf ("%s v%d.%d -PEI Rebase Utility.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
|
|
printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");
|
|
}
|
|
|
|
VOID
|
|
Usage (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the utility usage syntax to STDOUT
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
Version();
|
|
|
|
printf (
|
|
"Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-F InputFvInfName]\n",
|
|
UTILITY_NAME
|
|
);
|
|
printf (" [-D BootDriverBaseAddress] [-R RuntimeDriverBaseAddress]\n");
|
|
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 rebase address for all drivers run in Flash.\n");
|
|
printf (" InputFvInfName is the Fv.inf file that contains this FV base address to rebase against.\n");
|
|
printf (" BootDriverBaseAddress is the rebase address for all boot drivers in this fv image.\n");
|
|
printf (" RuntimeDriverBaseAddress is the rebase address for all runtime drivers in this fv image.\n");
|
|
printf (" Argument pair may be in any order.\n\n");
|
|
}
|
|
|
|
EFI_STATUS
|
|
FfsRebase (
|
|
IN OUT EFI_FFS_FILE_HEADER *FfsFile,
|
|
IN UINT32 Flags,
|
|
IN OUT EFI_PHYSICAL_ADDRESS XipBase,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *BsBase,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *RtBase,
|
|
OUT FILE *LogFile
|
|
)
|
|
/*++
|
|
|
|
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;
|
|
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
|
EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;
|
|
UINTN Index;
|
|
EFI_FILE_SECTION_POINTER CurrentPe32Section;
|
|
EFI_FFS_FILE_STATE SavedState;
|
|
EFI_IMAGE_NT_HEADERS32 *PeHdr;
|
|
EFI_TE_IMAGE_HEADER *TEImageHeader;
|
|
UINT8 FileGuidString[80];
|
|
UINT32 TailSize;
|
|
EFI_FFS_FILE_TAIL TailValue;
|
|
EFI_PHYSICAL_ADDRESS *BaseToUpdate;
|
|
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
default:
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Rebase each PE32 section
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
for (Index = 1;; Index++) {
|
|
Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize context
|
|
//
|
|
memset (&ImageContext, 0, sizeof (ImageContext));
|
|
ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));
|
|
ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
|
|
Status = PeCoffLoaderGetImageInfo (&ImageContext);
|
|
if (EFI_ERROR (Status)) {
|
|
Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Don't Load PeImage, only to relocate current image.
|
|
//
|
|
ImageContext.ImageAddress = (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION);
|
|
|
|
//
|
|
// Check if section-alignment and file-alignment match or not
|
|
//
|
|
PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);
|
|
if (PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment) {
|
|
//
|
|
// Nor XIP module can be ignored.
|
|
//
|
|
if ((Flags & 1) == 0) {
|
|
continue;
|
|
}
|
|
Error (NULL, 0, 0, "Section-Alignment and File-Alignment does not match", FileGuidString);
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
//
|
|
// Update CodeView and PdbPointer in ImageContext
|
|
//
|
|
DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
|
|
ImageContext.ImageAddress +
|
|
ImageContext.DebugDirectoryEntryRva
|
|
);
|
|
ImageContext.CodeView = (VOID *)(UINTN)(
|
|
ImageContext.ImageAddress +
|
|
DebugEntry->RVA
|
|
);
|
|
switch (*(UINT32 *) ImageContext.CodeView) {
|
|
case CODEVIEW_SIGNATURE_NB10:
|
|
ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
|
|
break;
|
|
|
|
case CODEVIEW_SIGNATURE_RSDS:
|
|
ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// 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:
|
|
if ((Flags & 1) == 0) {
|
|
//
|
|
// We aren't relocating XIP code, so skip it.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
NewPe32BaseAddress =
|
|
XipBase + (UINTN)ImageContext.ImageAddress - (UINTN)FfsFile;
|
|
BaseToUpdate = &XipBase;
|
|
break;
|
|
|
|
case EFI_FV_FILETYPE_DRIVER:
|
|
PeHdr = (EFI_IMAGE_NT_HEADERS32*)(ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);
|
|
switch (PeHdr->OptionalHeader.Subsystem) {
|
|
case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
|
|
if ((Flags & 4) == 0) {
|
|
//
|
|
// RT drivers aren't supposed to be relocated
|
|
//
|
|
continue;
|
|
}
|
|
|
|
NewPe32BaseAddress = *RtBase;
|
|
BaseToUpdate = RtBase;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// We treat all other subsystems the same as BS_DRIVER
|
|
//
|
|
if ((Flags & 2) == 0) {
|
|
//
|
|
// Skip all BS_DRIVER's
|
|
//
|
|
continue;
|
|
}
|
|
|
|
NewPe32BaseAddress = *BsBase;
|
|
BaseToUpdate = BsBase;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case EFI_FV_FILETYPE_DXE_CORE:
|
|
if ((Flags & 2) == 0) {
|
|
//
|
|
// Skip DXE core
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
NewPe32BaseAddress = *BsBase;
|
|
BaseToUpdate = BsBase;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Not supported file type
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
ImageContext.DestinationAddress = NewPe32BaseAddress;
|
|
Status = PeCoffLoaderRelocateImage (&ImageContext);
|
|
if (EFI_ERROR (Status)) {
|
|
Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Update BASE address
|
|
//
|
|
fprintf (
|
|
LogFile,
|
|
"%s %016I64X %s\n",
|
|
FileGuidString,
|
|
ImageContext.DestinationAddress,
|
|
ImageContext.PdbPointer == NULL ? "*" : ImageContext.PdbPointer
|
|
);
|
|
*BaseToUpdate += EFI_SIZE_TO_PAGES (ImageContext.ImageSize) * EFI_PAGE_SIZE;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
if ((Flags & 1) == 0 || (
|
|
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
|
|
)) {
|
|
//
|
|
// Only XIP code may have a TE section
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Now process TE sections
|
|
//
|
|
for (Index = 1;; Index++) {
|
|
Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// 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));
|
|
|
|
//
|
|
// 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, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);
|
|
return Status;
|
|
}
|
|
//
|
|
// Don't reload TeImage
|
|
//
|
|
ImageContext.ImageAddress = (UINTN) TEImageHeader;
|
|
|
|
//
|
|
// Update CodeView and PdbPointer in ImageContext
|
|
//
|
|
DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
|
|
ImageContext.ImageAddress +
|
|
ImageContext.DebugDirectoryEntryRva +
|
|
sizeof(EFI_TE_IMAGE_HEADER) -
|
|
TEImageHeader->StrippedSize
|
|
);
|
|
|
|
ImageContext.CodeView = (VOID *)(UINTN)(
|
|
ImageContext.ImageAddress +
|
|
DebugEntry->RVA +
|
|
sizeof(EFI_TE_IMAGE_HEADER) -
|
|
TEImageHeader->StrippedSize
|
|
);
|
|
|
|
switch (*(UINT32 *) ImageContext.CodeView) {
|
|
case CODEVIEW_SIGNATURE_NB10:
|
|
ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
|
|
break;
|
|
|
|
case CODEVIEW_SIGNATURE_RSDS:
|
|
ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Reloacate TeImage
|
|
//
|
|
ImageContext.DestinationAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
|
|
- TEImageHeader->StrippedSize - (UINTN) FfsFile;
|
|
Status = PeCoffLoaderRelocateImage (&ImageContext);
|
|
if (EFI_ERROR (Status)) {
|
|
Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);
|
|
return Status;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
fprintf (
|
|
LogFile,
|
|
"%s %016I64X %s\n",
|
|
FileGuidString,
|
|
ImageContext.DestinationAddress,
|
|
ImageContext.PdbPointer == NULL ? "*" : ImageContext.PdbPointer
|
|
);
|
|
}
|
|
|
|
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;
|
|
}
|