| /** @file | |
| Copyright (c) 2004 - 2009, Intel Corporation | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| GenFw.c | |
| Abstract: | |
| Converts a pe32+ image to an FW, Te image type, or other specific image. | |
| **/ | |
| #include "WinNtInclude.h" | |
| #ifndef __GNUC__ | |
| #include <windows.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> | |
| // | |
| // 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 "EfiUtilityMsgs.h" | |
| #include "elf_common.h" | |
| #include "elf32.h" | |
| #include "elf64.h" | |
| // | |
| // Version of this utility | |
| // | |
| #define UTILITY_NAME "GenFw" | |
| #define UTILITY_MAJOR_VERSION 0 | |
| #define UTILITY_MINOR_VERSION 2 | |
| // | |
| // Action for this tool. | |
| // | |
| #define FW_DUMMY_IMAGE 0 | |
| #define FW_EFI_IMAGE 1 | |
| #define FW_TE_IMAGE 2 | |
| #define FW_ACPI_IMAGE 3 | |
| #define FW_BIN_IMAGE 4 | |
| #define FW_ZERO_DEBUG_IMAGE 5 | |
| #define FW_SET_STAMP_IMAGE 6 | |
| #define FW_MCI_IMAGE 7 | |
| #define FW_MERGE_IMAGE 8 | |
| #define FW_RELOC_STRIPEED_IMAGE 9 | |
| #define DUMP_TE_HEADER 0x11 | |
| #define DEFAULT_MC_PAD_BYTE_VALUE 0xFF | |
| #define DEFAULT_MC_ALIGNMENT 16 | |
| #ifndef _MAX_PATH | |
| #define _MAX_PATH 500 | |
| #endif | |
| #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 CHAR8 *mInImageName; | |
| 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\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_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, 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 ouput content.\n"); | |
| fprintf (stdout, " -e EFI_FILETYPE, --efiImage EFI_FILETYPE\n\ | |
| Create Efi Image. EFI_FILETYPE is one of BASE, SEC,\n\ | |
| PEI_CORE, PEIM, DXE_CORE, DXE_DRIVER, UEFI_APPLICATION,\n\ | |
| DXE_SAL_DRIVER, UEFI_DRIVER, DXE_RUNTIME_DRIVER, \n\ | |
| DXE_SMM_DRIVER, SECURITY_CORE, COMBINED_PEIM_DRIVER, \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, -r, -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, " -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, -r, -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, " -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 Relocation info stripped from the input 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-1-1 8:0:0 ~ 2038-1-19 3:14:07\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, " --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, " -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: | |
| 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 != 0) && | |
| (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) { | |
| Error (NULL, 0, 3000, "Invalid", "DSDT revision check failed."); | |
| return STATUS_ERROR; | |
| } | |
| 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_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) { | |
| 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; | |
| } | |
| INTN | |
| IsElfHeader( | |
| UINT8 *FileBuffer | |
| ) | |
| { | |
| return (FileBuffer[EI_MAG0] == ELFMAG0 | |
| && FileBuffer[EI_MAG1] == ELFMAG1 | |
| && FileBuffer[EI_MAG2] == ELFMAG2 | |
| && FileBuffer[EI_MAG3] == ELFMAG3); | |
| } | |
| typedef Elf32_Shdr Elf_Shdr; | |
| typedef Elf32_Ehdr Elf_Ehdr; | |
| typedef Elf32_Rel Elf_Rel; | |
| typedef Elf32_Sym Elf_Sym; | |
| typedef Elf32_Phdr Elf_Phdr; | |
| typedef Elf32_Dyn Elf_Dyn; | |
| #define ELFCLASS ELFCLASS32 | |
| #define ELF_R_TYPE(r) ELF32_R_TYPE(r) | |
| #define ELF_R_SYM(r) ELF32_R_SYM(r) | |
| // | |
| // Well known ELF structures. | |
| // | |
| Elf_Ehdr *Ehdr; | |
| Elf_Shdr *ShdrBase; | |
| Elf_Phdr *gPhdrBase; | |
| // | |
| // PE section alignment. | |
| // | |
| const UINT32 CoffAlignment = 0x20; | |
| const UINT32 CoffNbrSections = 4; | |
| // | |
| // Current offset in coff file. | |
| // | |
| UINT32 CoffOffset; | |
| // | |
| // Result Coff file in memory. | |
| // | |
| UINT8 *CoffFile = NULL; | |
| // | |
| // ELF sections to offset in Coff file. | |
| // | |
| UINT32 *CoffSectionsOffset = NULL; | |
| // | |
| // Offset in Coff file of headers and sections. | |
| // | |
| UINT32 NtHdrOffset; | |
| UINT32 TableOffset; | |
| UINT32 TextOffset; | |
| UINT32 DataOffset; | |
| UINT32 RelocOffset; | |
| EFI_IMAGE_BASE_RELOCATION *CoffBaseRel; | |
| UINT16 *CoffEntryRel; | |
| UINT32 | |
| CoffAlign( | |
| UINT32 Offset | |
| ) | |
| { | |
| return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1); | |
| } | |
| Elf_Shdr * | |
| GetShdrByIndex( | |
| UINT32 Num | |
| ) | |
| { | |
| if (Num >= Ehdr->e_shnum) | |
| return NULL; | |
| return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize); | |
| } | |
| INTN | |
| CheckElfHeader( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Note: Magic has already been tested. | |
| // | |
| if (Ehdr->e_ident[EI_CLASS] != ELFCLASS) { | |
| Error (NULL, 0, 3000, "Unsupported", "%s needs to be ported for 64-bit ELF.", mInImageName); | |
| return 0; | |
| } | |
| if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { | |
| Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB"); | |
| return 0; | |
| } | |
| if ((Ehdr->e_type != ET_EXEC) && (Ehdr->e_type != ET_DYN)) { | |
| Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN"); | |
| return 0; | |
| } | |
| if (!((Ehdr->e_machine == EM_386) || (Ehdr->e_machine == EM_ARM))) { | |
| Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_386 or EM_ARM"); | |
| return 0; | |
| } | |
| if (Ehdr->e_version != EV_CURRENT) { | |
| Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%d) not EV_CURRENT (%d)", Ehdr->e_version, EV_CURRENT); | |
| return 0; | |
| } | |
| // | |
| // Find the section header table | |
| // | |
| ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff); | |
| gPhdrBase = (Elf_Phdr *)((UINT8 *)Ehdr + Ehdr->e_phoff); | |
| CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32)); | |
| memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32)); | |
| return 1; | |
| } | |
| int | |
| IsTextShdr( | |
| Elf_Shdr *Shdr | |
| ) | |
| { | |
| return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC; | |
| } | |
| int | |
| IsDataShdr( | |
| Elf_Shdr *Shdr | |
| ) | |
| { | |
| return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE); | |
| } | |
| VOID | |
| CreateSectionHeader( | |
| const CHAR8 *Name, | |
| UINT32 Offset, | |
| UINT32 Size, | |
| UINT32 Flags | |
| ) | |
| { | |
| EFI_IMAGE_SECTION_HEADER *Hdr; | |
| Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset); | |
| strcpy((char *)Hdr->Name, Name); | |
| Hdr->Misc.VirtualSize = Size; | |
| Hdr->VirtualAddress = Offset; | |
| Hdr->SizeOfRawData = Size; | |
| Hdr->PointerToRawData = Offset; | |
| Hdr->PointerToRelocations = 0; | |
| Hdr->PointerToLinenumbers = 0; | |
| Hdr->NumberOfRelocations = 0; | |
| Hdr->NumberOfLinenumbers = 0; | |
| Hdr->Characteristics = Flags; | |
| TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER); | |
| } | |
| VOID | |
| ScanSections( | |
| VOID | |
| ) | |
| { | |
| UINT32 i; | |
| EFI_IMAGE_DOS_HEADER *DosHdr; | |
| EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; | |
| UINT32 CoffEntry; | |
| CoffEntry = 0; | |
| CoffOffset = 0; | |
| // | |
| // Coff file start with a DOS header. | |
| // | |
| CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40; | |
| NtHdrOffset = CoffOffset; | |
| switch (Ehdr->e_machine) { | |
| case EM_386: | |
| case EM_ARM: | |
| CoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32); | |
| break; | |
| case EM_X86_64: | |
| case EM_IA_64: | |
| CoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64); | |
| break; | |
| default: | |
| VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)Ehdr->e_machine); | |
| CoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32); | |
| break; | |
| } | |
| TableOffset = CoffOffset; | |
| CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER); | |
| // | |
| // First text sections. | |
| // | |
| CoffOffset = CoffAlign(CoffOffset); | |
| TextOffset = CoffOffset; | |
| for (i = 0; i < Ehdr->e_shnum; i++) { | |
| Elf_Shdr *shdr = GetShdrByIndex(i); | |
| if (IsTextShdr(shdr)) { | |
| if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { | |
| // the alignment field is valid | |
| if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { | |
| // if the section address is aligned we must align PE/COFF | |
| CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); | |
| } else if ((shdr->sh_addr % shdr->sh_addralign) != (CoffOffset % shdr->sh_addralign)) { | |
| // ARM RVCT tools have behavior outside of the ELF specification to try | |
| // and make images smaller. If sh_addr is not aligned to sh_addralign | |
| // then the section needs to preserve sh_addr MOD sh_addralign. | |
| // Normally doing nothing here works great. | |
| Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); | |
| } | |
| } | |
| /* Relocate entry. */ | |
| if ((Ehdr->e_entry >= shdr->sh_addr) && | |
| (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) { | |
| CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr; | |
| } | |
| CoffSectionsOffset[i] = CoffOffset; | |
| CoffOffset += shdr->sh_size; | |
| } | |
| } | |
| if (Ehdr->e_machine != EM_ARM) { | |
| CoffOffset = CoffAlign(CoffOffset); | |
| } | |
| // | |
| // Then data sections. | |
| // | |
| DataOffset = CoffOffset; | |
| for (i = 0; i < Ehdr->e_shnum; i++) { | |
| Elf_Shdr *shdr = GetShdrByIndex(i); | |
| if (IsDataShdr(shdr)) { | |
| if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { | |
| // the alignment field is valid | |
| if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { | |
| // if the section address is aligned we must align PE/COFF | |
| CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); | |
| } else if ((shdr->sh_addr % shdr->sh_addralign) != (CoffOffset % shdr->sh_addralign)) { | |
| // ARM RVCT tools have behavior outside of the ELF specification to try | |
| // and make images smaller. If sh_addr is not aligned to sh_addralign | |
| // then the section needs to preserve sh_addr MOD sh_addralign. | |
| // Normally doing nothing here works great. | |
| Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); | |
| } | |
| } | |
| CoffSectionsOffset[i] = CoffOffset; | |
| CoffOffset += shdr->sh_size; | |
| } | |
| } | |
| CoffOffset = CoffAlign(CoffOffset); | |
| RelocOffset = CoffOffset; | |
| // | |
| // Allocate base Coff file. Will be expanded later for relocations. | |
| // | |
| CoffFile = (UINT8 *)malloc(CoffOffset); | |
| memset(CoffFile, 0, CoffOffset); | |
| // | |
| // Fill headers. | |
| // | |
| DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile; | |
| DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE; | |
| DosHdr->e_lfanew = NtHdrOffset; | |
| NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(CoffFile + NtHdrOffset); | |
| NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE; | |
| switch (Ehdr->e_machine) { | |
| case EM_386: | |
| NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32; | |
| NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; | |
| break; | |
| case EM_X86_64: | |
| NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_X64; | |
| NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; | |
| break; | |
| case EM_IA_64: | |
| NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF; | |
| NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; | |
| break; | |
| case EM_ARM: | |
| NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_ARMT; | |
| NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; | |
| break; | |
| default: | |
| VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)Ehdr->e_machine); | |
| NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32; | |
| NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; | |
| } | |
| NtHdr->Pe32.FileHeader.NumberOfSections = CoffNbrSections; | |
| NtHdr->Pe32.FileHeader.TimeDateStamp = time(NULL); | |
| NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0; | |
| NtHdr->Pe32.FileHeader.NumberOfSymbols = 0; | |
| NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader); | |
| NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE | |
| | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED | |
| | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED | |
| | EFI_IMAGE_FILE_32BIT_MACHINE; | |
| NtHdr->Pe32.OptionalHeader.SizeOfCode = DataOffset - TextOffset; | |
| NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset; | |
| NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0; | |
| NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry; | |
| NtHdr->Pe32.OptionalHeader.BaseOfCode = TextOffset; | |
| NtHdr->Pe32.OptionalHeader.BaseOfData = DataOffset; | |
| NtHdr->Pe32.OptionalHeader.ImageBase = 0; | |
| NtHdr->Pe32.OptionalHeader.SectionAlignment = CoffAlignment; | |
| NtHdr->Pe32.OptionalHeader.FileAlignment = CoffAlignment; | |
| NtHdr->Pe32.OptionalHeader.SizeOfImage = 0; | |
| NtHdr->Pe32.OptionalHeader.SizeOfHeaders = TextOffset; | |
| NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES; | |
| // | |
| // Section headers. | |
| // | |
| if ((DataOffset - TextOffset) > 0) { | |
| CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset, | |
| EFI_IMAGE_SCN_CNT_CODE | |
| | EFI_IMAGE_SCN_MEM_EXECUTE | |
| | EFI_IMAGE_SCN_MEM_READ); | |
| } else { | |
| // Don't make a section of size 0. | |
| NtHdr->Pe32.FileHeader.NumberOfSections--; | |
| } | |
| if ((RelocOffset - TextOffset) > 0) { | |
| CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset, | |
| EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | |
| | EFI_IMAGE_SCN_MEM_WRITE | |
| | EFI_IMAGE_SCN_MEM_READ); | |
| } else { | |
| // Don't make a section of size 0. | |
| NtHdr->Pe32.FileHeader.NumberOfSections--; | |
| } | |
| } | |
| VOID | |
| WriteSections( | |
| int (*Filter)(Elf_Shdr *) | |
| ) | |
| { | |
| UINT32 Idx; | |
| Elf_Shdr *SecShdr; | |
| UINT32 SecOffset; | |
| // | |
| // First: copy sections. | |
| // | |
| for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) { | |
| Elf_Shdr *Shdr = GetShdrByIndex(Idx); | |
| if ((*Filter)(Shdr)) { | |
| switch (Shdr->sh_type) { | |
| case SHT_PROGBITS: | |
| /* Copy. */ | |
| memcpy(CoffFile + CoffSectionsOffset[Idx], | |
| (UINT8*)Ehdr + Shdr->sh_offset, | |
| Shdr->sh_size); | |
| break; | |
| case SHT_NOBITS: | |
| memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size); | |
| break; | |
| default: | |
| // | |
| // Ignore for unkown section type. | |
| // | |
| VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (UINTN)Shdr->sh_type); | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // Second: apply relocations. | |
| // | |
| for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) { | |
| Elf_Shdr *RelShdr = GetShdrByIndex(Idx); | |
| if (RelShdr->sh_type != SHT_REL) | |
| continue; | |
| SecShdr = GetShdrByIndex(RelShdr->sh_info); | |
| SecOffset = CoffSectionsOffset[RelShdr->sh_info]; | |
| if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) { | |
| UINT32 RelIdx; | |
| Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link); | |
| UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset; | |
| for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) { | |
| Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx); | |
| Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize); | |
| Elf_Shdr *SymShdr; | |
| UINT8 *Targ; | |
| if (Sym->st_shndx == SHN_UNDEF | |
| || Sym->st_shndx == SHN_ABS | |
| || Sym->st_shndx > Ehdr->e_shnum) { | |
| Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName); | |
| } | |
| SymShdr = GetShdrByIndex(Sym->st_shndx); | |
| // | |
| // Note: r_offset in a memory address. | |
| // Convert it to a pointer in the coff file. | |
| // | |
| Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr); | |
| if (Ehdr->e_machine == EM_386) { | |
| switch (ELF_R_TYPE(Rel->r_info)) { | |
| case R_386_NONE: | |
| break; | |
| case R_386_32: | |
| // | |
| // Absolute relocation. | |
| // | |
| *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr | |
| + CoffSectionsOffset[Sym->st_shndx]; | |
| break; | |
| case R_386_PC32: | |
| // | |
| // Relative relocation: Symbol - Ip + Addend | |
| // | |
| *(UINT32 *)Targ = *(UINT32 *)Targ | |
| + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr) | |
| - (SecOffset - SecShdr->sh_addr); | |
| break; | |
| default: | |
| Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF_R_TYPE(Rel->r_info)); | |
| } | |
| } else if (Ehdr->e_machine == EM_ARM) { | |
| switch (ELF32_R_TYPE(Rel->r_info)) { | |
| case R_ARM_RBASE: // No relocation - no action required | |
| case R_ARM_PC24: // PC-relative relocations don't require modification | |
| case R_ARM_XPC25: // PC-relative relocations don't require modification | |
| break; | |
| case R_ARM_ABS32: | |
| case R_ARM_RABS32: | |
| // | |
| // Absolute relocation. | |
| // | |
| *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + CoffSectionsOffset[Sym->st_shndx]; | |
| break; | |
| default: | |
| Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF32_R_TYPE(Rel->r_info)); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| VOID | |
| CoffAddFixupEntry( | |
| UINT16 Val | |
| ) | |
| { | |
| *CoffEntryRel = Val; | |
| CoffEntryRel++; | |
| CoffBaseRel->SizeOfBlock += 2; | |
| CoffOffset += 2; | |
| } | |
| VOID | |
| CoffAddFixup( | |
| UINT32 Offset, | |
| UINT8 Type | |
| ) | |
| { | |
| if (CoffBaseRel == NULL | |
| || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) { | |
| if (CoffBaseRel != NULL) { | |
| // | |
| // Add a null entry (is it required ?) | |
| // | |
| CoffAddFixupEntry (0); | |
| // | |
| // Pad for alignment. | |
| // | |
| if (CoffOffset % 4 != 0) | |
| CoffAddFixupEntry (0); | |
| } | |
| CoffFile = realloc | |
| (CoffFile, | |
| CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000); | |
| memset(CoffFile + CoffOffset, 0, | |
| sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000); | |
| CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset); | |
| CoffBaseRel->VirtualAddress = Offset & ~0xfff; | |
| CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION); | |
| CoffEntryRel = (UINT16 *)(CoffBaseRel + 1); | |
| CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION); | |
| } | |
| // | |
| // Fill the entry. | |
| // | |
| CoffAddFixupEntry((Type << 12) | (Offset & 0xfff)); | |
| } | |
| Elf_Phdr * | |
| GetPhdrByIndex ( | |
| UINT32 num | |
| ) | |
| { | |
| if (num >= Ehdr->e_phnum) { | |
| return NULL; | |
| } | |
| return (Elf32_Phdr *)((UINT8*)gPhdrBase + num * Ehdr->e_phentsize); | |
| } | |
| VOID | |
| WriteRelocations( | |
| VOID | |
| ) | |
| { | |
| UINT32 Index; | |
| EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; | |
| EFI_IMAGE_DATA_DIRECTORY *Dir; | |
| BOOLEAN FoundRelocations; | |
| Elf_Dyn *Dyn; | |
| Elf_Rel *Rel; | |
| UINTN RelElementSize; | |
| UINTN RelSize; | |
| UINTN RelOffset; | |
| UINTN K; | |
| UINT8 *Targ; | |
| Elf32_Phdr *DynamicSegment; | |
| Elf32_Phdr *TargetSegment; | |
| for (Index = 0, FoundRelocations = FALSE; Index < Ehdr->e_shnum; Index++) { | |
| Elf_Shdr *RelShdr = GetShdrByIndex(Index); | |
| if (RelShdr->sh_type == SHT_REL) { | |
| Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info); | |
| if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) { | |
| UINT32 RelIdx; | |
| FoundRelocations = TRUE; | |
| for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) { | |
| Elf_Rel *Rel = (Elf_Rel *) | |
| ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx); | |
| if (Ehdr->e_machine == EM_386) { | |
| switch (ELF_R_TYPE(Rel->r_info)) { | |
| case R_386_NONE: | |
| case R_386_PC32: | |
| break; | |
| case R_386_32: | |
| CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info] | |
| + (Rel->r_offset - SecShdr->sh_addr), | |
| EFI_IMAGE_REL_BASED_HIGHLOW); | |
| break; | |
| default: | |
| Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF_R_TYPE(Rel->r_info)); | |
| } | |
| } else if (Ehdr->e_machine == EM_ARM) { | |
| switch (ELF32_R_TYPE(Rel->r_info)) { | |
| case R_ARM_RBASE: | |
| case R_ARM_PC24: | |
| case R_ARM_XPC25: | |
| break; | |
| case R_ARM_ABS32: | |
| case R_ARM_RABS32: | |
| CoffAddFixup ( | |
| CoffSectionsOffset[RelShdr->sh_info] | |
| + (Rel->r_offset - SecShdr->sh_addr), | |
| EFI_IMAGE_REL_BASED_HIGHLOW | |
| ); | |
| break; | |
| default: | |
| Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF32_R_TYPE(Rel->r_info)); | |
| } | |
| } else { | |
| Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %d (processor type).", Ehdr->e_machine); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if (!FoundRelocations && (Ehdr->e_machine == EM_ARM)) { | |
| /* Try again, but look for PT_DYNAMIC instead of SHT_REL */ | |
| for (Index = 0; Index < Ehdr->e_phnum; Index++) { | |
| RelElementSize = 0; | |
| RelSize = 0; | |
| RelOffset = 0; | |
| DynamicSegment = GetPhdrByIndex (Index); | |
| if (DynamicSegment->p_type == PT_DYNAMIC) { | |
| Dyn = (Elf32_Dyn *) ((UINT8 *)Ehdr + DynamicSegment->p_offset); | |
| while (Dyn->d_tag != DT_NULL) { | |
| switch (Dyn->d_tag) { | |
| case DT_REL: | |
| RelOffset = Dyn->d_un.d_val; | |
| break; | |
| case DT_RELSZ: | |
| RelSize = Dyn->d_un.d_val; | |
| break; | |
| case DT_RELENT: | |
| RelElementSize = Dyn->d_un.d_val; | |
| break; | |
| } | |
| Dyn++; | |
| } | |
| if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) { | |
| Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName); | |
| } | |
| for (K = 0; K < RelSize; K += RelElementSize) { | |
| Rel = (Elf32_Rel *) ((UINT8 *) Ehdr + DynamicSegment->p_offset + RelOffset + K); | |
| switch (ELF32_R_TYPE (Rel->r_info)) { | |
| case R_ARM_RBASE: | |
| break; | |
| case R_ARM_RABS32: | |
| TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1); | |
| // Note: r_offset in a memory address. Convert it to a pointer in the coff file. | |
| Targ = CoffFile + CoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr; | |
| *(UINT32 *)Targ = *(UINT32 *)Targ + CoffSectionsOffset [ELF32_R_SYM( Rel->r_info )]; | |
| CoffAddFixup (CoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW); | |
| break; | |
| default: | |
| Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type.", mInImageName); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // Pad by adding empty entries. | |
| // | |
| while (CoffOffset & (CoffAlignment - 1)) { | |
| CoffAddFixupEntry(0); | |
| } | |
| NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(CoffFile + NtHdrOffset); | |
| Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; | |
| Dir->Size = CoffOffset - RelocOffset; | |
| if (Dir->Size == 0) { | |
| // If no relocations, null out the directory entry and don't add the .reloc section | |
| Dir->VirtualAddress = 0; | |
| NtHdr->Pe32.FileHeader.NumberOfSections--; | |
| } else { | |
| Dir->VirtualAddress = RelocOffset; | |
| CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset, | |
| EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | |
| | EFI_IMAGE_SCN_MEM_DISCARDABLE | |
| | EFI_IMAGE_SCN_MEM_READ); | |
| } | |
| } | |
| VOID | |
| WriteDebug( | |
| VOID | |
| ) | |
| { | |
| UINT32 Len; | |
| UINT32 DebugOffset; | |
| EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; | |
| EFI_IMAGE_DATA_DIRECTORY *DataDir; | |
| EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir; | |
| EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10; | |
| Len = strlen(mInImageName) + 1; | |
| DebugOffset = CoffOffset; | |
| CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) | |
| + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) | |
| + Len; | |
| CoffOffset = CoffAlign(CoffOffset); | |
| CoffFile = realloc(CoffFile, CoffOffset); | |
| memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset); | |
| Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset); | |
| Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW; | |
| Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len; | |
| Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); | |
| Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); | |
| Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1); | |
| Nb10->Signature = CODEVIEW_SIGNATURE_NB10; | |
| strcpy ((char *)(Nb10 + 1), mInImageName); | |
| NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(CoffFile + NtHdrOffset); | |
| DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]; | |
| DataDir->VirtualAddress = DebugOffset; | |
| DataDir->Size = CoffOffset - DebugOffset; | |
| if (DataDir->Size == 0) { | |
| // If no debug, null out the directory entry and don't add the .debug section | |
| DataDir->VirtualAddress = 0; | |
| NtHdr->Pe32.FileHeader.NumberOfSections--; | |
| } else { | |
| DataDir->VirtualAddress = DebugOffset; | |
| CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset, | |
| EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | |
| | EFI_IMAGE_SCN_MEM_DISCARDABLE | |
| | EFI_IMAGE_SCN_MEM_READ); | |
| } | |
| } | |
| VOID | |
| ConvertElf ( | |
| UINT8 **FileBuffer, | |
| UINT32 *FileLength | |
| ) | |
| { | |
| EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; | |
| // | |
| // Check header, read section table. | |
| // | |
| Ehdr = (Elf32_Ehdr*)*FileBuffer; | |
| if (!CheckElfHeader()) | |
| return; | |
| VerboseMsg ("Check Efl Image Header"); | |
| // | |
| // Compute sections new address. | |
| // | |
| ScanSections(); | |
| VerboseMsg ("Compute sections new address."); | |
| // | |
| // Write and relocate sections. | |
| // | |
| WriteSections(IsTextShdr); | |
| WriteSections(IsDataShdr); | |
| VerboseMsg ("Write and relocate sections."); | |
| // | |
| // Translate and write relocations. | |
| // | |
| WriteRelocations(); | |
| VerboseMsg ("Translate and write relocations."); | |
| // | |
| // Write debug info. | |
| // | |
| WriteDebug(); | |
| VerboseMsg ("Write debug info."); | |
| NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(CoffFile + NtHdrOffset); | |
| NtHdr->Pe32.OptionalHeader.SizeOfImage = CoffOffset; | |
| // | |
| // Replace. | |
| // | |
| free(*FileBuffer); | |
| *FileBuffer = CoffFile; | |
| *FileLength = CoffOffset; | |
| // | |
| // Free memory space | |
| // | |
| if (CoffSectionsOffset != NULL) { | |
| free (CoffSectionsOffset); | |
| } | |
| } | |
| void | |
| ZeroXdataSection ( | |
| IN CHAR8 *ImageName, | |
| IN OUT UINT8 *FileBuffer, | |
| IN EFI_IMAGE_SECTION_HEADER *SectionHeader, | |
| IN UINT32 SectionTotalNumber | |
| ) | |
| { | |
| FILE *fpMapFile; | |
| CHAR8 MapFileName[_MAX_PATH]; | |
| CHAR8 Line [MAX_LINE_LEN]; | |
| CHAR8 KeyWord [MAX_LINE_LEN]; | |
| CHAR8 SectionName [MAX_LINE_LEN]; | |
| UINT32 FunctionType = 0; | |
| UINT32 SectionOffset; | |
| UINT32 SectionLength; | |
| UINT32 SectionNumber; | |
| CHAR8 *PdbPointer; | |
| INT32 Index = 0; | |
| for (Index = 0; Index < SectionTotalNumber; Index ++) { | |
| if (stricmp ((char *)SectionHeader[Index].Name, ".zdata") == 0) { | |
| // | |
| // try to zero the customized .zdata section, which is mapped to .xdata | |
| // | |
| 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", SectionHeader[Index].PointerToRawData, SectionHeader[Index].SizeOfRawData); | |
| return; | |
| } | |
| } | |
| // | |
| // Try to get PDB file name | |
| // | |
| PdbPointer = (CHAR8 *) PeCoffLoaderGetPdbPointer (FileBuffer); | |
| if (PdbPointer != NULL) { | |
| strcpy (MapFileName, PdbPointer); | |
| } else { | |
| strcpy (MapFileName, ImageName); | |
| } | |
| // | |
| // Construct map file name | |
| // | |
| Index = strlen (MapFileName) - 1; | |
| while (Index >= 0 && MapFileName[Index] != '.') { | |
| Index --; | |
| } | |
| if (Index < 0) { | |
| // | |
| // don't know how to costruct map file | |
| // | |
| return; | |
| } | |
| // | |
| // fill map file postfix | |
| // | |
| MapFileName[Index + 1] = 'm'; | |
| MapFileName[Index + 2] = 'a'; | |
| MapFileName[Index + 3] = 'p'; | |
| MapFileName[Index + 4] = '\0'; | |
| // | |
| // try opening Map File | |
| // | |
| fpMapFile = fopen (MapFileName, "r"); | |
| if (fpMapFile == NULL) { | |
| // | |
| // Can't open Map file. Maybe it doesn't exist. | |
| // | |
| return; | |
| } | |
| // | |
| // Output Functions information into Fv Map file | |
| // | |
| while (fgets (Line, MAX_LINE_LEN, fpMapFile) != NULL) { | |
| // | |
| // Skip blank line | |
| // | |
| if (Line[0] == 0x0a) { | |
| if (FunctionType != 0) { | |
| // | |
| // read all section table data | |
| // | |
| FunctionType = 0; | |
| break; | |
| } | |
| FunctionType = 0; | |
| continue; | |
| } | |
| // | |
| // By Start keyword | |
| // | |
| if (FunctionType == 0) { | |
| sscanf (Line, "%s", KeyWord); | |
| if (stricmp (KeyWord, "Start") == 0) { | |
| // | |
| // function list | |
| // | |
| FunctionType = 1; | |
| } | |
| continue; | |
| } | |
| // | |
| // Printf Function Information | |
| // | |
| if (FunctionType == 1) { | |
| sscanf (Line, "%x:%x %xH %s", &SectionNumber, &SectionOffset, &SectionLength, SectionName); | |
| if (stricmp (SectionName, ".xdata") == 0) { | |
| FunctionType = 2; | |
| break; | |
| } | |
| } | |
| } | |
| if (FunctionType != 2) { | |
| // | |
| // no .xdata section is found | |
| // | |
| fclose (fpMapFile); | |
| return; | |
| } | |
| // | |
| // Zero .xdata Section data | |
| // | |
| memset (FileBuffer + SectionHeader[SectionNumber-1].PointerToRawData + SectionOffset, 0, SectionLength); | |
| DebugMsg (NULL, 0, 9, NULL, "Zero the .xdata section for PE image at Offset 0x%x and Length 0x%x", SectionHeader[SectionNumber-1].PointerToRawData + SectionOffset, SectionLength); | |
| fclose (fpMapFile); | |
| return; | |
| } | |
| 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; | |
| UINT32 OutImageType; | |
| 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; | |
| RUNTIME_FUNCTION *RuntimeFunction; | |
| UNWIND_INFO *UnwindInfo; | |
| STATUS Status; | |
| BOOLEAN ReplaceFlag; | |
| BOOLEAN KeepExceptionTableFlag; | |
| 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; | |
| SetUtilityName (UTILITY_NAME); | |
| // | |
| // Assign to fix compile warning | |
| // | |
| InputFileNum = 0; | |
| InputFileName = NULL; | |
| mInImageName = NULL; | |
| OutImageName = NULL; | |
| ModuleType = NULL; | |
| OutImageType = FW_DUMMY_IMAGE; | |
| 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; | |
| Optional32 = NULL; | |
| Optional64 = NULL; | |
| KeepExceptionTableFlag = FALSE; | |
| KeepZeroPendingFlag = 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 (OutImageType != FW_TE_IMAGE) { | |
| OutImageType = FW_EFI_IMAGE; | |
| } | |
| argc -= 2; | |
| argv += 2; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--stripped") == 0)) { | |
| OutImageType = FW_RELOC_STRIPEED_IMAGE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--acpi") == 0)) { | |
| OutImageType = FW_ACPI_IMAGE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--terse") == 0)) { | |
| OutImageType = FW_TE_IMAGE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-u") == 0) || (stricmp (argv[0], "--dump") == 0)) { | |
| OutImageType = DUMP_TE_HEADER; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--exe2bin") == 0)) { | |
| OutImageType = FW_BIN_IMAGE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-z") == 0) || (stricmp (argv[0], "--zero") == 0)) { | |
| OutImageType = FW_ZERO_DEBUG_IMAGE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--stamp") == 0)) { | |
| OutImageType = 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], "--keepzeropending") == 0) { | |
| KeepZeroPendingFlag = TRUE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-m") == 0) || (stricmp (argv[0], "--mcifile") == 0)) { | |
| OutImageType = FW_MCI_IMAGE; | |
| argc --; | |
| argv ++; | |
| continue; | |
| } | |
| if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--join") == 0)) { | |
| OutImageType = 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], "-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, currnt input level is %d", 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 (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!"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| 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!"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); | |
| } | |
| InputFileName [InputFileNum ++] = argv[0]; | |
| argc --; | |
| argv ++; | |
| } | |
| VerboseMsg ("%s tool start.", UTILITY_NAME); | |
| if (OutImageType == 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 ((OutImageType == FW_MERGE_IMAGE) && ReplaceFlag) { | |
| Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with -j 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 (OutImageType) { | |
| 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 ("Conver 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; | |
| 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 (OutImageName, "rb"); | |
| if (fpOut != NULL) { | |
| 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 = fopen (OutImageName, "wb"); | |
| if (!fpOut) { | |
| Error (NULL, 0, 0001, "Error opening output file", OutImageName); | |
| goto Finish; | |
| } | |
| VerboseMsg ("Output file name is %s", OutImageName); | |
| } else if (!ReplaceFlag) { | |
| if (OutImageType == DUMP_TE_HEADER) { | |
| fpOut = stdout; | |
| } else { | |
| Error (NULL, 0, 1001, "Missing option", "output file"); | |
| goto Finish; | |
| } | |
| } | |
| // | |
| // Combine MciBinary files to one file | |
| // | |
| if (OutImageType == FW_MERGE_IMAGE) { | |
| for (Index = 0; Index < InputFileNum; Index ++) { | |
| fpIn = fopen (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 (OutImageType == FW_MCI_IMAGE) { | |
| fpIn = fopen (mInImageName, "r"); | |
| if (!fpIn) { | |
| 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, FileLength, 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.", CheckSum, mInImageName); | |
| goto Finish; | |
| } | |
| // | |
| // Open the output file and write the buffer contents | |
| // | |
| if (fpOut != NULL) { | |
| if (fwrite (FileBuffer, FileLength, 1, fpOut) != 1) { | |
| Error (NULL, 0, 0002, "Error writing file", OutImageName); | |
| goto Finish; | |
| } | |
| } | |
| if (ReplaceFlag) { | |
| fpInOut = fopen (mInImageName, "wb"); | |
| if (fpInOut != NULL) { | |
| Error (NULL, 0, 0001, "Error opening file", mInImageName); | |
| goto Finish; | |
| } | |
| if (fwrite (FileBuffer, FileLength, 1, fpInOut) != 1) { | |
| Error (NULL, 0, 0002, "Error writing file", mInImageName); | |
| goto Finish; | |
| } | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength); | |
| // | |
| // Convert Mci.TXT to Mci.bin file successfully | |
| // | |
| goto Finish; | |
| } | |
| // | |
| // Open input file and read file data into file buffer. | |
| // | |
| fpIn = fopen (mInImageName, "rb"); | |
| if (!fpIn) { | |
| Error (NULL, 0, 0001, "Error opening file", mInImageName); | |
| 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); | |
| DebugMsg (NULL, 0, 9, "input file info", "the input file size is %d bytes", FileLength); | |
| // | |
| // Replace file | |
| // | |
| if (ReplaceFlag) { | |
| fpInOut = fopen (mInImageName, "wb"); | |
| if (!fpInOut) { | |
| Error (NULL, 0, 0001, "Error opening file", mInImageName); | |
| goto Finish; | |
| } | |
| } | |
| // | |
| // Dump TeImage Header into output file. | |
| // | |
| if (OutImageType == 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; | |
| } | |
| 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", TEImageHeader.AddressOfEntryPoint); | |
| fprintf (fpInOut, "%17X base of code\n", TEImageHeader.BaseOfCode); | |
| fprintf (fpInOut, "%17lX image base\n", (long unsigned int)TEImageHeader.ImageBase); | |
| fprintf (fpInOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", TEImageHeader.DataDirectory[0].VirtualAddress, TEImageHeader.DataDirectory[0].Size); | |
| fprintf (fpInOut, "%17X [%8X] RVA [size] of Debug Directory\n", TEImageHeader.DataDirectory[1].VirtualAddress, 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", TEImageHeader.AddressOfEntryPoint); | |
| fprintf (fpOut, "%17X base of code\n", TEImageHeader.BaseOfCode); | |
| fprintf (fpOut, "%17lX image base\n", (long unsigned int)TEImageHeader.ImageBase); | |
| fprintf (fpOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", TEImageHeader.DataDirectory[0].VirtualAddress, TEImageHeader.DataDirectory[0].Size); | |
| fprintf (fpOut, "%17X [%8X] RVA [size] of Debug Directory\n", TEImageHeader.DataDirectory[1].VirtualAddress, TEImageHeader.DataDirectory[1].Size); | |
| } | |
| goto Finish; | |
| } | |
| // | |
| // Following code to convert dll to efi image or te image. | |
| // Get new image type | |
| // | |
| if ((OutImageType == FW_EFI_IMAGE) || (OutImageType == FW_TE_IMAGE)) { | |
| if (ModuleType == NULL) { | |
| if (OutImageType == FW_EFI_IMAGE) { | |
| Error (NULL, 0, 1001, "Missing option", "EFI_FILETYPE"); | |
| goto Finish; | |
| } else if (OutImageType == 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_DRIVER") == 0 || | |
| stricmp (ModuleType, "SMM_CORE") == 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 EFL image to PeImage | |
| // | |
| if (IsElfHeader(FileBuffer)) { | |
| VerboseMsg ("Convert the input ELF Image to Pe Image"); | |
| ConvertElf(&FileBuffer, &FileLength); | |
| } | |
| // | |
| // Remove reloc section from PE or TE image | |
| // | |
| if (OutImageType == 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 offical UEFI value. | |
| PeHdr->Pe32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMT; | |
| } | |
| // | |
| // Extract bin data from Pe image. | |
| // | |
| if (OutImageType == 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 | |
| // | |
| if (fpOut != NULL) { | |
| fwrite (FileBuffer + PeHdr->Pe32.OptionalHeader.SizeOfHeaders, 1, FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders, fpOut); | |
| } | |
| if (fpInOut != NULL) { | |
| fwrite (FileBuffer + PeHdr->Pe32.OptionalHeader.SizeOfHeaders, 1, FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders, fpInOut); | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders); | |
| goto Finish; | |
| } | |
| // | |
| // Zero Debug Information of Pe Image | |
| // | |
| if (OutImageType == FW_ZERO_DEBUG_IMAGE) { | |
| Status = ZeroDebugData (FileBuffer, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 3000, "Invalid", "Zero DebugData Error status is 0x%lx", (UINTN) Status); | |
| goto Finish; | |
| } | |
| if (fpOut != NULL) { | |
| fwrite (FileBuffer, 1, FileLength, fpOut); | |
| } | |
| if (fpInOut != NULL) { | |
| fwrite (FileBuffer, 1, FileLength, fpInOut); | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength); | |
| goto Finish; | |
| } | |
| // | |
| // Set Time Stamp of Pe Image | |
| // | |
| if (OutImageType == FW_SET_STAMP_IMAGE) { | |
| Status = SetStamp (FileBuffer, TimeStamp); | |
| if (EFI_ERROR (Status)) { | |
| goto Finish; | |
| } | |
| if (fpOut != NULL) { | |
| fwrite (FileBuffer, 1, FileLength, fpOut); | |
| } | |
| if (fpInOut != NULL) { | |
| fwrite (FileBuffer, 1, FileLength, fpInOut); | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength); | |
| goto Finish; | |
| } | |
| // | |
| // Extract acpi data from pe image. | |
| // | |
| if (OutImageType == 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 | |
| // | |
| if (fpOut != NULL) { | |
| fwrite (FileBuffer + SectionHeader->PointerToRawData, 1, FileLength, fpOut); | |
| } | |
| if (fpInOut != NULL) { | |
| fwrite (FileBuffer + SectionHeader->PointerToRawData, 1, FileLength, fpInOut); | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength); | |
| goto Finish; | |
| } | |
| } | |
| 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] = 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; | |
| Optional32->MajorLinkerVersion = 0; | |
| Optional32->MinorLinkerVersion = 0; | |
| 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 Execption 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 %d", SectionHeader->SizeOfRawData - AllignedRelocSize); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { | |
| Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; | |
| Optional64->MajorLinkerVersion = 0; | |
| Optional64->MinorLinkerVersion = 0; | |
| 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) || PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) { | |
| 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)); | |
| } | |
| } | |
| } | |
| memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION)); | |
| } | |
| // | |
| // Zero Execption 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 %d", 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); | |
| } | |
| } | |
| // | |
| // Zero ExceptionTable Xdata | |
| // | |
| if (!KeepExceptionTableFlag) { | |
| SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); | |
| ZeroXdataSection(mInImageName, FileBuffer, SectionHeader, PeHdr->Pe32.FileHeader.NumberOfSections); | |
| } | |
| // | |
| // Zero Time/Data field | |
| // | |
| ZeroDebugData (FileBuffer, FALSE); | |
| if (OutImageType == 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 %X", | |
| TEImageHeader.Machine, TEImageHeader.NumberOfSections, TEImageHeader.StrippedSize, TEImageHeader.AddressOfEntryPoint, TEImageHeader.BaseOfCode, TEImageHeader.ImageBase); | |
| // | |
| // Update Image to TeImage | |
| // | |
| if (fpOut != NULL) { | |
| fwrite (&TEImageHeader, 1, sizeof (EFI_TE_IMAGE_HEADER), fpOut); | |
| fwrite (FileBuffer + TEImageHeader.StrippedSize, 1, FileLength - TEImageHeader.StrippedSize, fpOut); | |
| } | |
| if (fpInOut != NULL) { | |
| fwrite (&TEImageHeader, 1, sizeof (EFI_TE_IMAGE_HEADER), fpInOut); | |
| fwrite (FileBuffer + TEImageHeader.StrippedSize, 1, FileLength - TEImageHeader.StrippedSize, fpInOut); | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength - TEImageHeader.StrippedSize); | |
| goto Finish; | |
| } | |
| WriteFile: | |
| // | |
| // Update Image to EfiImage | |
| // | |
| if (fpOut != NULL) { | |
| fwrite (FileBuffer, 1, FileLength, fpOut); | |
| } | |
| if (fpInOut != NULL) { | |
| fwrite (FileBuffer, 1, FileLength, fpInOut); | |
| } | |
| VerboseMsg ("the size of output file is %d bytes", FileLength); | |
| Finish: | |
| if (fpInOut != NULL) { | |
| if (GetUtilityStatus () != STATUS_SUCCESS) { | |
| // | |
| // when file updates failed, original file is still recoveried. | |
| // | |
| fwrite (FileBuffer, 1, FileLength, 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 (OutImageName, "wb"); | |
| fwrite (OutputFileBuffer, 1, OutputFileLength, fpOut); | |
| fclose (fpOut); | |
| free (OutputFileBuffer); | |
| } | |
| } | |
| } | |
| 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 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; | |
| UINT32 *NewTimeStamp; | |
| // | |
| // Init variable. | |
| // | |
| DebugDirectoryEntryRva = 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. | |
| // | |
| 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; | |
| if (ZeroDebugFlag) { | |
| Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0; | |
| Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0; | |
| } | |
| } | |
| } 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; | |
| 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; | |
| 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); | |
| DebugEntry->TimeDateStamp = 0; | |
| if (ZeroDebugFlag) { | |
| memset (FileBuffer + DebugEntry->FileOffset, 0, DebugEntry->SizeOfData); | |
| memset (DebugEntry, 0, sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)); | |
| } | |
| } | |
| 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; | |
| ExportDirectoryEntryRva = 0; | |
| ResourceDirectoryEntryRva = 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); | |
| 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; | |
| 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; | |
| 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(*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(cptr[0]) == 'd') && (tolower(cptr[1]) == 'd') && isspace (cptr[2])) { | |
| // | |
| // Skip blanks and look for a hex digit | |
| // | |
| cptr += 3; | |
| for (; *cptr && isspace(*cptr); cptr++) { | |
| } | |
| if (isxdigit (*cptr)) { | |
| if (sscanf (cptr, "%X", Data) != 1) { | |
| return STATUS_ERROR; | |
| } | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| return STATUS_ERROR; | |
| } |