diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFw/GenFw.c | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFw/GenFw.c | 3255 |
1 files changed, 3255 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFw/GenFw.c b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFw/GenFw.c new file mode 100644 index 00000000..4faf329b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFw/GenFw.c @@ -0,0 +1,3255 @@ +/** @file +Converts a pe32+ image to an FW, Te image type, or other specific image. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "WinNtInclude.h" + +#ifndef __GNUC__ +#include <windows.h> +#include <io.h> +#include <sys/types.h> +#include <sys/stat.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> + +#include <Common/UefiBaseTypes.h> +#include <IndustryStandard/PeImage.h> +#include <Common/UefiInternalFormRepresentation.h> + +// +// Acpi Table definition +// +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Acpi1_0.h> +#include <IndustryStandard/Acpi2_0.h> +#include <IndustryStandard/Acpi3_0.h> +#include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h> + +#include "CommonLib.h" +#include "PeCoffLib.h" +#include "ParseInf.h" +#include "EfiUtilityMsgs.h" + +#include "GenFw.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wlogical-op" +#endif + +// +// Version of this utility +// +#define UTILITY_NAME "GenFw" +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 2 + +#define HII_RESOURCE_SECTION_INDEX 1 +#define HII_RESOURCE_SECTION_NAME "HII" + +#define DEFAULT_MC_PAD_BYTE_VALUE 0xFF +#define DEFAULT_MC_ALIGNMENT 16 + +#define STATUS_IGNORE 0xA +// +// Structure definition for a microcode header +// +typedef struct { + UINT32 HeaderVersion; + UINT32 PatchId; + UINT32 Date; + UINT32 CpuId; + UINT32 Checksum; + UINT32 LoaderVersion; + UINT32 PlatformId; + UINT32 DataSize; // if 0, then TotalSize = 2048, and TotalSize field is invalid + UINT32 TotalSize; // number of bytes + UINT32 Reserved[3]; +} MICROCODE_IMAGE_HEADER; + +static EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + +static const char *gHiiPackageRCFileHeader[] = { + "//", + "// DO NOT EDIT -- auto-generated file", + "//", + NULL +}; + +// +// Module image information +// +CHAR8 *mInImageName; +UINT32 mImageTimeStamp = 0; +UINT32 mImageSize = 0; +UINT32 mOutImageType = FW_DUMMY_IMAGE; +BOOLEAN mIsConvertXip = FALSE; + + +STATIC +EFI_STATUS +ZeroDebugData ( + IN OUT UINT8 *FileBuffer, + BOOLEAN ZeroDebug + ); + +STATIC +EFI_STATUS +SetStamp ( + IN OUT UINT8 *FileBuffer, + IN CHAR8 *TimeStamp + ); + +STATIC +STATUS +MicrocodeReadData ( + FILE *InFptr, + UINT32 *Data + ); + +STATIC +VOID +Version ( + VOID + ) +/*++ + +Routine Description: + + Print out version information for this utility. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); +} + +STATIC +VOID +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print Help message. + +Arguments: + + VOID + +Returns: + + None + +--*/ +{ + // + // Summary usage + // + fprintf (stdout, "\nUsage: %s [options] <input_file>\n\n", UTILITY_NAME); + + // + // Copyright declaration + // + fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n"); + + // + // Details Option + // + fprintf (stdout, "Options:\n"); + fprintf (stdout, " -o FileName, --outputfile FileName\n\ + File will be created to store the output content.\n"); + fprintf (stdout, " -e EFI_FILETYPE, --efiImage EFI_FILETYPE\n\ + Create Efi Image. EFI_FILETYPE is one of BASE,SMM_CORE,\n\ + PEI_CORE, PEIM, DXE_CORE, DXE_DRIVER, UEFI_APPLICATION,\n\ + SEC, DXE_SAL_DRIVER, UEFI_DRIVER, DXE_RUNTIME_DRIVER,\n\ + DXE_SMM_DRIVER, SECURITY_CORE, COMBINED_PEIM_DRIVER,\n\ + MM_STANDALONE, MM_CORE_STANDALONE,\n\ + PIC_PEIM, RELOCATABLE_PEIM, BS_DRIVER, RT_DRIVER,\n\ + APPLICATION, SAL_RT_DRIVER to support all module types\n\ + It can only be used together with --keepexceptiontable,\n\ + --keepzeropending, --keepoptionalheader, -r, -o option.\n\ + It is a action option. If it is combined with other action options,\n\ + the later input action option will override the previous one.\n"); + fprintf (stdout, " -c, --acpi Create Acpi table.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -t, --terse Create Te Image.\n\ + It can only be used together with --keepexceptiontable,\n\ + --keepzeropending, --keepoptionalheader, -r, -o option.\n\ + It is a action option. If it is combined with other action options,\n\ + the later input action option will override the previous one.\n"); + fprintf (stdout, " -u, --dump Dump TeImage Header.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -z, --zero Zero the Debug Data Fields in the PE input image file.\n\ + It also zeros the time stamp fields.\n\ + This option can be used to compare the binary efi image.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -b, --exe2bin Convert the input EXE to the output BIN file.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n");; + fprintf (stdout, " -l, --stripped Strip off the relocation info from PE or TE image.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -s timedate, --stamp timedate\n\ + timedate format is \"yyyy-mm-dd 00:00:00\". if timedata \n\ + is set to NOW, current system time is used. The support\n\ + date scope is 1970-01-01 00+timezone:00:00\n\ + ~ 2038-01-19 03+timezone:14:07\n\ + The scope is adjusted according to the different zones.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -m, --mcifile Convert input microcode txt file to microcode bin file.\n\ + It can't be combined with other action options\n\ + except for -o option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -j, --join Combine multi microcode bin files to one file.\n\ + It can be specified with -a, -p, -o option.\n\ + No other options can be combined with it.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -a NUM, --align NUM NUM is one HEX or DEC format alignment value.\n\ + This option is only used together with -j option.\n"); + fprintf (stdout, " -p NUM, --pad NUM NUM is one HEX or DEC format padding value.\n\ + This option is only used together with -j option.\n"); + fprintf (stdout, " --keepexceptiontable Don't clear exception table.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " --keepoptionalheader Don't zero PE/COFF optional header fields.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " --keepzeropending Don't strip zero pending of .reloc.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " -r, --replace Overwrite the input file with the output content.\n\ + If more input files are specified,\n\ + the last input file will be as the output file.\n"); + fprintf (stdout, " -g HiiPackageListGuid, --hiiguid HiiPackageListGuid\n\ + Guid is used to specify hii package list guid.\n\ + Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n\ + If not specified, the first Form FormSet guid is used.\n"); + fprintf (stdout, " --hiipackage Combine all input binary hii packages into \n\ + a single package list as the text resource data(RC).\n\ + It can't be combined with other action options\n\ + except for -o option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --hiibinpackage Combine all input binary hii packages into \n\ + a single package list as the binary resource section.\n\ + It can't be combined with other action options\n\ + except for -o option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --rebase NewAddress Rebase image to new base address. New address \n\ + is also set to the first none code section header.\n\ + It can't be combined with other action options\n\ + except for -o or -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --address NewAddress Set new address into the first none code \n\ + section header of the input image.\n\ + It can't be combined with other action options\n\ + except for -o or -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n"); + fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n"); + fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n"); + fprintf (stdout, " --version Show program's version number and exit\n"); + fprintf (stdout, " -h, --help Show this help message and exit\n"); +} + +STATIC +STATUS +CheckAcpiTable ( + VOID *AcpiTable, + UINT32 Length + ) +/*++ + +Routine Description: + + Check Acpi Table + +Arguments: + + AcpiTable Buffer for AcpiSection + Length AcpiSection Length + +Returns: + + 0 success + non-zero otherwise + +--*/ +{ + EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader; + EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + UINT32 ExpectedLength; + + AcpiHeader = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable; + + // + // Generic check for AcpiTable length. + // + if (AcpiHeader->Length > Length) { + Error (NULL, 0, 3000, "Invalid", "AcpiTable length check failed.", NULL); + return STATUS_ERROR; + } + + // + // Currently, we only check must-have tables: FADT, FACS, DSDT, + // and some important tables: MADT, MCFG. + // + switch (AcpiHeader->Signature) { + + // + // "FACP" Fixed ACPI Description Table + // + case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE: + switch (AcpiHeader->Revision) { + case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION: + ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE); + break; + case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION: + ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE); + break; + case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION: + ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE); + break; + default: + if (AcpiHeader->Revision > EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) { + ExpectedLength = AcpiHeader->Length; + break; + } + Error (NULL, 0, 3000, "Invalid", "FACP revision check failed."); + return STATUS_ERROR; + } + if (ExpectedLength != AcpiHeader->Length) { + Error (NULL, 0, 3000, "Invalid", "FACP length check failed."); + return STATUS_ERROR; + } + break; + + // + // "FACS" Firmware ACPI Control Structure + // + case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE: + Facs = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable; + if (Facs->Version > EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) { + break; + } + if ((Facs->Version != EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && + (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && + (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)){ + Error (NULL, 0, 3000, "Invalid", "FACS version check failed."); + return STATUS_ERROR; + } + if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) && + (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) && + (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) { + Error (NULL, 0, 3000, "Invalid", "FACS length check failed."); + return STATUS_ERROR; + } + break; + + // + // "DSDT" Differentiated System Description Table + // + case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: + if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) { + break; + } + if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) { + Error (NULL, 0, 3000, "Invalid", "DSDT length check failed."); + return STATUS_ERROR; + } + break; + + // + // "APIC" Multiple APIC Description Table + // + case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE: + if (AcpiHeader->Revision > EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) { + break; + } + if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) && + (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) && + (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) { + Error (NULL, 0, 3000, "Invalid", "APIC revision check failed."); + return STATUS_ERROR; + } + if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32)) { + Error (NULL, 0, 3000, "Invalid", "APIC length check failed."); + return STATUS_ERROR; + } + break; + + // + // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table + // + case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE: + if (AcpiHeader->Revision > EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) { + break; + } + if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) { + Error (NULL, 0, 3000, "Invalid", "MCFG revision check failed."); + return STATUS_ERROR; + } + if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64)) { + Error (NULL, 0, 3000, "Invalid", "MCFG length check failed."); + return STATUS_ERROR; + } + break; + + // + // Other table pass check + // + default: + break; + } + + return STATUS_SUCCESS; +} + +VOID +SetHiiResourceHeader ( + UINT8 *HiiBinData, + UINT32 OffsetToFile + ) +{ + UINT32 Index; + EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString; + EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry; + + // + // Fill Resource section entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiBinData); + ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1); + for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index ++) { + if (ResourceDirectoryEntry->u1.s.NameIsString) { + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiBinData + ResourceDirectoryEntry->u1.s.NameOffset); + + if (ResourceDirectoryString->Length == 3 && + ResourceDirectoryString->String[0] == L'H' && + ResourceDirectoryString->String[1] == L'I' && + ResourceDirectoryString->String[2] == L'I') { + // + // Resource Type "HII" found + // + if (ResourceDirectoryEntry->u2.s.DataIsDirectory) { + // + // Move to next level - resource Name + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiBinData + ResourceDirectoryEntry->u2.s.OffsetToDirectory); + ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1); + + if (ResourceDirectoryEntry->u2.s.DataIsDirectory) { + // + // Move to next level - resource Language + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiBinData + ResourceDirectoryEntry->u2.s.OffsetToDirectory); + ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1); + } + } + + // + // Now it ought to be resource Data and update its OffsetToData value + // + if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) { + ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (HiiBinData + ResourceDirectoryEntry->u2.OffsetToData); + ResourceDataEntry->OffsetToData = ResourceDataEntry->OffsetToData + OffsetToFile; + break; + } + } + } + ResourceDirectoryEntry++; + } + + return; +} + +EFI_IMAGE_OPTIONAL_HEADER_UNION * +GetPeCoffHeader ( + void *Data + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + + // + // Read the dos & pe hdrs of the image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)Data; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, check for PE/COFF header + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(Data); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + return NULL; + } + } else { + + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(((UINT8 *)Data) + DosHdr->e_lfanew); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + return NULL; + } + } + + return PeHdr; +} + +void +PeCoffConvertImageToXip ( + UINT8 **FileBuffer, + UINT32 *FileLength + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NewPeHdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN TotalNecessaryFileSize; + UINTN SectionSize; + UINT8 *XipFile; + UINT32 XipLength; + UINTN Index; + UINTN FirstSectionOffset; + BOOLEAN ConversionNeeded; + + PeHdr = GetPeCoffHeader ((void *) *FileBuffer); + if (PeHdr == NULL) { + return; + } + + if (PeHdr->Pe32.OptionalHeader.SectionAlignment != PeHdr->Pe32.OptionalHeader.FileAlignment) { + // + // The only reason to expand zero fill sections is to make them compatible with XIP images. + // If SectionAlignment is not equal to FileAlignment then it is not an XIP type image. + // + return; + } + + // + // Calculate size of XIP file, and determine if the conversion is needed. + // + ConversionNeeded = FALSE; + XipLength = 0; + FirstSectionOffset = *FileLength; + TotalNecessaryFileSize = 0; + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + SectionSize = MAX (SectionHeader->Misc.VirtualSize, SectionHeader->SizeOfRawData); + TotalNecessaryFileSize += SectionSize; + if (SectionSize > 0) { + FirstSectionOffset = MIN (FirstSectionOffset, SectionHeader->VirtualAddress); + XipLength = MAX (XipLength, SectionHeader->VirtualAddress + SectionSize); + if (SectionHeader->VirtualAddress != SectionHeader->PointerToRawData) { + ConversionNeeded = TRUE; + } + } + if (SectionHeader->Misc.VirtualSize > SectionHeader->SizeOfRawData) { + ConversionNeeded = TRUE; + } + } + + if (FirstSectionOffset < PeHdr->Pe32.OptionalHeader.SizeOfHeaders) { + // + // If one of the sections should be loaded to an offset overlapping with + // the executable header, then it cannot be made into an XIP image. + // + VerboseMsg ("PE/COFF conversion to XIP is impossible due to overlap"); + VerboseMsg ("of section data with the executable header."); + return; + } + + if (FirstSectionOffset == *FileLength) { + // + // If we never found a section with a non-zero size, then we + // skip the conversion. + // + return; + } + + TotalNecessaryFileSize += FirstSectionOffset; + + if (!ConversionNeeded) { + return; + } + + if (XipLength > (2 * TotalNecessaryFileSize)) { + VerboseMsg ("PE/COFF conversion to XIP appears to be larger than necessary."); + VerboseMsg ("The image linking process may have left unused memory ranges."); + } + + if (PeHdr->Pe32.FileHeader.PointerToSymbolTable != 0) { + // + // This field is obsolete and should be zero + // + PeHdr->Pe32.FileHeader.PointerToSymbolTable = 0; + } + + // + // Allocate the extra space that we need to grow the image + // + XipFile = malloc (XipLength); + if (XipFile == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + return; + } + memset (XipFile, 0, XipLength); + + // + // Copy the file headers + // + memcpy (XipFile, *FileBuffer, PeHdr->Pe32.OptionalHeader.SizeOfHeaders); + + NewPeHdr = GetPeCoffHeader ((void *)XipFile); + if (NewPeHdr == NULL) { + free (XipFile); + return; + } + + // + // Copy the section data over to the appropriate XIP offsets + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(NewPeHdr->Pe32.OptionalHeader) + NewPeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if (SectionHeader->SizeOfRawData > 0) { + memcpy ( + XipFile + SectionHeader->VirtualAddress, + *FileBuffer + SectionHeader->PointerToRawData, + SectionHeader->SizeOfRawData + ); + } + // + // Make the size of raw data in section header alignment. + // + SectionSize = (SectionHeader->Misc.VirtualSize + PeHdr->Pe32.OptionalHeader.FileAlignment - 1) & (~(PeHdr->Pe32.OptionalHeader.FileAlignment - 1)); + if (SectionSize < SectionHeader->SizeOfRawData) { + SectionHeader->SizeOfRawData = SectionSize; + } + + SectionHeader->PointerToRawData = SectionHeader->VirtualAddress; + } + + free (*FileBuffer); + *FileLength = XipLength; + *FileBuffer = XipFile; + + mIsConvertXip = TRUE; +} + +UINT8 * +CreateHiiResouceSectionHeader ( + UINT32 *pSectionHeaderSize, + UINT32 HiiDataSize + ) +/*++ + +Routine Description: + + Create COFF resource section header + +Arguments: + + pSectionHeaderSize - Pointer to section header size. + HiiDataSize - Size of the total HII data in section. + +Returns: + The created section header buffer. + +--*/ +{ + UINT32 HiiSectionHeaderSize; + UINT32 HiiSectionOffset; + UINT8 *HiiSectionHeader; + EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *TypeResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *NameResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *LanguageResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString; + EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry; + + // + // Calculate the total size for the resource header (include Type, Name and Language) + // then allocate memory for the resource header. + // + HiiSectionHeaderSize = 3 * (sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY)) + + 3 * (sizeof (UINT16) + 3 * sizeof (CHAR16)) + + sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY); + HiiSectionHeader = malloc (HiiSectionHeaderSize); + if (HiiSectionHeader == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + return NULL; + } + memset (HiiSectionHeader, 0, HiiSectionHeaderSize); + + HiiSectionOffset = 0; + // + // Create Type entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY); + ResourceDirectory->NumberOfNamedEntries = 1; + TypeResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY); + TypeResourceDirectoryEntry->u1.s.NameIsString = 1; + TypeResourceDirectoryEntry->u2.s.DataIsDirectory = 1; + TypeResourceDirectoryEntry->u2.s.OffsetToDirectory = HiiSectionOffset; + // + // Create Name entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY); + ResourceDirectory->NumberOfNamedEntries = 1; + NameResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY); + NameResourceDirectoryEntry->u1.s.NameIsString = 1; + NameResourceDirectoryEntry->u2.s.DataIsDirectory = 1; + NameResourceDirectoryEntry->u2.s.OffsetToDirectory = HiiSectionOffset; + // + // Create Language entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY); + ResourceDirectory->NumberOfNamedEntries = 1; + LanguageResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY); + LanguageResourceDirectoryEntry->u1.s.NameIsString = 1; + // + // Create string entry for Type + // + TypeResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset; + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset); + ResourceDirectoryString->Length = 3; + ResourceDirectoryString->String[0] = L'H'; + ResourceDirectoryString->String[1] = L'I'; + ResourceDirectoryString->String[2] = L'I'; + HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]); + // + // Create string entry for Name + // + NameResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset; + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset); + ResourceDirectoryString->Length = 3; + ResourceDirectoryString->String[0] = L'E'; + ResourceDirectoryString->String[1] = L'F'; + ResourceDirectoryString->String[2] = L'I'; + HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]); + // + // Create string entry for Language + // + LanguageResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset; + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset); + ResourceDirectoryString->Length = 3; + ResourceDirectoryString->String[0] = L'B'; + ResourceDirectoryString->String[1] = L'I'; + ResourceDirectoryString->String[2] = L'N'; + HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]); + // + // Create Leaf data + // + LanguageResourceDirectoryEntry->u2.OffsetToData = HiiSectionOffset; + ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY); + ResourceDataEntry->OffsetToData = HiiSectionOffset; + ResourceDataEntry->Size = HiiDataSize; + + *pSectionHeaderSize = HiiSectionHeaderSize; + return HiiSectionHeader; +} + +EFI_STATUS +RebaseImageRead ( + 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 +SetAddressToSectionHeader ( + IN CHAR8 *FileName, + IN OUT UINT8 *FileBuffer, + IN UINT64 NewPe32BaseAddress + ) +/*++ + +Routine Description: + + Set new base address into the section header of PeImage + +Arguments: + + FileName - Name of file + FileBuffer - Pointer to PeImage. + NewPe32BaseAddress - New Base Address for PE image. + +Returns: + + EFI_SUCCESS Set new base address into this image successfully. + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINTN Index; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + + // + // Initialize context + // + memset (&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead; + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName); + return Status; + } + + if (ImageContext.RelocationsStripped) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName); + return Status; + } + + // + // Get PeHeader pointer + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset); + + // + // Get section header list + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN) ImgHdr + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + // + // Set base address into the first section header that doesn't point to code section. + // + for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { + *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress; + break; + } + } + + // + // BaseAddress is set to section header. + // + return EFI_SUCCESS; +} + +EFI_STATUS +RebaseImage ( + IN CHAR8 *FileName, + IN OUT UINT8 *FileBuffer, + IN UINT64 NewPe32BaseAddress + ) +/*++ + +Routine Description: + + Set new base address into PeImage, and fix up PeImage based on new address. + +Arguments: + + FileName - Name of file + FileBuffer - Pointer to PeImage. + NewPe32BaseAddress - New Base Address for PE image. + +Returns: + + EFI_INVALID_PARAMETER - BaseAddress is not valid. + EFI_SUCCESS - Update PeImage is correctly. + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINTN Index; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + UINT8 *MemoryImagePointer; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + + // + // Initialize context + // + memset (&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead; + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName); + return Status; + } + + if (ImageContext.RelocationsStripped) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName); + return Status; + } + + // + // Get PeHeader pointer + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset); + + // + // 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) & (~((INT64)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 ( + FileBuffer + SectionHeader->PointerToRawData, + (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), + SectionHeader->SizeOfRawData < SectionHeader->Misc.VirtualSize ? SectionHeader->SizeOfRawData : SectionHeader->Misc.VirtualSize + ); + } + + free ((VOID *) MemoryImagePointer); + + // + // 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; + } + + // + // Set new base address into section header + // + Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress); + + return Status; +} + +int +main ( + int argc, + char *argv[] + ) +/*++ + +Routine Description: + + Main function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to command line parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + UINT32 Type; + UINT32 InputFileNum; + CHAR8 **InputFileName; + char *OutImageName; + char *ModuleType; + CHAR8 *TimeStamp; + FILE *fpIn; + FILE *fpOut; + FILE *fpInOut; + UINT32 Data; + UINT32 *DataPointer; + UINT32 *OldDataPointer; + UINT32 CheckSum; + UINT32 Index; + UINT32 Index1; + UINT32 Index2; + UINT64 Temp64; + UINT32 MciAlignment; + UINT8 MciPadValue; + UINT32 AllignedRelocSize; + UINT8 *FileBuffer; + UINT32 FileLength; + UINT8 *OutputFileBuffer; + UINT32 OutputFileLength; + UINT8 *InputFileBuffer; + UINT32 InputFileLength; + RUNTIME_FUNCTION *RuntimeFunction; + UNWIND_INFO *UnwindInfo; + STATUS Status; + BOOLEAN ReplaceFlag; + BOOLEAN KeepExceptionTableFlag; + BOOLEAN KeepOptionalHeaderFlag; + BOOLEAN KeepZeroPendingFlag; + UINT64 LogLevel; + EFI_TE_IMAGE_HEADER TEImageHeader; + EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64; + EFI_IMAGE_DOS_HEADER BackupDosHdr; + MICROCODE_IMAGE_HEADER *MciHeader; + UINT8 *HiiPackageListBuffer; + UINT8 *HiiPackageDataPointer; + EFI_GUID HiiPackageListGuid; + EFI_HII_PACKAGE_LIST_HEADER HiiPackageListHeader; + EFI_HII_PACKAGE_HEADER HiiPackageHeader; + EFI_IFR_FORM_SET IfrFormSet; + UINT8 NumberOfFormPackage; + EFI_HII_PACKAGE_HEADER EndPackage; + UINT32 HiiSectionHeaderSize; + UINT8 *HiiSectionHeader; + UINT64 NewBaseAddress; + BOOLEAN NegativeAddr; + FILE *ReportFile; + CHAR8 *ReportFileName; + UINTN FileLen; + time_t InputFileTime; + time_t OutputFileTime; + struct stat Stat_Buf; + BOOLEAN ZeroDebugFlag; + + SetUtilityName (UTILITY_NAME); + + // + // Assign to fix compile warning + // + FileLen = 0; + InputFileNum = 0; + InputFileName = NULL; + mInImageName = NULL; + OutImageName = NULL; + ModuleType = NULL; + Type = 0; + Status = STATUS_SUCCESS; + FileBuffer = NULL; + fpIn = NULL; + fpOut = NULL; + fpInOut = NULL; + TimeStamp = NULL; + MciAlignment = DEFAULT_MC_ALIGNMENT; + MciPadValue = DEFAULT_MC_PAD_BYTE_VALUE; + FileLength = 0; + MciHeader = NULL; + CheckSum = 0; + ReplaceFlag = FALSE; + LogLevel = 0; + OutputFileBuffer = NULL; + OutputFileLength = 0; + InputFileBuffer = NULL; + InputFileLength = 0; + Optional32 = NULL; + Optional64 = NULL; + KeepExceptionTableFlag = FALSE; + KeepOptionalHeaderFlag = FALSE; + KeepZeroPendingFlag = FALSE; + NumberOfFormPackage = 0; + HiiPackageListBuffer = NULL; + HiiPackageDataPointer = NULL; + EndPackage.Length = sizeof (EFI_HII_PACKAGE_HEADER); + EndPackage.Type = EFI_HII_PACKAGE_END; + memset (&HiiPackageListGuid, 0, sizeof (HiiPackageListGuid)); + HiiSectionHeaderSize = 0; + HiiSectionHeader = NULL; + NewBaseAddress = 0; + NegativeAddr = FALSE; + InputFileTime = 0; + OutputFileTime = 0; + ZeroDebugFlag = FALSE; + + if (argc == 1) { + Error (NULL, 0, 1001, "Missing options", "No input options."); + Usage (); + return STATUS_ERROR; + } + + argc --; + argv ++; + + if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) { + Version (); + Usage (); + return STATUS_SUCCESS; + } + + if (stricmp (argv[0], "--version") == 0) { + Version (); + return STATUS_SUCCESS; + } + + while (argc > 0) { + if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + Error (NULL, 0, 1003, "Invalid option value", "Output file name is missing for -o option"); + goto Finish; + } + OutImageName = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-e") == 0) || (stricmp (argv[0], "--efiImage") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + Error (NULL, 0, 1003, "Invalid option value", "Module Type is missing for -o option"); + goto Finish; + } + ModuleType = argv[1]; + if (mOutImageType == FW_ZERO_DEBUG_IMAGE) { + ZeroDebugFlag = TRUE; + } + if (mOutImageType != FW_TE_IMAGE) { + mOutImageType = FW_EFI_IMAGE; + } + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--stripped") == 0)) { + mOutImageType = FW_RELOC_STRIPEED_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--acpi") == 0)) { + mOutImageType = FW_ACPI_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--terse") == 0)) { + if (mOutImageType == FW_ZERO_DEBUG_IMAGE) { + ZeroDebugFlag = TRUE; + } + mOutImageType = FW_TE_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-u") == 0) || (stricmp (argv[0], "--dump") == 0)) { + mOutImageType = DUMP_TE_HEADER; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--exe2bin") == 0)) { + mOutImageType = FW_BIN_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-z") == 0) || (stricmp (argv[0], "--zero") == 0)) { + if (mOutImageType == FW_DUMMY_IMAGE) { + mOutImageType = FW_ZERO_DEBUG_IMAGE; + } + if (mOutImageType == FW_TE_IMAGE || mOutImageType == FW_EFI_IMAGE) { + ZeroDebugFlag = TRUE; + } + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--stamp") == 0)) { + mOutImageType = FW_SET_STAMP_IMAGE; + if (argv[1] == NULL || argv[1][0] == '-') { + Error (NULL, 0, 1003, "Invalid option value", "time stamp is missing for -s option"); + goto Finish; + } + TimeStamp = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--replace") == 0)) { + ReplaceFlag = TRUE; + argc --; + argv ++; + continue; + } + + if (stricmp (argv[0], "--keepexceptiontable") == 0) { + KeepExceptionTableFlag = TRUE; + argc --; + argv ++; + continue; + } + + if (stricmp(argv[0], "--keepoptionalheader") == 0) { + KeepOptionalHeaderFlag = TRUE; + argc--; + argv++; + continue; + } + + if (stricmp (argv[0], "--keepzeropending") == 0) { + KeepZeroPendingFlag = TRUE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-m") == 0) || (stricmp (argv[0], "--mcifile") == 0)) { + mOutImageType = FW_MCI_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--join") == 0)) { + mOutImageType = FW_MERGE_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) { + if (AsciiStringToUint64 (argv[1], FALSE, &Temp64) != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + MciAlignment = (UINT32) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "--rebase") == 0)) { + if (argv[1][0] == '-') { + NegativeAddr = TRUE; + Status = AsciiStringToUint64 (argv[1] + 1, FALSE, &Temp64); + } else { + NegativeAddr = FALSE; + Status = AsciiStringToUint64 (argv[1], FALSE, &Temp64); + } + if (Status != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + mOutImageType = FW_REBASE_IMAGE; + NewBaseAddress = (UINT64) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "--address") == 0)) { + if (argv[1][0] == '-') { + NegativeAddr = TRUE; + Status = AsciiStringToUint64 (argv[1] + 1, FALSE, &Temp64); + } else { + NegativeAddr = FALSE; + Status = AsciiStringToUint64 (argv[1], FALSE, &Temp64); + } + if (Status != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + mOutImageType = FW_SET_ADDRESS_IMAGE; + NewBaseAddress = (UINT64) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-p") == 0) || (stricmp (argv[0], "--pad") == 0)) { + if (AsciiStringToUint64 (argv[1], FALSE, &Temp64) != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + MciPadValue = (UINT8) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) { + SetPrintLevel (VERBOSE_LOG_LEVEL); + VerboseMsg ("Verbose output Mode Set!"); + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) { + SetPrintLevel (KEY_LOG_LEVEL); + KeyMsg ("Quiet output Mode Set!"); + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) { + Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + if (LogLevel > 9) { + Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel); + goto Finish; + } + SetPrintLevel (LogLevel); + DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]); + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--hiiguid") == 0)) { + Status = StringToGuid (argv[1], &HiiPackageListGuid); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + argc -= 2; + argv += 2; + continue; + } + + if (stricmp (argv[0], "--hiipackage") == 0) { + mOutImageType = FW_HII_PACKAGE_LIST_RCIMAGE; + argc --; + argv ++; + continue; + } + + if (stricmp (argv[0], "--hiibinpackage") == 0) { + mOutImageType = FW_HII_PACKAGE_LIST_BINIMAGE; + argc --; + argv ++; + continue; + } + + if (argv[0][0] == '-') { + Error (NULL, 0, 1000, "Unknown option", argv[0]); + goto Finish; + } + // + // Get Input file name + // + if ((InputFileNum == 0) && (InputFileName == NULL)) { + InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)); + if (InputFileName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + + memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); + } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) { + // + // InputFileName buffer too small, need to realloc + // + InputFileName = (CHAR8 **) realloc ( + InputFileName, + (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *) + ); + + if (InputFileName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + + memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); + } + + InputFileName [InputFileNum ++] = argv[0]; + argc --; + argv ++; + } + + VerboseMsg ("%s tool start.", UTILITY_NAME); + + if (mOutImageType == FW_DUMMY_IMAGE) { + Error (NULL, 0, 1001, "Missing option", "No create file action specified; pls specify -e, -c or -t option to create efi image, or acpi table or TeImage!"); + if (ReplaceFlag) { + Error (NULL, 0, 1001, "Missing option", "-r option is not supported as the independent option. It can be used together with other create file option specified at the above."); + } + goto Finish; + } + + // + // check input files + // + if (InputFileNum == 0) { + Error (NULL, 0, 1001, "Missing option", "Input files"); + goto Finish; + } + + // + // Combine MciBinary files to one file + // + if ((mOutImageType == FW_MERGE_IMAGE) && ReplaceFlag) { + Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with -j merge files option."); + goto Finish; + } + + // + // Combine HiiBinary packages to a single package list + // + if ((mOutImageType == FW_HII_PACKAGE_LIST_RCIMAGE) && ReplaceFlag) { + Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with --hiipackage merge files option."); + goto Finish; + } + + if ((mOutImageType == FW_HII_PACKAGE_LIST_BINIMAGE) && ReplaceFlag) { + Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with --hiibinpackage merge files option."); + goto Finish; + } + + // + // Input image file + // + mInImageName = InputFileName [InputFileNum - 1]; + VerboseMsg ("the input file name is %s", mInImageName); + + // + // Action will be taken for the input file. + // + switch (mOutImageType) { + case FW_EFI_IMAGE: + VerboseMsg ("Create efi image on module type %s based on the input PE image.", ModuleType); + break; + case FW_TE_IMAGE: + VerboseMsg ("Create Te Image based on the input PE image."); + break; + case FW_ACPI_IMAGE: + VerboseMsg ("Get acpi table data from the input PE image."); + break; + case FW_RELOC_STRIPEED_IMAGE: + VerboseMsg ("Remove relocation section from Pe or Te image."); + break; + case FW_BIN_IMAGE: + VerboseMsg ("Convert the input EXE to the output BIN file."); + break; + case FW_ZERO_DEBUG_IMAGE: + VerboseMsg ("Zero the Debug Data Fields and Time Stamp in input PE image."); + break; + case FW_SET_STAMP_IMAGE: + VerboseMsg ("Set new time stamp %s in the input PE image.", TimeStamp); + break; + case DUMP_TE_HEADER: + VerboseMsg ("Dump the TE header information of the input TE image."); + break; + case FW_MCI_IMAGE: + VerboseMsg ("Convert input MicroCode.txt file to MicroCode.bin file."); + break; + case FW_MERGE_IMAGE: + VerboseMsg ("Combine the input multi microcode bin files to one bin file."); + break; + case FW_HII_PACKAGE_LIST_RCIMAGE: + VerboseMsg ("Combine the input multi hii bin packages to one text package list RC file."); + break; + case FW_HII_PACKAGE_LIST_BINIMAGE: + VerboseMsg ("Combine the input multi hii bin packages to one binary package list file."); + break; + case FW_REBASE_IMAGE: + VerboseMsg ("Rebase the input image to new base address."); + break; + case FW_SET_ADDRESS_IMAGE: + VerboseMsg ("Set the preferred address into the section header of the input image"); + break; + default: + break; + } + + if (ReplaceFlag) { + VerboseMsg ("Overwrite the input file with the output content."); + } + + // + // Open output file and Write image into the output file. + // + if (OutImageName != NULL) { + fpOut = fopen (LongFilePath (OutImageName), "rb"); + if (fpOut != NULL) { + // + // Get Output file time stamp + // + fstat(fileno (fpOut), &Stat_Buf); + OutputFileTime = Stat_Buf.st_mtime; + // + // Get Output file data + // + OutputFileLength = _filelength (fileno (fpOut)); + OutputFileBuffer = malloc (OutputFileLength); + if (OutputFileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + fclose (fpOut); + fpOut = NULL; + goto Finish; + } + fread (OutputFileBuffer, 1, OutputFileLength, fpOut); + fclose (fpOut); + fpOut = NULL; + } + VerboseMsg ("Output file name is %s", OutImageName); + } else if (!ReplaceFlag && mOutImageType != DUMP_TE_HEADER) { + Error (NULL, 0, 1001, "Missing option", "output file"); + goto Finish; + } + + // + // Open input file and read file data into file buffer. + // + fpIn = fopen (LongFilePath (mInImageName), "rb"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + // + // Get Iutput file time stamp + // + fstat(fileno (fpIn), &Stat_Buf); + InputFileTime = Stat_Buf.st_mtime; + // + // Get Input file data + // + InputFileLength = _filelength (fileno (fpIn)); + InputFileBuffer = malloc (InputFileLength); + if (InputFileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + fclose (fpIn); + goto Finish; + } + fread (InputFileBuffer, 1, InputFileLength, fpIn); + fclose (fpIn); + DebugMsg (NULL, 0, 9, "input file info", "the input file size is %u bytes", (unsigned) InputFileLength); + + // + // Combine multi binary HII package files. + // + if (mOutImageType == FW_HII_PACKAGE_LIST_RCIMAGE || mOutImageType == FW_HII_PACKAGE_LIST_BINIMAGE) { + // + // Open output file handle. + // + fpOut = fopen (LongFilePath (OutImageName), "wb"); + if (!fpOut) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + // + // Get hii package list length + // + HiiPackageListHeader.PackageLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + for (Index = 0; Index < InputFileNum; Index ++) { + fpIn = fopen (LongFilePath (InputFileName [Index]), "rb"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]); + goto Finish; + } + FileLength = _filelength (fileno (fpIn)); + fread (&HiiPackageHeader, 1, sizeof (HiiPackageHeader), fpIn); + if (HiiPackageHeader.Type == EFI_HII_PACKAGE_FORM) { + if (HiiPackageHeader.Length != FileLength) { + Error (NULL, 0, 3000, "Invalid", "The wrong package size is in HII package file %s", InputFileName [Index]); + fclose (fpIn); + goto Finish; + } + if (memcmp (&HiiPackageListGuid, &mZeroGuid, sizeof (EFI_GUID)) == 0) { + fread (&IfrFormSet, 1, sizeof (IfrFormSet), fpIn); + memcpy (&HiiPackageListGuid, &IfrFormSet.Guid, sizeof (EFI_GUID)); + } + NumberOfFormPackage ++; + } + HiiPackageListHeader.PackageLength += FileLength; + fclose (fpIn); + } + HiiPackageListHeader.PackageLength += sizeof (EndPackage); + // + // Check whether hii packages are valid + // + if (NumberOfFormPackage > 1) { + Error (NULL, 0, 3000, "Invalid", "The input hii packages contains more than one hii form package"); + goto Finish; + } + if (memcmp (&HiiPackageListGuid, &mZeroGuid, sizeof (EFI_GUID)) == 0) { + Error (NULL, 0, 3000, "Invalid", "HII package list guid is not specified!"); + goto Finish; + } + memcpy (&HiiPackageListHeader.PackageListGuid, &HiiPackageListGuid, sizeof (EFI_GUID)); + // + // read hii packages + // + HiiPackageListBuffer = malloc (HiiPackageListHeader.PackageLength); + if (HiiPackageListBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + memcpy (HiiPackageListBuffer, &HiiPackageListHeader, sizeof (HiiPackageListHeader)); + HiiPackageDataPointer = HiiPackageListBuffer + sizeof (HiiPackageListHeader); + for (Index = 0; Index < InputFileNum; Index ++) { + fpIn = fopen (LongFilePath (InputFileName [Index]), "rb"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]); + free (HiiPackageListBuffer); + goto Finish; + } + + FileLength = _filelength (fileno (fpIn)); + fread (HiiPackageDataPointer, 1, FileLength, fpIn); + fclose (fpIn); + HiiPackageDataPointer = HiiPackageDataPointer + FileLength; + } + memcpy (HiiPackageDataPointer, &EndPackage, sizeof (EndPackage)); + + // + // write the hii package into the binary package list file with the resource section header + // + if (mOutImageType == FW_HII_PACKAGE_LIST_BINIMAGE) { + // + // Create the resource section header + // + HiiSectionHeader = CreateHiiResouceSectionHeader (&HiiSectionHeaderSize, HiiPackageListHeader.PackageLength); + if (HiiSectionHeader == NULL) { + free (HiiPackageListBuffer); + goto Finish; + } + // + // Wrtie section header and HiiData into File. + // + fwrite (HiiSectionHeader, 1, HiiSectionHeaderSize, fpOut); + fwrite (HiiPackageListBuffer, 1, HiiPackageListHeader.PackageLength, fpOut); + // + // Free allocated resources. + // + free (HiiSectionHeader); + free (HiiPackageListBuffer); + // + // Done successfully + // + goto Finish; + } + + // + // write the hii package into the text package list rc file. + // + if (mOutImageType == FW_HII_PACKAGE_LIST_RCIMAGE) { + for (Index = 0; gHiiPackageRCFileHeader[Index] != NULL; Index++) { + fprintf (fpOut, "%s\n", gHiiPackageRCFileHeader[Index]); + } + fprintf (fpOut, "\n%d %s\n{", HII_RESOURCE_SECTION_INDEX, HII_RESOURCE_SECTION_NAME); + + HiiPackageDataPointer = HiiPackageListBuffer; + for (Index = 0; Index + 2 < HiiPackageListHeader.PackageLength; Index += 2) { + if (Index % 16 == 0) { + fprintf (fpOut, "\n "); + } + fprintf (fpOut, " 0x%04X,", *(UINT16 *) HiiPackageDataPointer); + HiiPackageDataPointer += 2; + } + + if (Index % 16 == 0) { + fprintf (fpOut, "\n "); + } + if ((Index + 2) == HiiPackageListHeader.PackageLength) { + fprintf (fpOut, " 0x%04X\n}\n", *(UINT16 *) HiiPackageDataPointer); + } + if ((Index + 1) == HiiPackageListHeader.PackageLength) { + fprintf (fpOut, " 0x%04X\n}\n", *(UINT8 *) HiiPackageDataPointer); + } + free (HiiPackageListBuffer); + // + // Done successfully + // + goto Finish; + } + } + + // + // Combine MciBinary files to one file + // + if (mOutImageType == FW_MERGE_IMAGE) { + // + // Open output file handle. + // + fpOut = fopen (LongFilePath (OutImageName), "wb"); + if (!fpOut) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + for (Index = 0; Index < InputFileNum; Index ++) { + fpIn = fopen (LongFilePath (InputFileName [Index]), "rb"); + if (!fpIn) { + Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]); + goto Finish; + } + + FileLength = _filelength (fileno (fpIn)); + FileBuffer = malloc (FileLength); + if (FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + fclose (fpIn); + goto Finish; + } + + fread (FileBuffer, 1, FileLength, fpIn); + fclose (fpIn); + // + // write input file to out file + // + fwrite (FileBuffer, 1, FileLength, fpOut); + // + // write pad value to out file. + // + while (FileLength ++ % MciAlignment != 0) { + fwrite (&MciPadValue, 1, 1, fpOut); + } + // + // free allocated memory space + // + free (FileBuffer); + FileBuffer = NULL; + } + // + // Done successfully + // + goto Finish; + } + + // + // Convert MicroCode.txt file to MicroCode.bin file + // + if (mOutImageType == FW_MCI_IMAGE) { + fpIn = fopen (LongFilePath (mInImageName), "r"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + + // + // The first pass is to determine + // how much data is in the file so we can allocate a working buffer. + // + FileLength = 0; + do { + Status = MicrocodeReadData (fpIn, &Data); + if (Status == STATUS_SUCCESS) { + FileLength += sizeof (Data); + } + if (Status == STATUS_IGNORE) { + Status = STATUS_SUCCESS; + } + } while (Status == STATUS_SUCCESS); + // + // Error if no data. + // + if (FileLength == 0) { + Error (NULL, 0, 3000, "Invalid", "no parseable data found in file %s", mInImageName); + goto Finish; + } + if (FileLength < sizeof (MICROCODE_IMAGE_HEADER)) { + Error (NULL, 0, 3000, "Invalid", "amount of parseable data in %s is insufficient to contain a microcode header", mInImageName); + goto Finish; + } + + // + // Allocate a buffer for the data + // + FileBuffer = malloc (FileLength); + if (FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + // + // Re-read the file, storing the data into our buffer + // + fseek (fpIn, 0, SEEK_SET); + DataPointer = (UINT32 *) FileBuffer; + OldDataPointer = DataPointer; + do { + OldDataPointer = DataPointer; + Status = MicrocodeReadData (fpIn, DataPointer++); + if (Status == STATUS_IGNORE) { + DataPointer = OldDataPointer; + Status = STATUS_SUCCESS; + } + } while (Status == STATUS_SUCCESS); + // + // close input file after read data + // + fclose (fpIn); + + // + // Can't do much checking on the header because, per the spec, the + // DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K, + // and the TotalSize field is invalid (actually missing). Thus we can't + // even verify the Reserved fields are 0. + // + MciHeader = (MICROCODE_IMAGE_HEADER *) FileBuffer; + if (MciHeader->DataSize == 0) { + Index = 2048; + } else { + Index = MciHeader->TotalSize; + } + + if (Index != FileLength) { + Error (NULL, 0, 3000, "Invalid", "file length of %s (0x%x) does not equal expected TotalSize: 0x%04X.", mInImageName, (unsigned) FileLength, (unsigned) Index); + goto Finish; + } + + // + // Checksum the contents + // + DataPointer = (UINT32 *) FileBuffer; + CheckSum = 0; + Index = 0; + while (Index < FileLength) { + CheckSum += *DataPointer; + DataPointer ++; + Index += sizeof (*DataPointer); + } + if (CheckSum != 0) { + Error (NULL, 0, 3000, "Invalid", "checksum (0x%x) failed on file %s.", (unsigned) CheckSum, mInImageName); + goto Finish; + } + // + // Open the output file and write the buffer contents + // + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Open input file and read file data into file buffer. + // + FileLength = InputFileLength; + FileBuffer = malloc (FileLength); + if (FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + memcpy (FileBuffer, InputFileBuffer, InputFileLength); + + // + // Dump TeImage Header into output file. + // + if (mOutImageType == DUMP_TE_HEADER) { + memcpy (&TEImageHeader, FileBuffer, sizeof (TEImageHeader)); + if (TEImageHeader.Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "TE header signature of file %s is not correct.", mInImageName); + goto Finish; + } + // + // Open the output file handle. + // + if (ReplaceFlag) { + fpInOut = fopen (LongFilePath (mInImageName), "wb"); + if (fpInOut == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + } else { + if (OutImageName != NULL) { + fpOut = fopen (LongFilePath (OutImageName), "wb"); + } else { + fpOut = stdout; + } + if (fpOut == NULL) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + } + if (fpInOut != NULL) { + fprintf (fpInOut, "Dump of file %s\n\n", mInImageName); + fprintf (fpInOut, "TE IMAGE HEADER VALUES\n"); + fprintf (fpInOut, "%17X machine\n", TEImageHeader.Machine); + fprintf (fpInOut, "%17X number of sections\n", TEImageHeader.NumberOfSections); + fprintf (fpInOut, "%17X subsystems\n", TEImageHeader.Subsystem); + fprintf (fpInOut, "%17X stripped size\n", TEImageHeader.StrippedSize); + fprintf (fpInOut, "%17X entry point\n", (unsigned) TEImageHeader.AddressOfEntryPoint); + fprintf (fpInOut, "%17X base of code\n", (unsigned) TEImageHeader.BaseOfCode); + fprintf (fpInOut, "%17llX image base\n", (unsigned long long)TEImageHeader.ImageBase); + fprintf (fpInOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", (unsigned) TEImageHeader.DataDirectory[0].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[0].Size); + fprintf (fpInOut, "%17X [%8X] RVA [size] of Debug Directory\n", (unsigned) TEImageHeader.DataDirectory[1].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[1].Size); + } + if (fpOut != NULL) { + fprintf (fpOut, "Dump of file %s\n\n", mInImageName); + fprintf (fpOut, "TE IMAGE HEADER VALUES\n"); + fprintf (fpOut, "%17X machine\n", TEImageHeader.Machine); + fprintf (fpOut, "%17X number of sections\n", TEImageHeader.NumberOfSections); + fprintf (fpOut, "%17X subsystems\n", TEImageHeader.Subsystem); + fprintf (fpOut, "%17X stripped size\n", TEImageHeader.StrippedSize); + fprintf (fpOut, "%17X entry point\n", (unsigned) TEImageHeader.AddressOfEntryPoint); + fprintf (fpOut, "%17X base of code\n", (unsigned) TEImageHeader.BaseOfCode); + fprintf (fpOut, "%17llX image base\n", (unsigned long long)TEImageHeader.ImageBase); + fprintf (fpOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", (unsigned) TEImageHeader.DataDirectory[0].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[0].Size); + fprintf (fpOut, "%17X [%8X] RVA [size] of Debug Directory\n", (unsigned) TEImageHeader.DataDirectory[1].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[1].Size); + } + goto Finish; + } + + // + // Following code to convert dll to efi image or te image. + // Get new image type + // + if ((mOutImageType == FW_EFI_IMAGE) || (mOutImageType == FW_TE_IMAGE)) { + if (ModuleType == NULL) { + if (mOutImageType == FW_EFI_IMAGE) { + Error (NULL, 0, 1001, "Missing option", "EFI_FILETYPE"); + goto Finish; + } else if (mOutImageType == FW_TE_IMAGE) { + // + // Default TE Image Type is Boot service driver + // + Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi boot service driver."); + } + } else { + if (stricmp (ModuleType, "BASE") == 0 || + stricmp (ModuleType, "SEC") == 0 || + stricmp (ModuleType, "SECURITY_CORE") == 0 || + stricmp (ModuleType, "PEI_CORE") == 0 || + stricmp (ModuleType, "PEIM") == 0 || + stricmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0 || + stricmp (ModuleType, "PIC_PEIM") == 0 || + stricmp (ModuleType, "RELOCATABLE_PEIM") == 0 || + stricmp (ModuleType, "DXE_CORE") == 0 || + stricmp (ModuleType, "BS_DRIVER") == 0 || + stricmp (ModuleType, "DXE_DRIVER") == 0 || + stricmp (ModuleType, "DXE_SMM_DRIVER") == 0 || + stricmp (ModuleType, "UEFI_DRIVER") == 0 || + stricmp (ModuleType, "SMM_CORE") == 0 || + stricmp (ModuleType, "MM_STANDALONE") == 0 || + stricmp (ModuleType, "MM_CORE_STANDALONE") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi boot service driver."); + + } else if (stricmp (ModuleType, "UEFI_APPLICATION") == 0 || + stricmp (ModuleType, "APPLICATION") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION; + VerboseMsg ("Efi Image subsystem type is efi application."); + + } else if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0 || + stricmp (ModuleType, "RT_DRIVER") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi runtime driver."); + + } else if (stricmp (ModuleType, "DXE_SAL_DRIVER") == 0 || + stricmp (ModuleType, "SAL_RT_DRIVER") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi sal runtime driver."); + + } else { + Error (NULL, 0, 1003, "Invalid option value", "EFI_FILETYPE = %s", ModuleType); + goto Finish; + } + } + } + + // + // Convert ELF image to PeImage + // + if (IsElfHeader(FileBuffer)) { + VerboseMsg ("Convert %s from ELF to PE/COFF.", mInImageName); + if (!ConvertElf(&FileBuffer, &FileLength)) { + Error (NULL, 0, 3000, "Invalid", "Unable to convert %s from ELF to PE/COFF.", mInImageName); + goto Finish; + } + } + + // + // Make sure File Offsets and Virtual Offsets are the same in the image so it is XIP + // XIP == eXecute In Place + // + PeCoffConvertImageToXip (&FileBuffer, &FileLength); + + // + // Remove reloc section from PE or TE image + // + if (mOutImageType == FW_RELOC_STRIPEED_IMAGE) { + // + // Check TeImage + // + TeHdr = (EFI_TE_IMAGE_HEADER *) FileBuffer; + if (TeHdr->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TeHdr + 1); + for (Index = 0; Index < TeHdr->NumberOfSections; Index ++, SectionHeader ++) { + if (strcmp ((char *)SectionHeader->Name, ".reloc") == 0) { + // + // Check the reloc section is in the end of image. + // + if ((SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData) == + (FileLength + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER))) { + // + // Remove .reloc section and update TeImage Header + // + FileLength = FileLength - SectionHeader->SizeOfRawData; + SectionHeader->SizeOfRawData = 0; + SectionHeader->Misc.VirtualSize = 0; + TeHdr->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + TeHdr->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; + break; + } + } + } + } else { + // + // Check PE Image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "TE and DOS header signatures were not found in %s image.", mInImageName); + goto Finish; + } + DosHdr = NULL; + } else { + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + DosHdr->e_lfanew); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "PE header signature was not found in %s image.", mInImageName); + goto Finish; + } + } + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if (strcmp ((char *)SectionHeader->Name, ".reloc") == 0) { + // + // Check the reloc section is in the end of image. + // + if ((SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData) == FileLength) { + // + // Remove .reloc section and update PeImage Header + // + FileLength = FileLength - SectionHeader->SizeOfRawData; + + PeHdr->Pe32.FileHeader.Characteristics |= EFI_IMAGE_FILE_RELOCS_STRIPPED; + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + Optional32->SizeOfImage -= SectionHeader->SizeOfRawData; + Optional32->SizeOfInitializedData -= SectionHeader->SizeOfRawData; + if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; + } + } + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + Optional64->SizeOfImage -= SectionHeader->SizeOfRawData; + Optional64->SizeOfInitializedData -= SectionHeader->SizeOfRawData; + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; + } + } + SectionHeader->Misc.VirtualSize = 0; + SectionHeader->SizeOfRawData = 0; + break; + } + } + } + } + // + // Write file + // + goto WriteFile; + } + // + // Read the dos & pe hdrs of the image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, check for PE/COFF header + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "DOS header signature was not found in %s image.", mInImageName); + goto Finish; + } + DosHdr = NULL; + } else { + + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + DosHdr->e_lfanew); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "PE header signature was not found in %s image.", mInImageName); + goto Finish; + } + } + + if (PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) { + // Some tools kick out IMAGE_FILE_MACHINE_ARM (0x1c0) vs IMAGE_FILE_MACHINE_ARMT (0x1c2) + // so patch back to the official UEFI value. + PeHdr->Pe32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMT; + } + + // + // Set new base address into image + // + if (mOutImageType == FW_REBASE_IMAGE || mOutImageType == FW_SET_ADDRESS_IMAGE) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (NewBaseAddress >= 0x100000000ULL) { + Error (NULL, 0, 3000, "Invalid", "New base address is larger than 4G for 32bit PE image"); + goto Finish; + } + } + + if (NegativeAddr) { + // + // Set Base Address to a negative value. + // + NewBaseAddress = (UINT64) (0 - NewBaseAddress); + } + if (mOutImageType == FW_REBASE_IMAGE) { + Status = RebaseImage (mInImageName, FileBuffer, NewBaseAddress); + } else { + Status = SetAddressToSectionHeader (mInImageName, FileBuffer, NewBaseAddress); + } + if (EFI_ERROR (Status)) { + if (NegativeAddr) { + Error (NULL, 0, 3000, "Invalid", "Rebase/Set Image %s to Base address -0x%llx can't success", mInImageName, 0 - NewBaseAddress); + } else { + Error (NULL, 0, 3000, "Invalid", "Rebase/Set Image %s to Base address 0x%llx can't success", mInImageName, NewBaseAddress); + } + goto Finish; + } + + // + // Write file + // + goto WriteFile; + } + + // + // Extract bin data from Pe image. + // + if (mOutImageType == FW_BIN_IMAGE) { + if (FileLength < PeHdr->Pe32.OptionalHeader.SizeOfHeaders) { + Error (NULL, 0, 3000, "Invalid", "FileSize of %s is not a legal size.", mInImageName); + goto Finish; + } + // + // Output bin data from exe file + // + FileLength = FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders; + memmove (FileBuffer, FileBuffer + PeHdr->Pe32.OptionalHeader.SizeOfHeaders, FileLength); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Zero Debug Information of Pe Image + // + if (mOutImageType == FW_ZERO_DEBUG_IMAGE) { + Status = ZeroDebugData (FileBuffer, TRUE); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "Zero DebugData Error status is 0x%x", (int) Status); + goto Finish; + } + + // + // Write the updated Image + // + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Set Time Stamp of Pe Image + // + if (mOutImageType == FW_SET_STAMP_IMAGE) { + Status = SetStamp (FileBuffer, TimeStamp); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Write the updated Image + // + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Extract acpi data from pe image. + // + if (mOutImageType == FW_ACPI_IMAGE) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if (strcmp ((char *)SectionHeader->Name, ".data") == 0 || strcmp ((char *)SectionHeader->Name, ".sdata") == 0) { + // + // Check Acpi Table + // + if (SectionHeader->Misc.VirtualSize < SectionHeader->SizeOfRawData) { + FileLength = SectionHeader->Misc.VirtualSize; + } else { + FileLength = SectionHeader->SizeOfRawData; + } + + if (CheckAcpiTable (FileBuffer + SectionHeader->PointerToRawData, FileLength) != STATUS_SUCCESS) { + Error (NULL, 0, 3000, "Invalid", "ACPI table check failed in %s.", mInImageName); + goto Finish; + } + + // + // Output Apci data to file + // + memmove (FileBuffer, FileBuffer + SectionHeader->PointerToRawData, FileLength); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + } + Error (NULL, 0, 3000, "Invalid", "failed to get ACPI table from %s.", mInImageName); + goto Finish; + } + // + // Zero all unused fields of the DOS header + // + if (DosHdr != NULL) { + memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER)); + memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER)); + DosHdr->e_magic = BackupDosHdr.e_magic; + DosHdr->e_lfanew = BackupDosHdr.e_lfanew; + + for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (UINT32 ) DosHdr->e_lfanew; Index++) { + FileBuffer[Index] = (UINT8) DosHdr->e_cp; + } + } + + // + // Initialize TeImage Header + // + memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER)); + TEImageHeader.Signature = EFI_TE_IMAGE_HEADER_SIGNATURE; + TEImageHeader.Machine = PeHdr->Pe32.FileHeader.Machine; + TEImageHeader.NumberOfSections = (UINT8) PeHdr->Pe32.FileHeader.NumberOfSections; + TEImageHeader.StrippedSize = (UINT16) ((UINTN) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader) - (UINTN) FileBuffer); + TEImageHeader.Subsystem = (UINT8) Type; + + // + // Patch the PE header + // + PeHdr->Pe32.OptionalHeader.Subsystem = (UINT16) Type; + + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + if (!KeepOptionalHeaderFlag) { + Optional32->MajorOperatingSystemVersion = 0; + Optional32->MinorOperatingSystemVersion = 0; + Optional32->MajorImageVersion = 0; + Optional32->MinorImageVersion = 0; + Optional32->MajorSubsystemVersion = 0; + Optional32->MinorSubsystemVersion = 0; + Optional32->Win32VersionValue = 0; + Optional32->CheckSum = 0; + Optional32->SizeOfStackReserve = 0; + Optional32->SizeOfStackCommit = 0; + Optional32->SizeOfHeapReserve = 0; + Optional32->SizeOfHeapCommit = 0; + } + TEImageHeader.AddressOfEntryPoint = Optional32->AddressOfEntryPoint; + TEImageHeader.BaseOfCode = Optional32->BaseOfCode; + TEImageHeader.ImageBase = (UINT64) (Optional32->ImageBase); + + if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + } + + // + // Zero .pdata section data. + // + if (!KeepExceptionTableFlag && Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION && + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0 && + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) { + // + // Zero .pdata Section data + // + memset (FileBuffer + SectionHeader->PointerToRawData, 0, SectionHeader->SizeOfRawData); + // + // Zero .pdata Section header name + // + memset (SectionHeader->Name, 0, sizeof (SectionHeader->Name)); + // + // Zero Exception Table + // + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0; + DebugMsg (NULL, 0, 9, "Zero the .pdata section for PE image", NULL); + break; + } + } + } + + // + // Strip zero padding at the end of the .reloc section + // + if (!KeepZeroPendingFlag && Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + if (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + // + // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory + // + if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) { + SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + AllignedRelocSize = (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1)); + // + // Check to see if there is zero padding at the end of the base relocations + // + if (AllignedRelocSize < SectionHeader->SizeOfRawData) { + // + // Check to see if the base relocations are at the end of the file + // + if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) { + // + // All the required conditions are met to strip the zero padding of the end of the base relocations section + // + Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + SectionHeader->SizeOfRawData = AllignedRelocSize; + FileLength = Optional32->SizeOfImage; + DebugMsg (NULL, 0, 9, "Remove the zero padding bytes at the end of the base relocations", "The size of padding bytes is %u", (unsigned) (SectionHeader->SizeOfRawData - AllignedRelocSize)); + } + } + } + } + } + } + } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + if (!KeepOptionalHeaderFlag) { + Optional64->MajorOperatingSystemVersion = 0; + Optional64->MinorOperatingSystemVersion = 0; + Optional64->MajorImageVersion = 0; + Optional64->MinorImageVersion = 0; + Optional64->MajorSubsystemVersion = 0; + Optional64->MinorSubsystemVersion = 0; + Optional64->Win32VersionValue = 0; + Optional64->CheckSum = 0; + Optional64->SizeOfStackReserve = 0; + Optional64->SizeOfStackCommit = 0; + Optional64->SizeOfHeapReserve = 0; + Optional64->SizeOfHeapCommit = 0; + } + TEImageHeader.AddressOfEntryPoint = Optional64->AddressOfEntryPoint; + TEImageHeader.BaseOfCode = Optional64->BaseOfCode; + TEImageHeader.ImageBase = (UINT64) (Optional64->ImageBase); + + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + } + + // + // Zero the .pdata section for X64 machine and don't check the Debug Directory is empty + // For Itaninum and X64 Image, remove .pdata section. + // + if ((!KeepExceptionTableFlag && PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64)) { + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION && + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0 && + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) { + // + // Zero .pdata Section header name + // + memset (SectionHeader->Name, 0, sizeof (SectionHeader->Name)); + + RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData); + for (Index1 = 0; Index1 < Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index2 = 0; Index2 < PeHdr->Pe32.FileHeader.NumberOfSections; Index2++, SectionHeader++) { + if (RuntimeFunction->UnwindInfoAddress >= SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) { + UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress)); + if (UnwindInfo->Version == 1) { + memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16)); + memset (UnwindInfo, 0, sizeof (UNWIND_INFO)); + } + break; + } + } + memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION)); + } + // + // Zero Exception Table + // + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0; + DebugMsg (NULL, 0, 9, "Zero the .pdata section if the machine type is X64 for PE32+ image", NULL); + break; + } + } + } + } + + // + // Strip zero padding at the end of the .reloc section + // + if (!KeepZeroPendingFlag && Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + if (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + // + // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory + // + if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) { + SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + AllignedRelocSize = (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1)); + // + // Check to see if there is zero padding at the end of the base relocations + // + if (AllignedRelocSize < SectionHeader->SizeOfRawData) { + // + // Check to see if the base relocations are at the end of the file + // + if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) { + // + // All the required conditions are met to strip the zero padding of the end of the base relocations section + // + Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + SectionHeader->SizeOfRawData = AllignedRelocSize; + FileLength = Optional64->SizeOfImage; + DebugMsg (NULL, 0, 9, "Remove the zero padding bytes at the end of the base relocations", "The size of padding bytes is %u", (unsigned) (SectionHeader->SizeOfRawData - AllignedRelocSize)); + } + } + } + } + } + } + } else { + Error (NULL, 0, 3000, "Invalid", "Magic 0x%x of PeImage %s is unknown.", PeHdr->Pe32.OptionalHeader.Magic, mInImageName); + goto Finish; + } + + if (((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) == 0) && \ + (TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0) && \ + (TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0)) { + // + // PeImage can be loaded into memory, but it has no relocation section. + // Fix TeImage Header to set VA of relocation data directory to not zero, the size is still zero. + // + if (Optional32 != NULL) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->SizeOfImage - sizeof (EFI_IMAGE_BASE_RELOCATION); + } else if (Optional64 != NULL) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->SizeOfImage - sizeof (EFI_IMAGE_BASE_RELOCATION); + } + } + + // + // Fill HII section data + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) { + if (stricmp ((char *)SectionHeader[Index].Name, ".hii") == 0) { + // + // Update resource section header offset + // + SetHiiResourceHeader ((UINT8*) FileBuffer + SectionHeader[Index].PointerToRawData, SectionHeader[Index].VirtualAddress); + // + // Update resource section name + // + strcpy((char *) SectionHeader[Index].Name, ".rsrc"); + // + // Update resource data directory. + // + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = SectionHeader[Index].VirtualAddress; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = SectionHeader[Index].Misc.VirtualSize; + } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = SectionHeader[Index].VirtualAddress; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = SectionHeader[Index].Misc.VirtualSize; + } + break; + } + } + + // + // Zero ExceptionTable Xdata + // + if (!KeepExceptionTableFlag) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) { + if (stricmp ((char *)SectionHeader[Index].Name, ".xdata") == 0) { + // + // zero .xdata section + // + memset (FileBuffer + SectionHeader[Index].PointerToRawData, 0, SectionHeader[Index].SizeOfRawData); + DebugMsg (NULL, 0, 9, NULL, "Zero the .xdata section for PE image at Offset 0x%x and Length 0x%x", (unsigned) SectionHeader[Index].PointerToRawData, (unsigned) SectionHeader[Index].SizeOfRawData); + break; + } + } + } + + // + // Zero Time/Data field + // + ZeroDebugData (FileBuffer, ZeroDebugFlag); + + if (mOutImageType == FW_TE_IMAGE) { + if ((PeHdr->Pe32.FileHeader.NumberOfSections &~0xFF) || (Type &~0xFF)) { + // + // Pack the subsystem and NumberOfSections into 1 byte. Make sure they fit both. + // + Error (NULL, 0, 3000, "Invalid", "Image's subsystem or NumberOfSections of PeImage %s cannot be packed into 1 byte.", mInImageName); + goto Finish; + } + + if ((PeHdr->Pe32.OptionalHeader.SectionAlignment != PeHdr->Pe32.OptionalHeader.FileAlignment)) { + // + // TeImage has the same section alignment and file alignment. + // + Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment of PeImage %s do not match, they must be equal for a TeImage.", mInImageName); + goto Finish; + } + + DebugMsg (NULL, 0, 9, "TeImage Header Info", "Machine type is %X, Number of sections is %X, Stripped size is %X, EntryPoint is %X, BaseOfCode is %X, ImageBase is %llX", + TEImageHeader.Machine, TEImageHeader.NumberOfSections, TEImageHeader.StrippedSize, (unsigned) TEImageHeader.AddressOfEntryPoint, (unsigned) TEImageHeader.BaseOfCode, (unsigned long long) TEImageHeader.ImageBase); + // + // Update Image to TeImage + // + FileLength = FileLength - TEImageHeader.StrippedSize; + memmove (FileBuffer + sizeof (EFI_TE_IMAGE_HEADER), FileBuffer + TEImageHeader.StrippedSize, FileLength); + FileLength = FileLength + sizeof (EFI_TE_IMAGE_HEADER); + memcpy (FileBuffer, &TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER)); + VerboseMsg ("the size of output file is %u bytes", (unsigned) (FileLength)); + } else { + + // + // Following codes are to fix the objcopy's issue: + // objcopy in binutil 2.50.18 will set PE image's charactices to "RELOC_STRIPPED" if image has no ".reloc" section + // It cause issue for EFI image which has no ".reloc" sections. + // Following codes will be removed when objcopy in binutil fix this problem for PE image. + // + if ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + if (Optional32->ImageBase == 0) { + PeHdr->Pe32.FileHeader.Characteristics &= ~EFI_IMAGE_FILE_RELOCS_STRIPPED; + } + } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + if (Optional64->ImageBase == 0) { + PeHdr->Pe32.FileHeader.Characteristics &= ~EFI_IMAGE_FILE_RELOCS_STRIPPED; + } + } + } + } + +WriteFile: + // + // Update Image to EfiImage or TE image + // + if (ReplaceFlag) { + if ((FileLength != InputFileLength) || (memcmp (FileBuffer, InputFileBuffer, FileLength) != 0)) { + // + // Update File when File is changed. + // + fpInOut = fopen (LongFilePath (mInImageName), "wb"); + if (fpInOut == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + fwrite (FileBuffer, 1, FileLength, fpInOut); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + } + } else { + if ((OutputFileTime < InputFileTime) || (FileLength != OutputFileLength) || (memcmp (FileBuffer, OutputFileBuffer, FileLength) != 0)) { + // + // Update File when File is changed or File is old. + // + fpOut = fopen (LongFilePath (OutImageName), "wb"); + if (fpOut == NULL) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + fwrite (FileBuffer, 1, FileLength, fpOut); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + } + } + mImageSize = FileLength; + +Finish: + if (fpInOut != NULL) { + if (GetUtilityStatus () != STATUS_SUCCESS) { + // + // when file updates failed, original file is still recovered. + // + fwrite (InputFileBuffer, 1, InputFileLength, fpInOut); + } + // + // Write converted data into fpInOut file and close input file. + // + fclose (fpInOut); + } + + if (FileBuffer != NULL) { + free (FileBuffer); + } + + if (InputFileName != NULL) { + free (InputFileName); + } + + if (fpOut != NULL) { + // + // Write converted data into fpOut file and close output file. + // + fclose (fpOut); + if (GetUtilityStatus () != STATUS_SUCCESS) { + if (OutputFileBuffer == NULL) { + remove (OutImageName); + } else { + fpOut = fopen (LongFilePath (OutImageName), "wb"); + fwrite (OutputFileBuffer, 1, OutputFileLength, fpOut); + fclose (fpOut); + } + } + } + + if (InputFileBuffer != NULL) { + free (InputFileBuffer); + } + + if (OutputFileBuffer != NULL) { + free (OutputFileBuffer); + } + + // + // Write module size and time stamp to report file. + // + if (OutImageName != NULL) { + FileLen = strlen (OutImageName); + } + if (FileLen >= 4 && strcmp (OutImageName + (FileLen - 4), ".efi") == 0) { + ReportFileName = (CHAR8 *) malloc (FileLen + 1); + if (ReportFileName != NULL) { + strcpy (ReportFileName, OutImageName); + strcpy (ReportFileName + (FileLen - 4), ".txt"); + ReportFile = fopen (LongFilePath (ReportFileName), "w+"); + if (ReportFile != NULL) { + fprintf (ReportFile, "MODULE_SIZE = %u\n", (unsigned) mImageSize); + fprintf (ReportFile, "TIME_STAMP = %u\n", (unsigned) mImageTimeStamp); + fclose(ReportFile); + } + free (ReportFileName); + } + } + VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ()); + + return GetUtilityStatus (); +} + +STATIC +EFI_STATUS +ZeroDebugData ( + IN OUT UINT8 *FileBuffer, + BOOLEAN ZeroDebugFlag + ) +/*++ + +Routine Description: + + Zero debug information in PeImage. + +Arguments: + + FileBuffer - Pointer to PeImage. + ZeroDebugFlag - TRUE to zero Debug information, FALSE to only zero time/stamp + +Returns: + + EFI_ABORTED - PeImage is invalid. + EFI_SUCCESS - Zero debug data successfully. + +--*/ +{ + UINT32 Index; + UINT32 DebugDirectoryEntryRva; + UINT32 DebugDirectoryEntrySize; + UINT32 DebugDirectoryEntryFileOffset; + UINT32 ExportDirectoryEntryRva; + UINT32 ExportDirectoryEntryFileOffset; + UINT32 ResourceDirectoryEntryRva; + UINT32 ResourceDirectoryEntryFileOffset; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_FILE_HEADER *FileHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY *RsdsEntry; + UINT32 *NewTimeStamp; + + // + // Init variable. + // + DebugDirectoryEntryRva = 0; + DebugDirectoryEntrySize = 0; + ExportDirectoryEntryRva = 0; + ResourceDirectoryEntryRva = 0; + DebugDirectoryEntryFileOffset = 0; + ExportDirectoryEntryFileOffset = 0; + ResourceDirectoryEntryFileOffset = 0; + DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer; + FileHdr = (EFI_IMAGE_FILE_HEADER *) (FileBuffer + DosHdr->e_lfanew + sizeof (UINT32)); + + + DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, must start with PE/COFF header + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32)); + } else { + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32)); + } + + // + // Get Debug, Export and Resource EntryTable RVA address. + // Resource Directory entry need to review. + // + Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + DebugDirectoryEntrySize = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if (ZeroDebugFlag) { + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0; + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0; + } + } + } else { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + DebugDirectoryEntrySize = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if (ZeroDebugFlag) { + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0; + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0; + } + } + } + + // + // Get DirectoryEntryTable file offset. + // + for (Index = 0; Index < FileHdr->NumberOfSections; Index ++, SectionHeader ++) { + if (DebugDirectoryEntryRva >= SectionHeader->VirtualAddress && + DebugDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = + DebugDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ExportDirectoryEntryRva >= SectionHeader->VirtualAddress && + ExportDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ExportDirectoryEntryFileOffset = + ExportDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ResourceDirectoryEntryRva >= SectionHeader->VirtualAddress && + ResourceDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ResourceDirectoryEntryFileOffset = + ResourceDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + } + + // + //Zero Debug Data and TimeStamp + // + FileHdr->TimeDateStamp = 0; + mImageTimeStamp = 0; + if (ExportDirectoryEntryFileOffset != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ExportDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = 0; + } + + if (ResourceDirectoryEntryFileOffset != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ResourceDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = 0; + } + + if (DebugDirectoryEntryFileOffset != 0) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (FileBuffer + DebugDirectoryEntryFileOffset); + Index = 0; + for (Index=0; Index < DebugDirectoryEntrySize / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); Index ++, DebugEntry ++) { + DebugEntry->TimeDateStamp = 0; + if (mIsConvertXip) { + DebugEntry->FileOffset = DebugEntry->RVA; + } + if (ZeroDebugFlag || DebugEntry->Type != EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + memset (FileBuffer + DebugEntry->FileOffset, 0, DebugEntry->SizeOfData); + memset (DebugEntry, 0, sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)); + } + if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + RsdsEntry = (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY *) (FileBuffer + DebugEntry->FileOffset); + if (RsdsEntry->Signature == CODEVIEW_SIGNATURE_MTOC) { + // MTOC sets DebugDirectoryEntrySize to size of the .debug section, so fix it. + if (!ZeroDebugFlag) { + if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + } else { + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + } + } + break; + } + } + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetStamp ( + IN OUT UINT8 *FileBuffer, + IN CHAR8 *TimeStamp + ) +/*++ + +Routine Description: + + Set new time stamp into PeImage FileHdr and Directory table: + Debug, Export and Resource. + +Arguments: + + FileBuffer - Pointer to PeImage. + TimeStamp - Time stamp string. + +Returns: + + EFI_INVALID_PARAMETER - TimeStamp format is not recognized. + EFI_SUCCESS - Set new time stamp in this image successfully. + +--*/ +{ + struct tm stime; + struct tm *ptime; + time_t newtime; + UINT32 Index; + UINT32 DebugDirectoryEntryRva; + UINT32 DebugDirectoryEntryFileOffset; + UINT32 ExportDirectoryEntryRva; + UINT32 ExportDirectoryEntryFileOffset; + UINT32 ResourceDirectoryEntryRva; + UINT32 ResourceDirectoryEntryFileOffset; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_FILE_HEADER *FileHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINT32 *NewTimeStamp; + + // + // Init variable. + // + DebugDirectoryEntryRva = 0; + DebugDirectoryEntryFileOffset = 0; + ExportDirectoryEntryRva = 0; + ExportDirectoryEntryFileOffset = 0; + ResourceDirectoryEntryRva = 0; + ResourceDirectoryEntryFileOffset = 0; + // + // Get time and date that will be set. + // + if (TimeStamp == NULL) { + Error (NULL, 0, 3000, "Invalid", "TimeStamp cannot be NULL."); + return EFI_INVALID_PARAMETER; + } + // + // compare the value with "NOW", if yes, current system time is set. + // + if (stricmp (TimeStamp, "NOW") == 0) { + // + // get system current time and date + // + time (&newtime); + } else { + // + // Check Time Format strictly yyyy-mm-dd 00:00:00 + // + for (Index = 0; TimeStamp[Index] != '\0' && Index < 20; Index ++) { + if (Index == 4 || Index == 7) { + if (TimeStamp[Index] == '-') { + continue; + } + } else if (Index == 13 || Index == 16) { + if (TimeStamp[Index] == ':') { + continue; + } + } else if (Index == 10 && TimeStamp[Index] == ' ') { + continue; + } else if ((TimeStamp[Index] < '0') || (TimeStamp[Index] > '9')) { + break; + } + } + + if (Index < 19 || TimeStamp[19] != '\0') { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect Time \"%s\"\n Correct Format \"yyyy-mm-dd 00:00:00\"", TimeStamp); + return EFI_INVALID_PARAMETER; + } + + // + // get the date and time from TimeStamp + // + if (sscanf (TimeStamp, "%d-%d-%d %d:%d:%d", + &stime.tm_year, + &stime.tm_mon, + &stime.tm_mday, + &stime.tm_hour, + &stime.tm_min, + &stime.tm_sec + ) != 6) { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect Tiem \"%s\"\n Correct Format \"yyyy-mm-dd 00:00:00\"", TimeStamp); + return EFI_INVALID_PARAMETER; + } + + // + // in struct, Month (0 - 11; Jan = 0). So decrease 1 from it + // + if (stime.tm_mon <= 0 || stime.tm_mday <=0) { + Error (NULL, 0, 3000, "Invalid", "%s Invalid date!", TimeStamp); + return EFI_INVALID_PARAMETER; + } + stime.tm_mon -= 1; + + // + // in struct, Year (current year minus 1900) + // and only the dates can be handled from Jan 1, 1970 to Jan 18, 2038 + // + // + // convert 0 -> 100 (2000), 1 -> 101 (2001), ..., 38 -> 138 (2038) + // + if (stime.tm_year >= 1970 && stime.tm_year <= 2038) { + // + // convert 1970 -> 70, 2000 -> 100, ... + // + stime.tm_year -= 1900; + } else { + Error (NULL, 0, 3000, "Invalid", "%s Invalid or unsupported datetime!", TimeStamp); + return EFI_INVALID_PARAMETER; + } + + // + // convert the date and time to time_t format + // + newtime = mktime (&stime); + if (newtime == (time_t) - 1) { + Error (NULL, 0, 3000, "Invalid", "%s Invalid or unsupported datetime!", TimeStamp); + return EFI_INVALID_PARAMETER; + } + } + + ptime = localtime (&newtime); + if (ptime != NULL) { + DebugMsg (NULL, 0, 9, "New Image Time Stamp", "%04d-%02d-%02d %02d:%02d:%02d", + ptime->tm_year + 1900, ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec); + } + // + // Set new time and data into PeImage. + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, must start with PE/COFF header + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32)); + } else { + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32)); + } + + // + // Get Debug, Export and Resource EntryTable RVA address. + // Resource Directory entry need to review. + // + if (FileHdr->Machine == EFI_IMAGE_MACHINE_IA32) { + Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + } + } else { + Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + } + } + + // + // Get DirectoryEntryTable file offset. + // + for (Index = 0; Index < FileHdr->NumberOfSections; Index ++, SectionHeader ++) { + if (DebugDirectoryEntryRva >= SectionHeader->VirtualAddress && + DebugDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = + DebugDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ExportDirectoryEntryRva >= SectionHeader->VirtualAddress && + ExportDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ExportDirectoryEntryFileOffset = + ExportDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ResourceDirectoryEntryRva >= SectionHeader->VirtualAddress && + ResourceDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ResourceDirectoryEntryFileOffset = + ResourceDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + } + + // + // Set new stamp + // + FileHdr->TimeDateStamp = (UINT32) newtime; + mImageTimeStamp = (UINT32) newtime; + if (ExportDirectoryEntryRva != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ExportDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = (UINT32) newtime; + } + + if (ResourceDirectoryEntryRva != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ResourceDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = (UINT32) newtime; + } + + if (DebugDirectoryEntryRva != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + DebugDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = (UINT32) newtime; + } + + return EFI_SUCCESS; +} + +STATIC +STATUS +MicrocodeReadData ( + FILE *InFptr, + UINT32 *Data + ) +/*++ + +Routine Description: + Read a 32-bit microcode data value from a text file and convert to raw binary form. + +Arguments: + InFptr - file pointer to input text file + Data - pointer to where to return the data parsed + +Returns: + STATUS_SUCCESS - no errors or warnings, Data contains valid information + STATUS_ERROR - errors were encountered + +--*/ +{ + CHAR8 Line[MAX_LINE_LEN]; + CHAR8 *cptr; + int ScannedData = 0; + + Line[MAX_LINE_LEN - 1] = 0; + while (1) { + if (fgets (Line, MAX_LINE_LEN, InFptr) == NULL) { + return STATUS_ERROR; + } + // + // If it was a binary file, then it may have overwritten our null terminator + // + if (Line[MAX_LINE_LEN - 1] != 0) { + return STATUS_ERROR; + } + + // + // strip space + // + for (cptr = Line; *cptr && isspace((int)*cptr); cptr++) { + } + + // Skip Blank Lines and Comment Lines + if ((strlen(cptr) != 0) && (*cptr != ';')) { + break; + } + } + + // Look for + // dd 000000001h ; comment + // dd XXXXXXXX + // DD XXXXXXXXX + // DD XXXXXXXXX + // + if ((tolower((int)cptr[0]) == 'd') && (tolower((int)cptr[1]) == 'd') && isspace ((int)cptr[2])) { + // + // Skip blanks and look for a hex digit + // + cptr += 3; + for (; *cptr && isspace((int)*cptr); cptr++) { + } + if (isxdigit ((int)*cptr)) { + if (sscanf (cptr, "%X", &ScannedData) != 1) { + return STATUS_ERROR; + } + } + *Data = (UINT32) ScannedData; + return STATUS_SUCCESS; + } + + return STATUS_ERROR; +} |