]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenFw/GenFw.c
Hot fixing for the bug that GenFw can not convert ELF to PE format correctly, the...
[mirror_edk2.git] / BaseTools / Source / C / GenFw / GenFw.c
1 /** @file
2
3 Copyright (c) 2004 - 2009, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 GenFw.c
15
16 Abstract:
17
18 Converts a pe32+ image to an FW, Te image type, or other specific image.
19
20 **/
21
22 #include "WinNtInclude.h"
23
24 #ifndef __GNUC__
25 #include <windows.h>
26 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <ctype.h>
32
33 #include <Common/UefiBaseTypes.h>
34 #include <IndustryStandard/PeImage.h>
35
36 //
37 // Acpi Table definition
38 //
39 #include <IndustryStandard/Acpi.h>
40 #include <IndustryStandard/Acpi1_0.h>
41 #include <IndustryStandard/Acpi2_0.h>
42 #include <IndustryStandard/Acpi3_0.h>
43 #include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
44
45 #include "CommonLib.h"
46 #include "EfiUtilityMsgs.h"
47
48 #include "elf_common.h"
49 #include "elf32.h"
50 #include "elf64.h"
51
52
53 //
54 // Version of this utility
55 //
56 #define UTILITY_NAME "GenFw"
57 #define UTILITY_MAJOR_VERSION 0
58 #define UTILITY_MINOR_VERSION 2
59
60 //
61 // Action for this tool.
62 //
63 #define FW_DUMMY_IMAGE 0
64 #define FW_EFI_IMAGE 1
65 #define FW_TE_IMAGE 2
66 #define FW_ACPI_IMAGE 3
67 #define FW_BIN_IMAGE 4
68 #define FW_ZERO_DEBUG_IMAGE 5
69 #define FW_SET_STAMP_IMAGE 6
70 #define FW_MCI_IMAGE 7
71 #define FW_MERGE_IMAGE 8
72 #define FW_RELOC_STRIPEED_IMAGE 9
73
74 #define DUMP_TE_HEADER 0x11
75
76 #define DEFAULT_MC_PAD_BYTE_VALUE 0xFF
77 #define DEFAULT_MC_ALIGNMENT 16
78
79 #ifndef _MAX_PATH
80 #define _MAX_PATH 500
81 #endif
82
83 #define STATUS_IGNORE 0xA
84 //
85 // Structure definition for a microcode header
86 //
87 typedef struct {
88 UINT32 HeaderVersion;
89 UINT32 PatchId;
90 UINT32 Date;
91 UINT32 CpuId;
92 UINT32 Checksum;
93 UINT32 LoaderVersion;
94 UINT32 PlatformId;
95 UINT32 DataSize; // if 0, then TotalSize = 2048, and TotalSize field is invalid
96 UINT32 TotalSize; // number of bytes
97 UINT32 Reserved[3];
98 } MICROCODE_IMAGE_HEADER;
99
100 STATIC CHAR8 *mInImageName;
101
102 STATIC
103 EFI_STATUS
104 ZeroDebugData (
105 IN OUT UINT8 *FileBuffer,
106 BOOLEAN ZeroDebug
107 );
108
109 STATIC
110 EFI_STATUS
111 SetStamp (
112 IN OUT UINT8 *FileBuffer,
113 IN CHAR8 *TimeStamp
114 );
115
116 STATIC
117 STATUS
118 MicrocodeReadData (
119 FILE *InFptr,
120 UINT32 *Data
121 );
122
123 STATIC
124 VOID
125 Version (
126 VOID
127 )
128 /*++
129
130 Routine Description:
131
132 Print out version information for this utility.
133
134 Arguments:
135
136 None
137
138 Returns:
139
140 None
141
142 --*/
143 {
144 fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
145 }
146
147 STATIC
148 VOID
149 Usage (
150 VOID
151 )
152 /*++
153
154 Routine Description:
155
156 Print Help message.
157
158 Arguments:
159
160 VOID
161
162 Returns:
163
164 None
165
166 --*/
167 {
168 //
169 // Summary usage
170 //
171 fprintf (stdout, "\nUsage: %s [options] <input_file>\n\n", UTILITY_NAME);
172
173 //
174 // Copyright declaration
175 //
176 fprintf (stdout, "Copyright (c) 2007, Intel Corporation. All rights reserved.\n\n");
177
178 //
179 // Details Option
180 //
181 fprintf (stdout, "Options:\n");
182 fprintf (stdout, " -o FileName, --outputfile FileName\n\
183 File will be created to store the ouput content.\n");
184 fprintf (stdout, " -e EFI_FILETYPE, --efiImage EFI_FILETYPE\n\
185 Create Efi Image. EFI_FILETYPE is one of BASE, SEC,\n\
186 PEI_CORE, PEIM, DXE_CORE, DXE_DRIVER, UEFI_APPLICATION,\n\
187 DXE_SAL_DRIVER, UEFI_DRIVER, DXE_RUNTIME_DRIVER, \n\
188 DXE_SMM_DRIVER, SECURITY_CORE, COMBINED_PEIM_DRIVER, \n\
189 PIC_PEIM, RELOCATABLE_PEIM, BS_DRIVER, RT_DRIVER,\n\
190 APPLICATION, SAL_RT_DRIVER to support all module types\n\
191 It can only be used together with --keepexceptiontable,\n\
192 --keepzeropending, -r, -o option.It is a action option.\n\
193 If it is combined with other action options, the later\n\
194 input action option will override the previous one.\n");
195 fprintf (stdout, " -c, --acpi Create Acpi table.\n\
196 It can't be combined with other action options\n\
197 except for -o, -r option. It is a action option.\n\
198 If it is combined with other action options, the later\n\
199 input action option will override the previous one.\n");
200 fprintf (stdout, " -t, --terse Create Te Image.\n\
201 It can only be used together with --keepexceptiontable,\n\
202 --keepzeropending, -r, -o option.It is a action option.\n\
203 If it is combined with other action options, the later\n\
204 input action option will override the previous one.\n");
205 fprintf (stdout, " -u, --dump Dump TeImage Header.\n\
206 It can't be combined with other action options\n\
207 except for -o, -r option. It is a action option.\n\
208 If it is combined with other action options, the later\n\
209 input action option will override the previous one.\n");
210 fprintf (stdout, " -z, --zero Zero the Debug Data Fields in the PE input image file.\n\
211 It also zeros the time stamp fields.\n\
212 This option can be used to compare the binary efi image.\n\
213 It can't be combined with other action options\n\
214 except for -o, -r option. It is a action option.\n\
215 If it is combined with other action options, the later\n\
216 input action option will override the previous one.\n");
217 fprintf (stdout, " -b, --exe2bin Convert the input EXE to the output BIN file.\n\
218 It can't be combined with other action options\n\
219 except for -o, -r option. It is a action option.\n\
220 If it is combined with other action options, the later\n\
221 input action option will override the previous one.\n");;
222 fprintf (stdout, " -l, --stripped Relocation info stripped from the input PE or TE image.\n\
223 It can't be combined with other action options\n\
224 except for -o, -r option. It is a action option.\n\
225 If it is combined with other action options, the later\n\
226 input action option will override the previous one.\n");
227 fprintf (stdout, " -s timedate, --stamp timedate\n\
228 timedate format is \"yyyy-mm-dd 00:00:00\". if timedata \n\
229 is set to NOW, current system time is used. The support\n\
230 date scope is 1970-1-1 8:0:0 ~ 2038-1-19 3:14:07\n\
231 It can't be combined with other action options\n\
232 except for -o, -r option. It is a action option.\n\
233 If it is combined with other action options, the later\n\
234 input action option will override the previous one.\n");
235 fprintf (stdout, " -m, --mcifile Convert input microcode txt file to microcode bin file.\n\
236 It can't be combined with other action options\n\
237 except for -o option. It is a action option.\n\
238 If it is combined with other action options, the later\n\
239 input action option will override the previous one.\n");
240 fprintf (stdout, " -j, --join Combine multi microcode bin files to one file.\n\
241 It can be specified with -a, -p, -o option.\n\
242 No other options can be combined with it.\n\
243 If it is combined with other action options, the later\n\
244 input action option will override the previous one.\n");
245 fprintf (stdout, " -a NUM, --align NUM NUM is one HEX or DEC format alignment value.\n\
246 This option is only used together with -j option.\n");
247 fprintf (stdout, " -p NUM, --pad NUM NUM is one HEX or DEC format padding value.\n\
248 This option is only used together with -j option.\n");
249 fprintf (stdout, " --keepexceptiontable Don't clear exception table.\n\
250 This option can be used together with -e or -t.\n\
251 It doesn't work for other options.\n");
252 fprintf (stdout, " --keepzeropending Don't strip zero pending of .reloc.\n\
253 This option can be used together with -e or -t.\n\
254 It doesn't work for other options.\n");
255 fprintf (stdout, " -r, --replace Overwrite the input file with the output content.\n\
256 If more input files are specified,\n\
257 the last input file will be as the output file.\n");
258 fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
259 fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
260 fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
261 fprintf (stdout, " --version Show program's version number and exit\n");
262 fprintf (stdout, " -h, --help Show this help message and exit\n");
263 }
264
265 STATIC
266 STATUS
267 CheckAcpiTable (
268 VOID *AcpiTable,
269 UINT32 Length
270 )
271 /*++
272
273 Routine Description:
274
275 Check Acpi Table
276
277 Arguments:
278
279 AcpiTable Buffer for AcpiSection
280 Length AcpiSection Length
281
282 Returns:
283
284 0 success
285 non-zero otherwise
286
287 --*/
288 {
289 EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader;
290 EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
291 UINT32 ExpectedLength;
292
293 AcpiHeader = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable;
294
295 //
296 // Generic check for AcpiTable length.
297 //
298 if (AcpiHeader->Length > Length) {
299 Error (NULL, 0, 3000, "Invalid", "AcpiTable length check failed.", NULL);
300 return STATUS_ERROR;
301 }
302
303 //
304 // Currently, we only check must-have tables: FADT, FACS, DSDT,
305 // and some important tables: MADT, MCFG.
306 //
307 switch (AcpiHeader->Signature) {
308
309 //
310 // "FACP" Fixed ACPI Description Table
311 //
312 case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
313 switch (AcpiHeader->Revision) {
314 case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
315 ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE);
316 break;
317 case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
318 ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE);
319 break;
320 case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
321 ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE);
322 break;
323 default:
324 Error (NULL, 0, 3000, "Invalid", "FACP revision check failed.");
325 return STATUS_ERROR;
326 }
327 if (ExpectedLength != AcpiHeader->Length) {
328 Error (NULL, 0, 3000, "Invalid", "FACP length check failed.");
329 return STATUS_ERROR;
330 }
331 break;
332
333 //
334 // "FACS" Firmware ACPI Control Structure
335 //
336 case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
337 Facs = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable;
338 if ((Facs->Version != 0) &&
339 (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
340 (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)){
341 Error (NULL, 0, 3000, "Invalid", "FACS version check failed.");
342 return STATUS_ERROR;
343 }
344 if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&
345 (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&
346 (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) {
347 Error (NULL, 0, 3000, "Invalid", "FACS length check failed.");
348 return STATUS_ERROR;
349 }
350 break;
351
352 //
353 // "DSDT" Differentiated System Description Table
354 //
355 case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
356 if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) {
357 Error (NULL, 0, 3000, "Invalid", "DSDT revision check failed.");
358 return STATUS_ERROR;
359 }
360 if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {
361 Error (NULL, 0, 3000, "Invalid", "DSDT length check failed.");
362 return STATUS_ERROR;
363 }
364 break;
365
366 //
367 // "APIC" Multiple APIC Description Table
368 //
369 case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
370 if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&
371 (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&
372 (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) {
373 Error (NULL, 0, 3000, "Invalid", "APIC revision check failed.");
374 return STATUS_ERROR;
375 }
376 if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32)) {
377 Error (NULL, 0, 3000, "Invalid", "APIC length check failed.");
378 return STATUS_ERROR;
379 }
380 break;
381
382 //
383 // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table
384 //
385 case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:
386 if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) {
387 Error (NULL, 0, 3000, "Invalid", "MCFG revision check failed.");
388 return STATUS_ERROR;
389 }
390 if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64)) {
391 Error (NULL, 0, 3000, "Invalid", "MCFG length check failed.");
392 return STATUS_ERROR;
393 }
394 break;
395
396 //
397 // Other table pass check
398 //
399 default:
400 break;
401 }
402
403 return STATUS_SUCCESS;
404 }
405
406
407 INTN
408 IsElfHeader(
409 UINT8 *FileBuffer
410 )
411 {
412 return (FileBuffer[EI_MAG0] == ELFMAG0
413 && FileBuffer[EI_MAG1] == ELFMAG1
414 && FileBuffer[EI_MAG2] == ELFMAG2
415 && FileBuffer[EI_MAG3] == ELFMAG3);
416 }
417
418 typedef Elf32_Shdr Elf_Shdr;
419 typedef Elf32_Ehdr Elf_Ehdr;
420 typedef Elf32_Rel Elf_Rel;
421 typedef Elf32_Sym Elf_Sym;
422 typedef Elf32_Phdr Elf_Phdr;
423 typedef Elf32_Dyn Elf_Dyn;
424
425 #define ELFCLASS ELFCLASS32
426 #define ELF_R_TYPE(r) ELF32_R_TYPE(r)
427 #define ELF_R_SYM(r) ELF32_R_SYM(r)
428
429 //
430 // Well known ELF structures.
431 //
432 Elf_Ehdr *Ehdr;
433 Elf_Shdr *ShdrBase;
434 Elf_Phdr *gPhdrBase;
435
436 //
437 // PE section alignment.
438 //
439 const UINT32 CoffAlignment = 0x20;
440 const UINT32 CoffNbrSections = 4;
441
442 //
443 // Current offset in coff file.
444 //
445 UINT32 CoffOffset;
446
447 //
448 // Result Coff file in memory.
449 //
450 UINT8 *CoffFile = NULL;
451 //
452 // ELF sections to offset in Coff file.
453 //
454 UINT32 *CoffSectionsOffset = NULL;
455
456 //
457 // Offset in Coff file of headers and sections.
458 //
459 UINT32 NtHdrOffset;
460 UINT32 TableOffset;
461 UINT32 TextOffset;
462 UINT32 DataOffset;
463 UINT32 RelocOffset;
464
465 EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
466 UINT16 *CoffEntryRel;
467
468 UINT32
469 CoffAlign(
470 UINT32 Offset
471 )
472 {
473 return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
474 }
475
476 Elf_Shdr *
477 GetShdrByIndex(
478 UINT32 Num
479 )
480 {
481 if (Num >= Ehdr->e_shnum)
482 return NULL;
483 return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
484 }
485
486 INTN
487 CheckElfHeader(
488 VOID
489 )
490 {
491 //
492 // Note: Magic has already been tested.
493 //
494 if (Ehdr->e_ident[EI_CLASS] != ELFCLASS) {
495 Error (NULL, 0, 3000, "Unsupported", "%s needs to be ported for 64-bit ELF.", mInImageName);
496 return 0;
497 }
498 if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
499 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");
500 return 0;
501 }
502 if ((Ehdr->e_type != ET_EXEC) && (Ehdr->e_type != ET_DYN)) {
503 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");
504 return 0;
505 }
506 if (!((Ehdr->e_machine == EM_386) || (Ehdr->e_machine == EM_ARM))) {
507 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_386 or EM_ARM");
508 return 0;
509 }
510 if (Ehdr->e_version != EV_CURRENT) {
511 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%d) not EV_CURRENT (%d)", Ehdr->e_version, EV_CURRENT);
512 return 0;
513 }
514
515 //
516 // Find the section header table
517 //
518 ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
519 gPhdrBase = (Elf_Phdr *)((UINT8 *)Ehdr + Ehdr->e_phoff);
520
521 CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));
522
523 memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));
524 return 1;
525 }
526
527 int
528 IsTextShdr(
529 Elf_Shdr *Shdr
530 )
531 {
532 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
533 }
534
535 int
536 IsDataShdr(
537 Elf_Shdr *Shdr
538 )
539 {
540 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
541 }
542
543 VOID
544 CreateSectionHeader(
545 const CHAR8 *Name,
546 UINT32 Offset,
547 UINT32 Size,
548 UINT32 Flags
549 )
550 {
551 EFI_IMAGE_SECTION_HEADER *Hdr;
552 Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset);
553
554 strcpy((char *)Hdr->Name, Name);
555 Hdr->Misc.VirtualSize = Size;
556 Hdr->VirtualAddress = Offset;
557 Hdr->SizeOfRawData = Size;
558 Hdr->PointerToRawData = Offset;
559 Hdr->PointerToRelocations = 0;
560 Hdr->PointerToLinenumbers = 0;
561 Hdr->NumberOfRelocations = 0;
562 Hdr->NumberOfLinenumbers = 0;
563 Hdr->Characteristics = Flags;
564
565 TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
566 }
567
568 VOID
569 ScanSections(
570 VOID
571 )
572 {
573 UINT32 i;
574 EFI_IMAGE_DOS_HEADER *DosHdr;
575 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
576 UINT32 CoffEntry;
577
578 CoffEntry = 0;
579 CoffOffset = 0;
580
581 //
582 // Coff file start with a DOS header.
583 //
584 CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
585 NtHdrOffset = CoffOffset;
586 switch (Ehdr->e_machine) {
587 case EM_386:
588 case EM_ARM:
589 CoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
590 break;
591 case EM_X86_64:
592 case EM_IA_64:
593 CoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);
594 break;
595 default:
596 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)Ehdr->e_machine);
597 CoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
598 break;
599 }
600
601 TableOffset = CoffOffset;
602 CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
603
604 //
605 // First text sections.
606 //
607 CoffOffset = CoffAlign(CoffOffset);
608 TextOffset = CoffOffset;
609 for (i = 0; i < Ehdr->e_shnum; i++) {
610 Elf_Shdr *shdr = GetShdrByIndex(i);
611 if (IsTextShdr(shdr)) {
612 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
613 // the alignment field is valid
614 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
615 // if the section address is aligned we must align PE/COFF
616 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
617 } else if ((shdr->sh_addr % shdr->sh_addralign) != (CoffOffset % shdr->sh_addralign)) {
618 // ARM RVCT tools have behavior outside of the ELF specification to try
619 // and make images smaller. If sh_addr is not aligned to sh_addralign
620 // then the section needs to preserve sh_addr MOD sh_addralign.
621 // Normally doing nothing here works great.
622 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
623 }
624 }
625
626 /* Relocate entry. */
627 if ((Ehdr->e_entry >= shdr->sh_addr) &&
628 (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
629 CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
630 }
631 CoffSectionsOffset[i] = CoffOffset;
632 CoffOffset += shdr->sh_size;
633 }
634 }
635
636 if (Ehdr->e_machine != EM_ARM) {
637 CoffOffset = CoffAlign(CoffOffset);
638 }
639
640 //
641 // Then data sections.
642 //
643 DataOffset = CoffOffset;
644 for (i = 0; i < Ehdr->e_shnum; i++) {
645 Elf_Shdr *shdr = GetShdrByIndex(i);
646 if (IsDataShdr(shdr)) {
647 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
648 // the alignment field is valid
649 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
650 // if the section address is aligned we must align PE/COFF
651 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
652 } else if ((shdr->sh_addr % shdr->sh_addralign) != (CoffOffset % shdr->sh_addralign)) {
653 // ARM RVCT tools have behavior outside of the ELF specification to try
654 // and make images smaller. If sh_addr is not aligned to sh_addralign
655 // then the section needs to preserve sh_addr MOD sh_addralign.
656 // Normally doing nothing here works great.
657 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
658 }
659 }
660
661 CoffSectionsOffset[i] = CoffOffset;
662 CoffOffset += shdr->sh_size;
663 }
664 }
665 CoffOffset = CoffAlign(CoffOffset);
666
667 RelocOffset = CoffOffset;
668
669 //
670 // Allocate base Coff file. Will be expanded later for relocations.
671 //
672 CoffFile = (UINT8 *)malloc(CoffOffset);
673 memset(CoffFile, 0, CoffOffset);
674
675 //
676 // Fill headers.
677 //
678 DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
679 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
680 DosHdr->e_lfanew = NtHdrOffset;
681
682 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(CoffFile + NtHdrOffset);
683
684 NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE;
685
686 switch (Ehdr->e_machine) {
687 case EM_386:
688 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
689 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
690 break;
691 case EM_X86_64:
692 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;
693 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
694 break;
695 case EM_IA_64:
696 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;
697 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
698 break;
699 case EM_ARM:
700 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_ARMT;
701 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
702 break;
703 default:
704 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)Ehdr->e_machine);
705 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
706 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
707 }
708
709 NtHdr->Pe32.FileHeader.NumberOfSections = CoffNbrSections;
710 NtHdr->Pe32.FileHeader.TimeDateStamp = time(NULL);
711 NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0;
712 NtHdr->Pe32.FileHeader.NumberOfSymbols = 0;
713 NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader);
714 NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
715 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
716 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
717 | EFI_IMAGE_FILE_32BIT_MACHINE;
718
719 NtHdr->Pe32.OptionalHeader.SizeOfCode = DataOffset - TextOffset;
720 NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
721 NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0;
722 NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry;
723
724 NtHdr->Pe32.OptionalHeader.BaseOfCode = TextOffset;
725
726 NtHdr->Pe32.OptionalHeader.BaseOfData = DataOffset;
727 NtHdr->Pe32.OptionalHeader.ImageBase = 0;
728 NtHdr->Pe32.OptionalHeader.SectionAlignment = CoffAlignment;
729 NtHdr->Pe32.OptionalHeader.FileAlignment = CoffAlignment;
730 NtHdr->Pe32.OptionalHeader.SizeOfImage = 0;
731
732 NtHdr->Pe32.OptionalHeader.SizeOfHeaders = TextOffset;
733 NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
734
735 //
736 // Section headers.
737 //
738 if ((DataOffset - TextOffset) > 0) {
739 CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
740 EFI_IMAGE_SCN_CNT_CODE
741 | EFI_IMAGE_SCN_MEM_EXECUTE
742 | EFI_IMAGE_SCN_MEM_READ);
743 } else {
744 // Don't make a section of size 0.
745 NtHdr->Pe32.FileHeader.NumberOfSections--;
746 }
747
748 if ((RelocOffset - TextOffset) > 0) {
749 CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
750 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
751 | EFI_IMAGE_SCN_MEM_WRITE
752 | EFI_IMAGE_SCN_MEM_READ);
753 } else {
754 // Don't make a section of size 0.
755 NtHdr->Pe32.FileHeader.NumberOfSections--;
756 }
757 }
758
759 VOID
760 WriteSections(
761 int (*Filter)(Elf_Shdr *)
762 )
763 {
764 UINT32 Idx;
765 Elf_Shdr *SecShdr;
766 UINT32 SecOffset;
767
768 //
769 // First: copy sections.
770 //
771 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
772 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
773 if ((*Filter)(Shdr)) {
774 switch (Shdr->sh_type) {
775 case SHT_PROGBITS:
776 /* Copy. */
777 memcpy(CoffFile + CoffSectionsOffset[Idx],
778 (UINT8*)Ehdr + Shdr->sh_offset,
779 Shdr->sh_size);
780 break;
781
782 case SHT_NOBITS:
783 memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
784 break;
785
786 default:
787 //
788 // Ignore for unkown section type.
789 //
790 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (UINTN)Shdr->sh_type);
791 break;
792 }
793 }
794 }
795
796 //
797 // Second: apply relocations.
798 //
799 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
800 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
801 if (RelShdr->sh_type != SHT_REL)
802 continue;
803 SecShdr = GetShdrByIndex(RelShdr->sh_info);
804 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
805 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
806 UINT32 RelIdx;
807 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
808 UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
809
810 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
811 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
812 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
813 Elf_Shdr *SymShdr;
814 UINT8 *Targ;
815
816 if (Sym->st_shndx == SHN_UNDEF
817 || Sym->st_shndx == SHN_ABS
818 || Sym->st_shndx > Ehdr->e_shnum) {
819 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);
820 }
821 SymShdr = GetShdrByIndex(Sym->st_shndx);
822
823 //
824 // Note: r_offset in a memory address.
825 // Convert it to a pointer in the coff file.
826 //
827 Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
828
829 if (Ehdr->e_machine == EM_386) {
830 switch (ELF_R_TYPE(Rel->r_info)) {
831 case R_386_NONE:
832 break;
833 case R_386_32:
834 //
835 // Absolute relocation.
836 //
837 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
838 + CoffSectionsOffset[Sym->st_shndx];
839 break;
840 case R_386_PC32:
841 //
842 // Relative relocation: Symbol - Ip + Addend
843 //
844 *(UINT32 *)Targ = *(UINT32 *)Targ
845 + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
846 - (SecOffset - SecShdr->sh_addr);
847 break;
848 default:
849 Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF_R_TYPE(Rel->r_info));
850 }
851 } else if (Ehdr->e_machine == EM_ARM) {
852 switch (ELF32_R_TYPE(Rel->r_info)) {
853 case R_ARM_RBASE: // No relocation - no action required
854 case R_ARM_PC24: // PC-relative relocations don't require modification
855 case R_ARM_XPC25: // PC-relative relocations don't require modification
856 break;
857 case R_ARM_ABS32:
858 case R_ARM_RABS32:
859 //
860 // Absolute relocation.
861 //
862 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + CoffSectionsOffset[Sym->st_shndx];
863 break;
864 default:
865 Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF32_R_TYPE(Rel->r_info));
866 }
867 }
868 }
869 }
870 }
871 }
872
873 VOID
874 CoffAddFixupEntry(
875 UINT16 Val
876 )
877 {
878 *CoffEntryRel = Val;
879 CoffEntryRel++;
880 CoffBaseRel->SizeOfBlock += 2;
881 CoffOffset += 2;
882 }
883
884 VOID
885 CoffAddFixup(
886 UINT32 Offset,
887 UINT8 Type
888 )
889 {
890 if (CoffBaseRel == NULL
891 || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
892 if (CoffBaseRel != NULL) {
893 //
894 // Add a null entry (is it required ?)
895 //
896 CoffAddFixupEntry (0);
897 //
898 // Pad for alignment.
899 //
900 if (CoffOffset % 4 != 0)
901 CoffAddFixupEntry (0);
902 }
903
904 CoffFile = realloc
905 (CoffFile,
906 CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
907 memset(CoffFile + CoffOffset, 0,
908 sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
909
910 CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
911 CoffBaseRel->VirtualAddress = Offset & ~0xfff;
912 CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
913
914 CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
915 CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
916 }
917
918 //
919 // Fill the entry.
920 //
921 CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
922 }
923
924
925 Elf_Phdr *
926 GetPhdrByIndex (
927 UINT32 num
928 )
929 {
930 if (num >= Ehdr->e_phnum) {
931 return NULL;
932 }
933
934 return (Elf32_Phdr *)((UINT8*)gPhdrBase + num * Ehdr->e_phentsize);
935 }
936
937
938 VOID
939 WriteRelocations(
940 VOID
941 )
942 {
943 UINT32 Index;
944 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
945 EFI_IMAGE_DATA_DIRECTORY *Dir;
946 BOOLEAN FoundRelocations;
947 Elf_Dyn *Dyn;
948 Elf_Rel *Rel;
949 UINTN RelElementSize;
950 UINTN RelSize;
951 UINTN RelOffset;
952 UINTN K;
953 UINT8 *Targ;
954 Elf32_Phdr *DynamicSegment;
955 Elf32_Phdr *TargetSegment;
956
957 for (Index = 0, FoundRelocations = FALSE; Index < Ehdr->e_shnum; Index++) {
958 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
959 if (RelShdr->sh_type == SHT_REL) {
960 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
961 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
962 UINT32 RelIdx;
963 FoundRelocations = TRUE;
964 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
965 Elf_Rel *Rel = (Elf_Rel *)
966 ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
967
968 if (Ehdr->e_machine == EM_386) {
969 switch (ELF_R_TYPE(Rel->r_info)) {
970 case R_386_NONE:
971 case R_386_PC32:
972 break;
973 case R_386_32:
974 CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
975 + (Rel->r_offset - SecShdr->sh_addr),
976 EFI_IMAGE_REL_BASED_HIGHLOW);
977 break;
978 default:
979 Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF_R_TYPE(Rel->r_info));
980 }
981 } else if (Ehdr->e_machine == EM_ARM) {
982 switch (ELF32_R_TYPE(Rel->r_info)) {
983 case R_ARM_RBASE:
984 case R_ARM_PC24:
985 case R_ARM_XPC25:
986 break;
987 case R_ARM_ABS32:
988 case R_ARM_RABS32:
989 CoffAddFixup (
990 CoffSectionsOffset[RelShdr->sh_info]
991 + (Rel->r_offset - SecShdr->sh_addr),
992 EFI_IMAGE_REL_BASED_HIGHLOW
993 );
994 break;
995 default:
996 Error (NULL, 0, 3000, "Invalid", "%s unhandled section type %x.", mInImageName, ELF32_R_TYPE(Rel->r_info));
997 }
998 } else {
999 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %d (processor type).", Ehdr->e_machine);
1000 }
1001 }
1002 }
1003 }
1004 }
1005
1006 if (!FoundRelocations && (Ehdr->e_machine == EM_ARM)) {
1007 /* Try again, but look for PT_DYNAMIC instead of SHT_REL */
1008
1009 for (Index = 0; Index < Ehdr->e_phnum; Index++) {
1010 RelElementSize = 0;
1011 RelSize = 0;
1012 RelOffset = 0;
1013
1014 DynamicSegment = GetPhdrByIndex (Index);
1015
1016 if (DynamicSegment->p_type == PT_DYNAMIC) {
1017 Dyn = (Elf32_Dyn *) ((UINT8 *)Ehdr + DynamicSegment->p_offset);
1018
1019 while (Dyn->d_tag != DT_NULL) {
1020 switch (Dyn->d_tag) {
1021 case DT_REL:
1022 RelOffset = Dyn->d_un.d_val;
1023 break;
1024
1025 case DT_RELSZ:
1026 RelSize = Dyn->d_un.d_val;
1027 break;
1028
1029 case DT_RELENT:
1030 RelElementSize = Dyn->d_un.d_val;
1031 break;
1032 }
1033 Dyn++;
1034 }
1035 if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {
1036 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
1037 }
1038
1039 for (K = 0; K < RelSize; K += RelElementSize) {
1040
1041 Rel = (Elf32_Rel *) ((UINT8 *) Ehdr + DynamicSegment->p_offset + RelOffset + K);
1042
1043 switch (ELF32_R_TYPE (Rel->r_info)) {
1044 case R_ARM_RBASE:
1045 break;
1046 case R_ARM_RABS32:
1047 TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);
1048
1049 // Note: r_offset in a memory address. Convert it to a pointer in the coff file.
1050 Targ = CoffFile + CoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;
1051
1052 *(UINT32 *)Targ = *(UINT32 *)Targ + CoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];
1053
1054 CoffAddFixup (CoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);
1055 break;
1056 default:
1057 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type.", mInImageName);
1058 }
1059 }
1060 break;
1061 }
1062 }
1063 }
1064
1065 //
1066 // Pad by adding empty entries.
1067 //
1068 while (CoffOffset & (CoffAlignment - 1)) {
1069 CoffAddFixupEntry(0);
1070 }
1071
1072
1073 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(CoffFile + NtHdrOffset);
1074 Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1075 Dir->Size = CoffOffset - RelocOffset;
1076 if (Dir->Size == 0) {
1077 // If no relocations, null out the directory entry and don't add the .reloc section
1078 Dir->VirtualAddress = 0;
1079 NtHdr->Pe32.FileHeader.NumberOfSections--;
1080 } else {
1081 Dir->VirtualAddress = RelocOffset;
1082 CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
1083 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1084 | EFI_IMAGE_SCN_MEM_DISCARDABLE
1085 | EFI_IMAGE_SCN_MEM_READ);
1086 }
1087
1088 }
1089
1090 VOID
1091 WriteDebug(
1092 VOID
1093 )
1094 {
1095 UINT32 Len;
1096 UINT32 DebugOffset;
1097 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1098 EFI_IMAGE_DATA_DIRECTORY *DataDir;
1099 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
1100 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
1101
1102 Len = strlen(mInImageName) + 1;
1103 DebugOffset = CoffOffset;
1104
1105 CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
1106 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
1107 + Len;
1108 CoffOffset = CoffAlign(CoffOffset);
1109
1110 CoffFile = realloc(CoffFile, CoffOffset);
1111 memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
1112
1113 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
1114 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
1115 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
1116 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1117 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1118
1119 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
1120 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
1121 strcpy ((char *)(Nb10 + 1), mInImageName);
1122
1123
1124 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(CoffFile + NtHdrOffset);
1125 DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
1126 DataDir->VirtualAddress = DebugOffset;
1127 DataDir->Size = CoffOffset - DebugOffset;
1128 if (DataDir->Size == 0) {
1129 // If no debug, null out the directory entry and don't add the .debug section
1130 DataDir->VirtualAddress = 0;
1131 NtHdr->Pe32.FileHeader.NumberOfSections--;
1132 } else {
1133 DataDir->VirtualAddress = DebugOffset;
1134 CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
1135 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1136 | EFI_IMAGE_SCN_MEM_DISCARDABLE
1137 | EFI_IMAGE_SCN_MEM_READ);
1138
1139 }
1140 }
1141
1142 VOID
1143 ConvertElf (
1144 UINT8 **FileBuffer,
1145 UINT32 *FileLength
1146 )
1147 {
1148 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1149
1150 //
1151 // Check header, read section table.
1152 //
1153 Ehdr = (Elf32_Ehdr*)*FileBuffer;
1154 if (!CheckElfHeader())
1155 return;
1156
1157 VerboseMsg ("Check Efl Image Header");
1158 //
1159 // Compute sections new address.
1160 //
1161
1162 ScanSections();
1163
1164 VerboseMsg ("Compute sections new address.");
1165
1166 //
1167 // Write and relocate sections.
1168 //
1169 WriteSections(IsTextShdr);
1170 WriteSections(IsDataShdr);
1171 VerboseMsg ("Write and relocate sections.");
1172
1173 //
1174 // Translate and write relocations.
1175 //
1176 WriteRelocations();
1177 VerboseMsg ("Translate and write relocations.");
1178
1179 //
1180 // Write debug info.
1181 //
1182 WriteDebug();
1183 VerboseMsg ("Write debug info.");
1184
1185 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(CoffFile + NtHdrOffset);
1186 NtHdr->Pe32.OptionalHeader.SizeOfImage = CoffOffset;
1187
1188 //
1189 // Replace.
1190 //
1191 free(*FileBuffer);
1192 *FileBuffer = CoffFile;
1193 *FileLength = CoffOffset;
1194
1195 //
1196 // Free memory space
1197 //
1198 if (CoffSectionsOffset != NULL) {
1199 free (CoffSectionsOffset);
1200 }
1201 }
1202
1203 void
1204 ZeroXdataSection (
1205 IN CHAR8 *ImageName,
1206 IN OUT UINT8 *FileBuffer,
1207 IN EFI_IMAGE_SECTION_HEADER *SectionHeader,
1208 IN UINT32 SectionTotalNumber
1209 )
1210 {
1211 FILE *fpMapFile;
1212 CHAR8 MapFileName[_MAX_PATH];
1213 CHAR8 Line [MAX_LINE_LEN];
1214 CHAR8 KeyWord [MAX_LINE_LEN];
1215 CHAR8 SectionName [MAX_LINE_LEN];
1216 UINT32 FunctionType = 0;
1217 UINT32 SectionOffset;
1218 UINT32 SectionLength;
1219 UINT32 SectionNumber;
1220 CHAR8 *PdbPointer;
1221 INT32 Index = 0;
1222
1223 for (Index = 0; Index < SectionTotalNumber; Index ++) {
1224 if (stricmp ((char *)SectionHeader[Index].Name, ".zdata") == 0) {
1225 //
1226 // try to zero the customized .zdata section, which is mapped to .xdata
1227 //
1228 memset (FileBuffer + SectionHeader[Index].PointerToRawData, 0, SectionHeader[Index].SizeOfRawData);
1229 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);
1230 return;
1231 }
1232 }
1233 //
1234 // Try to get PDB file name
1235 //
1236 PdbPointer = (CHAR8 *) PeCoffLoaderGetPdbPointer (FileBuffer);
1237 if (PdbPointer != NULL) {
1238 strcpy (MapFileName, PdbPointer);
1239 } else {
1240 strcpy (MapFileName, ImageName);
1241 }
1242
1243 //
1244 // Construct map file name
1245 //
1246 Index = strlen (MapFileName) - 1;
1247 while (Index >= 0 && MapFileName[Index] != '.') {
1248 Index --;
1249 }
1250 if (Index < 0) {
1251 //
1252 // don't know how to costruct map file
1253 //
1254 return;
1255 }
1256
1257 //
1258 // fill map file postfix
1259 //
1260 MapFileName[Index + 1] = 'm';
1261 MapFileName[Index + 2] = 'a';
1262 MapFileName[Index + 3] = 'p';
1263 MapFileName[Index + 4] = '\0';
1264
1265 //
1266 // try opening Map File
1267 //
1268 fpMapFile = fopen (MapFileName, "r");
1269 if (fpMapFile == NULL) {
1270 //
1271 // Can't open Map file. Maybe it doesn't exist.
1272 //
1273 return;
1274 }
1275
1276 //
1277 // Output Functions information into Fv Map file
1278 //
1279 while (fgets (Line, MAX_LINE_LEN, fpMapFile) != NULL) {
1280 //
1281 // Skip blank line
1282 //
1283 if (Line[0] == 0x0a) {
1284 if (FunctionType != 0) {
1285 //
1286 // read all section table data
1287 //
1288 FunctionType = 0;
1289 break;
1290 }
1291 FunctionType = 0;
1292 continue;
1293 }
1294
1295 //
1296 // By Start keyword
1297 //
1298 if (FunctionType == 0) {
1299 sscanf (Line, "%s", KeyWord);
1300 if (stricmp (KeyWord, "Start") == 0) {
1301 //
1302 // function list
1303 //
1304 FunctionType = 1;
1305 }
1306 continue;
1307 }
1308 //
1309 // Printf Function Information
1310 //
1311 if (FunctionType == 1) {
1312 sscanf (Line, "%x:%x %xH %s", &SectionNumber, &SectionOffset, &SectionLength, SectionName);
1313 if (stricmp (SectionName, ".xdata") == 0) {
1314 FunctionType = 2;
1315 break;
1316 }
1317 }
1318 }
1319
1320 if (FunctionType != 2) {
1321 //
1322 // no .xdata section is found
1323 //
1324 fclose (fpMapFile);
1325 return;
1326 }
1327
1328 //
1329 // Zero .xdata Section data
1330 //
1331 memset (FileBuffer + SectionHeader[SectionNumber-1].PointerToRawData + SectionOffset, 0, SectionLength);
1332 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);
1333 fclose (fpMapFile);
1334 return;
1335 }
1336
1337 int
1338 main (
1339 int argc,
1340 char *argv[]
1341 )
1342 /*++
1343
1344 Routine Description:
1345
1346 Main function.
1347
1348 Arguments:
1349
1350 argc - Number of command line parameters.
1351 argv - Array of pointers to command line parameter strings.
1352
1353 Returns:
1354 STATUS_SUCCESS - Utility exits successfully.
1355 STATUS_ERROR - Some error occurred during execution.
1356
1357 --*/
1358 {
1359 UINT32 Type;
1360 UINT32 InputFileNum;
1361 CHAR8 **InputFileName;
1362 char *OutImageName;
1363 char *ModuleType;
1364 CHAR8 *TimeStamp;
1365 UINT32 OutImageType;
1366 FILE *fpIn;
1367 FILE *fpOut;
1368 FILE *fpInOut;
1369 UINT32 Data;
1370 UINT32 *DataPointer;
1371 UINT32 *OldDataPointer;
1372 UINT32 CheckSum;
1373 UINT32 Index;
1374 UINT32 Index1;
1375 UINT32 Index2;
1376 UINT64 Temp64;
1377 UINT32 MciAlignment;
1378 UINT8 MciPadValue;
1379 UINT32 AllignedRelocSize;
1380 UINT8 *FileBuffer;
1381 UINT32 FileLength;
1382 UINT8 *OutputFileBuffer;
1383 UINT32 OutputFileLength;
1384 RUNTIME_FUNCTION *RuntimeFunction;
1385 UNWIND_INFO *UnwindInfo;
1386 STATUS Status;
1387 BOOLEAN ReplaceFlag;
1388 BOOLEAN KeepExceptionTableFlag;
1389 BOOLEAN KeepZeroPendingFlag;
1390 UINT64 LogLevel;
1391 EFI_TE_IMAGE_HEADER TEImageHeader;
1392 EFI_TE_IMAGE_HEADER *TeHdr;
1393 EFI_IMAGE_SECTION_HEADER *SectionHeader;
1394 EFI_IMAGE_DOS_HEADER *DosHdr;
1395 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
1396 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
1397 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
1398 EFI_IMAGE_DOS_HEADER BackupDosHdr;
1399 MICROCODE_IMAGE_HEADER *MciHeader;
1400
1401 SetUtilityName (UTILITY_NAME);
1402
1403 //
1404 // Assign to fix compile warning
1405 //
1406 InputFileNum = 0;
1407 InputFileName = NULL;
1408 mInImageName = NULL;
1409 OutImageName = NULL;
1410 ModuleType = NULL;
1411 OutImageType = FW_DUMMY_IMAGE;
1412 Type = 0;
1413 Status = STATUS_SUCCESS;
1414 FileBuffer = NULL;
1415 fpIn = NULL;
1416 fpOut = NULL;
1417 fpInOut = NULL;
1418 TimeStamp = NULL;
1419 MciAlignment = DEFAULT_MC_ALIGNMENT;
1420 MciPadValue = DEFAULT_MC_PAD_BYTE_VALUE;
1421 FileLength = 0;
1422 MciHeader = NULL;
1423 CheckSum = 0;
1424 ReplaceFlag = FALSE;
1425 LogLevel = 0;
1426 OutputFileBuffer = NULL;
1427 OutputFileLength = 0;
1428 Optional32 = NULL;
1429 Optional64 = NULL;
1430 KeepExceptionTableFlag = FALSE;
1431 KeepZeroPendingFlag = FALSE;
1432
1433 if (argc == 1) {
1434 Error (NULL, 0, 1001, "Missing options", "No input options.");
1435 Usage ();
1436 return STATUS_ERROR;
1437 }
1438
1439 argc --;
1440 argv ++;
1441
1442 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
1443 Version ();
1444 Usage ();
1445 return STATUS_SUCCESS;
1446 }
1447
1448 if (stricmp (argv[0], "--version") == 0) {
1449 Version ();
1450 return STATUS_SUCCESS;
1451 }
1452
1453 while (argc > 0) {
1454 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
1455 if (argv[1] == NULL || argv[1][0] == '-') {
1456 Error (NULL, 0, 1003, "Invalid option value", "Output file name is missing for -o option");
1457 goto Finish;
1458 }
1459 OutImageName = argv[1];
1460 argc -= 2;
1461 argv += 2;
1462 continue;
1463 }
1464
1465 if ((stricmp (argv[0], "-e") == 0) || (stricmp (argv[0], "--efiImage") == 0)) {
1466 if (argv[1] == NULL || argv[1][0] == '-') {
1467 Error (NULL, 0, 1003, "Invalid option value", "Module Type is missing for -o option");
1468 goto Finish;
1469 }
1470 ModuleType = argv[1];
1471 if (OutImageType != FW_TE_IMAGE) {
1472 OutImageType = FW_EFI_IMAGE;
1473 }
1474 argc -= 2;
1475 argv += 2;
1476 continue;
1477 }
1478
1479 if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--stripped") == 0)) {
1480 OutImageType = FW_RELOC_STRIPEED_IMAGE;
1481 argc --;
1482 argv ++;
1483 continue;
1484 }
1485
1486 if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--acpi") == 0)) {
1487 OutImageType = FW_ACPI_IMAGE;
1488 argc --;
1489 argv ++;
1490 continue;
1491 }
1492
1493 if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--terse") == 0)) {
1494 OutImageType = FW_TE_IMAGE;
1495 argc --;
1496 argv ++;
1497 continue;
1498 }
1499
1500 if ((stricmp (argv[0], "-u") == 0) || (stricmp (argv[0], "--dump") == 0)) {
1501 OutImageType = DUMP_TE_HEADER;
1502 argc --;
1503 argv ++;
1504 continue;
1505 }
1506
1507 if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--exe2bin") == 0)) {
1508 OutImageType = FW_BIN_IMAGE;
1509 argc --;
1510 argv ++;
1511 continue;
1512 }
1513
1514 if ((stricmp (argv[0], "-z") == 0) || (stricmp (argv[0], "--zero") == 0)) {
1515 OutImageType = FW_ZERO_DEBUG_IMAGE;
1516 argc --;
1517 argv ++;
1518 continue;
1519 }
1520
1521 if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--stamp") == 0)) {
1522 OutImageType = FW_SET_STAMP_IMAGE;
1523 if (argv[1] == NULL || argv[1][0] == '-') {
1524 Error (NULL, 0, 1003, "Invalid option value", "time stamp is missing for -s option");
1525 goto Finish;
1526 }
1527 TimeStamp = argv[1];
1528 argc -= 2;
1529 argv += 2;
1530 continue;
1531 }
1532
1533 if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--replace") == 0)) {
1534 ReplaceFlag = TRUE;
1535 argc --;
1536 argv ++;
1537 continue;
1538 }
1539
1540 if (stricmp (argv[0], "--keepexceptiontable") == 0) {
1541 KeepExceptionTableFlag = TRUE;
1542 argc --;
1543 argv ++;
1544 continue;
1545 }
1546
1547 if (stricmp (argv[0], "--keepzeropending") == 0) {
1548 KeepZeroPendingFlag = TRUE;
1549 argc --;
1550 argv ++;
1551 continue;
1552 }
1553
1554 if ((stricmp (argv[0], "-m") == 0) || (stricmp (argv[0], "--mcifile") == 0)) {
1555 OutImageType = FW_MCI_IMAGE;
1556 argc --;
1557 argv ++;
1558 continue;
1559 }
1560
1561 if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--join") == 0)) {
1562 OutImageType = FW_MERGE_IMAGE;
1563 argc --;
1564 argv ++;
1565 continue;
1566 }
1567
1568 if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) {
1569 if (AsciiStringToUint64 (argv[1], FALSE, &Temp64) != EFI_SUCCESS) {
1570 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1571 goto Finish;
1572 }
1573 MciAlignment = (UINT32) Temp64;
1574 argc -= 2;
1575 argv += 2;
1576 continue;
1577 }
1578
1579 if ((stricmp (argv[0], "-p") == 0) || (stricmp (argv[0], "--pad") == 0)) {
1580 if (AsciiStringToUint64 (argv[1], FALSE, &Temp64) != EFI_SUCCESS) {
1581 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1582 goto Finish;
1583 }
1584 MciPadValue = (UINT8) Temp64;
1585 argc -= 2;
1586 argv += 2;
1587 continue;
1588 }
1589
1590 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
1591 SetPrintLevel (VERBOSE_LOG_LEVEL);
1592 VerboseMsg ("Verbose output Mode Set!");
1593 argc --;
1594 argv ++;
1595 continue;
1596 }
1597
1598 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
1599 SetPrintLevel (KEY_LOG_LEVEL);
1600 KeyMsg ("Quiet output Mode Set!");
1601 argc --;
1602 argv ++;
1603 continue;
1604 }
1605
1606 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
1607 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
1608 if (EFI_ERROR (Status)) {
1609 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1610 goto Finish;
1611 }
1612 if (LogLevel > 9) {
1613 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", LogLevel);
1614 goto Finish;
1615 }
1616 SetPrintLevel (LogLevel);
1617 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
1618 argc -= 2;
1619 argv += 2;
1620 continue;
1621 }
1622
1623 if (argv[0][0] == '-') {
1624 Error (NULL, 0, 1000, "Unknown option", argv[0]);
1625 goto Finish;
1626 }
1627 //
1628 // Get Input file name
1629 //
1630 if ((InputFileNum == 0) && (InputFileName == NULL)) {
1631 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
1632 if (InputFileName == NULL) {
1633 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1634 return EFI_OUT_OF_RESOURCES;
1635 }
1636
1637 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
1638 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
1639 //
1640 // InputFileName buffer too small, need to realloc
1641 //
1642 InputFileName = (CHAR8 **) realloc (
1643 InputFileName,
1644 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
1645 );
1646
1647 if (InputFileName == NULL) {
1648 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1649 return EFI_OUT_OF_RESOURCES;
1650 }
1651
1652 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
1653 }
1654
1655 InputFileName [InputFileNum ++] = argv[0];
1656 argc --;
1657 argv ++;
1658 }
1659
1660 VerboseMsg ("%s tool start.", UTILITY_NAME);
1661
1662 if (OutImageType == FW_DUMMY_IMAGE) {
1663 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!");
1664 if (ReplaceFlag) {
1665 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.");
1666 }
1667 goto Finish;
1668 }
1669
1670 //
1671 // check input files
1672 //
1673 if (InputFileNum == 0) {
1674 Error (NULL, 0, 1001, "Missing option", "Input files");
1675 goto Finish;
1676 }
1677
1678 //
1679 // Combine MciBinary files to one file
1680 //
1681 if ((OutImageType == FW_MERGE_IMAGE) && ReplaceFlag) {
1682 Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with -j merge files option.");
1683 goto Finish;
1684 }
1685
1686 //
1687 // Input image file
1688 //
1689 mInImageName = InputFileName [InputFileNum - 1];
1690 VerboseMsg ("the input file name is %s", mInImageName);
1691
1692 //
1693 // Action will be taken for the input file.
1694 //
1695 switch (OutImageType) {
1696 case FW_EFI_IMAGE:
1697 VerboseMsg ("Create efi image on module type %s based on the input PE image.", ModuleType);
1698 break;
1699 case FW_TE_IMAGE:
1700 VerboseMsg ("Create Te Image based on the input PE image.");
1701 break;
1702 case FW_ACPI_IMAGE:
1703 VerboseMsg ("Get acpi table data from the input PE image.");
1704 break;
1705 case FW_RELOC_STRIPEED_IMAGE:
1706 VerboseMsg ("Remove relocation section from Pe or Te image.");
1707 break;
1708 case FW_BIN_IMAGE:
1709 VerboseMsg ("Convert the input EXE to the output BIN file.");
1710 break;
1711 case FW_ZERO_DEBUG_IMAGE:
1712 VerboseMsg ("Zero the Debug Data Fields and Time Stamp in input PE image.");
1713 break;
1714 case FW_SET_STAMP_IMAGE:
1715 VerboseMsg ("Set new time stamp %s in the input PE image.", TimeStamp);
1716 break;
1717 case DUMP_TE_HEADER:
1718 VerboseMsg ("Dump the TE header information of the input TE image.");
1719 break;
1720 case FW_MCI_IMAGE:
1721 VerboseMsg ("Conver input MicroCode.txt file to MicroCode.bin file.");
1722 break;
1723 case FW_MERGE_IMAGE:
1724 VerboseMsg ("Combine the input multi microcode bin files to one bin file.");
1725 break;
1726 default:
1727 break;
1728 }
1729
1730 if (ReplaceFlag) {
1731 VerboseMsg ("Overwrite the input file with the output content.");
1732 }
1733
1734 //
1735 // Open output file and Write image into the output file.
1736 //
1737 if (OutImageName != NULL) {
1738 fpOut = fopen (OutImageName, "rb");
1739 if (fpOut != NULL) {
1740 OutputFileLength = _filelength (fileno (fpOut));
1741 OutputFileBuffer = malloc (OutputFileLength);
1742 if (OutputFileBuffer == NULL) {
1743 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1744 fclose (fpOut);
1745 fpOut = NULL;
1746 goto Finish;
1747 }
1748 fread (OutputFileBuffer, 1, OutputFileLength, fpOut);
1749 fclose (fpOut);
1750 }
1751 fpOut = fopen (OutImageName, "wb");
1752 if (!fpOut) {
1753 Error (NULL, 0, 0001, "Error opening output file", OutImageName);
1754 goto Finish;
1755 }
1756 VerboseMsg ("Output file name is %s", OutImageName);
1757 } else if (!ReplaceFlag) {
1758 if (OutImageType == DUMP_TE_HEADER) {
1759 fpOut = stdout;
1760 } else {
1761 Error (NULL, 0, 1001, "Missing option", "output file");
1762 goto Finish;
1763 }
1764 }
1765
1766 //
1767 // Combine MciBinary files to one file
1768 //
1769 if (OutImageType == FW_MERGE_IMAGE) {
1770 for (Index = 0; Index < InputFileNum; Index ++) {
1771 fpIn = fopen (InputFileName [Index], "rb");
1772 if (!fpIn) {
1773 Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]);
1774 goto Finish;
1775 }
1776
1777 FileLength = _filelength (fileno (fpIn));
1778 FileBuffer = malloc (FileLength);
1779 if (FileBuffer == NULL) {
1780 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1781 fclose (fpIn);
1782 goto Finish;
1783 }
1784
1785 fread (FileBuffer, 1, FileLength, fpIn);
1786 fclose (fpIn);
1787 //
1788 // write input file to out file
1789 //
1790 fwrite (FileBuffer, 1, FileLength, fpOut);
1791 //
1792 // write pad value to out file.
1793 //
1794 while (FileLength ++ % MciAlignment != 0) {
1795 fwrite (&MciPadValue, 1, 1, fpOut);
1796 }
1797 //
1798 // free allocated memory space
1799 //
1800 free (FileBuffer);
1801 FileBuffer = NULL;
1802 }
1803 //
1804 // Done successfully
1805 //
1806 goto Finish;
1807 }
1808
1809 //
1810 // Convert MicroCode.txt file to MicroCode.bin file
1811 //
1812 if (OutImageType == FW_MCI_IMAGE) {
1813 fpIn = fopen (mInImageName, "r");
1814 if (!fpIn) {
1815 Error (NULL, 0, 0001, "Error opening file", mInImageName);
1816 goto Finish;
1817 }
1818
1819 //
1820 // The first pass is to determine
1821 // how much data is in the file so we can allocate a working buffer.
1822 //
1823 FileLength = 0;
1824 do {
1825 Status = MicrocodeReadData (fpIn, &Data);
1826 if (Status == STATUS_SUCCESS) {
1827 FileLength += sizeof (Data);
1828 }
1829 if (Status == STATUS_IGNORE) {
1830 Status = STATUS_SUCCESS;
1831 }
1832 } while (Status == STATUS_SUCCESS);
1833 //
1834 // Error if no data.
1835 //
1836 if (FileLength == 0) {
1837 Error (NULL, 0, 3000, "Invalid", "no parseable data found in file %s", mInImageName);
1838 goto Finish;
1839 }
1840 if (FileLength < sizeof (MICROCODE_IMAGE_HEADER)) {
1841 Error (NULL, 0, 3000, "Invalid", "amount of parseable data in %s is insufficient to contain a microcode header", mInImageName);
1842 goto Finish;
1843 }
1844
1845 //
1846 // Allocate a buffer for the data
1847 //
1848 FileBuffer = malloc (FileLength);
1849 if (FileBuffer == NULL) {
1850 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1851 goto Finish;
1852 }
1853 //
1854 // Re-read the file, storing the data into our buffer
1855 //
1856 fseek (fpIn, 0, SEEK_SET);
1857 DataPointer = (UINT32 *) FileBuffer;
1858 OldDataPointer = DataPointer;
1859 do {
1860 OldDataPointer = DataPointer;
1861 Status = MicrocodeReadData (fpIn, DataPointer++);
1862 if (Status == STATUS_IGNORE) {
1863 DataPointer = OldDataPointer;
1864 Status = STATUS_SUCCESS;
1865 }
1866 } while (Status == STATUS_SUCCESS);
1867 //
1868 // close input file after read data
1869 //
1870 fclose (fpIn);
1871
1872 //
1873 // Can't do much checking on the header because, per the spec, the
1874 // DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K,
1875 // and the TotalSize field is invalid (actually missing). Thus we can't
1876 // even verify the Reserved fields are 0.
1877 //
1878 MciHeader = (MICROCODE_IMAGE_HEADER *) FileBuffer;
1879 if (MciHeader->DataSize == 0) {
1880 Index = 2048;
1881 } else {
1882 Index = MciHeader->TotalSize;
1883 }
1884
1885 if (Index != FileLength) {
1886 Error (NULL, 0, 3000, "Invalid", "file length of %s (0x%x) does not equal expected TotalSize: 0x%04X.", mInImageName, FileLength, Index);
1887 goto Finish;
1888 }
1889
1890 //
1891 // Checksum the contents
1892 //
1893 DataPointer = (UINT32 *) FileBuffer;
1894 CheckSum = 0;
1895 Index = 0;
1896 while (Index < FileLength) {
1897 CheckSum += *DataPointer;
1898 DataPointer ++;
1899 Index += sizeof (*DataPointer);
1900 }
1901 if (CheckSum != 0) {
1902 Error (NULL, 0, 3000, "Invalid", "checksum (0x%x) failed on file %s.", CheckSum, mInImageName);
1903 goto Finish;
1904 }
1905 //
1906 // Open the output file and write the buffer contents
1907 //
1908 if (fpOut != NULL) {
1909 if (fwrite (FileBuffer, FileLength, 1, fpOut) != 1) {
1910 Error (NULL, 0, 0002, "Error writing file", OutImageName);
1911 goto Finish;
1912 }
1913 }
1914
1915 if (ReplaceFlag) {
1916 fpInOut = fopen (mInImageName, "wb");
1917 if (fpInOut != NULL) {
1918 Error (NULL, 0, 0001, "Error opening file", mInImageName);
1919 goto Finish;
1920 }
1921 if (fwrite (FileBuffer, FileLength, 1, fpInOut) != 1) {
1922 Error (NULL, 0, 0002, "Error writing file", mInImageName);
1923 goto Finish;
1924 }
1925 }
1926 VerboseMsg ("the size of output file is %d bytes", FileLength);
1927 //
1928 // Convert Mci.TXT to Mci.bin file successfully
1929 //
1930 goto Finish;
1931 }
1932
1933 //
1934 // Open input file and read file data into file buffer.
1935 //
1936 fpIn = fopen (mInImageName, "rb");
1937 if (!fpIn) {
1938 Error (NULL, 0, 0001, "Error opening file", mInImageName);
1939 goto Finish;
1940 }
1941
1942 FileLength = _filelength (fileno (fpIn));
1943 FileBuffer = malloc (FileLength);
1944 if (FileBuffer == NULL) {
1945 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1946 fclose (fpIn);
1947 goto Finish;
1948 }
1949
1950 fread (FileBuffer, 1, FileLength, fpIn);
1951 fclose (fpIn);
1952
1953 DebugMsg (NULL, 0, 9, "input file info", "the input file size is %d bytes", FileLength);
1954
1955 //
1956 // Replace file
1957 //
1958 if (ReplaceFlag) {
1959 fpInOut = fopen (mInImageName, "wb");
1960 if (!fpInOut) {
1961 Error (NULL, 0, 0001, "Error opening file", mInImageName);
1962 goto Finish;
1963 }
1964 }
1965 //
1966 // Dump TeImage Header into output file.
1967 //
1968 if (OutImageType == DUMP_TE_HEADER) {
1969 memcpy (&TEImageHeader, FileBuffer, sizeof (TEImageHeader));
1970 if (TEImageHeader.Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
1971 Error (NULL, 0, 3000, "Invalid", "TE header signature of file %s is not correct.", mInImageName);
1972 goto Finish;
1973 }
1974 if (fpInOut != NULL) {
1975 fprintf (fpInOut, "Dump of file %s\n\n", mInImageName);
1976 fprintf (fpInOut, "TE IMAGE HEADER VALUES\n");
1977 fprintf (fpInOut, "%17X machine\n", TEImageHeader.Machine);
1978 fprintf (fpInOut, "%17X number of sections\n", TEImageHeader.NumberOfSections);
1979 fprintf (fpInOut, "%17X subsystems\n", TEImageHeader.Subsystem);
1980 fprintf (fpInOut, "%17X stripped size\n", TEImageHeader.StrippedSize);
1981 fprintf (fpInOut, "%17X entry point\n", TEImageHeader.AddressOfEntryPoint);
1982 fprintf (fpInOut, "%17X base of code\n", TEImageHeader.BaseOfCode);
1983 fprintf (fpInOut, "%17lX image base\n", (long unsigned int)TEImageHeader.ImageBase);
1984 fprintf (fpInOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", TEImageHeader.DataDirectory[0].VirtualAddress, TEImageHeader.DataDirectory[0].Size);
1985 fprintf (fpInOut, "%17X [%8X] RVA [size] of Debug Directory\n", TEImageHeader.DataDirectory[1].VirtualAddress, TEImageHeader.DataDirectory[1].Size);
1986 }
1987
1988 if (fpOut != NULL) {
1989 fprintf (fpOut, "Dump of file %s\n\n", mInImageName);
1990 fprintf (fpOut, "TE IMAGE HEADER VALUES\n");
1991 fprintf (fpOut, "%17X machine\n", TEImageHeader.Machine);
1992 fprintf (fpOut, "%17X number of sections\n", TEImageHeader.NumberOfSections);
1993 fprintf (fpOut, "%17X subsystems\n", TEImageHeader.Subsystem);
1994 fprintf (fpOut, "%17X stripped size\n", TEImageHeader.StrippedSize);
1995 fprintf (fpOut, "%17X entry point\n", TEImageHeader.AddressOfEntryPoint);
1996 fprintf (fpOut, "%17X base of code\n", TEImageHeader.BaseOfCode);
1997 fprintf (fpOut, "%17lX image base\n", (long unsigned int)TEImageHeader.ImageBase);
1998 fprintf (fpOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", TEImageHeader.DataDirectory[0].VirtualAddress, TEImageHeader.DataDirectory[0].Size);
1999 fprintf (fpOut, "%17X [%8X] RVA [size] of Debug Directory\n", TEImageHeader.DataDirectory[1].VirtualAddress, TEImageHeader.DataDirectory[1].Size);
2000 }
2001 goto Finish;
2002 }
2003
2004 //
2005 // Following code to convert dll to efi image or te image.
2006 // Get new image type
2007 //
2008 if ((OutImageType == FW_EFI_IMAGE) || (OutImageType == FW_TE_IMAGE)) {
2009 if (ModuleType == NULL) {
2010 if (OutImageType == FW_EFI_IMAGE) {
2011 Error (NULL, 0, 1001, "Missing option", "EFI_FILETYPE");
2012 goto Finish;
2013 } else if (OutImageType == FW_TE_IMAGE) {
2014 //
2015 // Default TE Image Type is Boot service driver
2016 //
2017 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
2018 VerboseMsg ("Efi Image subsystem type is efi boot service driver.");
2019 }
2020 } else {
2021 if (stricmp (ModuleType, "BASE") == 0 ||
2022 stricmp (ModuleType, "SEC") == 0 ||
2023 stricmp (ModuleType, "SECURITY_CORE") == 0 ||
2024 stricmp (ModuleType, "PEI_CORE") == 0 ||
2025 stricmp (ModuleType, "PEIM") == 0 ||
2026 stricmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0 ||
2027 stricmp (ModuleType, "PIC_PEIM") == 0 ||
2028 stricmp (ModuleType, "RELOCATABLE_PEIM") == 0 ||
2029 stricmp (ModuleType, "DXE_CORE") == 0 ||
2030 stricmp (ModuleType, "BS_DRIVER") == 0 ||
2031 stricmp (ModuleType, "DXE_DRIVER") == 0 ||
2032 stricmp (ModuleType, "DXE_SMM_DRIVER") == 0 ||
2033 stricmp (ModuleType, "UEFI_DRIVER") == 0 ||
2034 stricmp (ModuleType, "SMM_DRIVER") == 0 ||
2035 stricmp (ModuleType, "SMM_CORE") == 0) {
2036 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
2037 VerboseMsg ("Efi Image subsystem type is efi boot service driver.");
2038
2039 } else if (stricmp (ModuleType, "UEFI_APPLICATION") == 0 ||
2040 stricmp (ModuleType, "APPLICATION") == 0) {
2041 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
2042 VerboseMsg ("Efi Image subsystem type is efi application.");
2043
2044 } else if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0 ||
2045 stricmp (ModuleType, "RT_DRIVER") == 0) {
2046 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
2047 VerboseMsg ("Efi Image subsystem type is efi runtime driver.");
2048
2049 } else if (stricmp (ModuleType, "DXE_SAL_DRIVER") == 0 ||
2050 stricmp (ModuleType, "SAL_RT_DRIVER") == 0) {
2051 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
2052 VerboseMsg ("Efi Image subsystem type is efi sal runtime driver.");
2053
2054 } else {
2055 Error (NULL, 0, 1003, "Invalid option value", "EFI_FILETYPE = %s", ModuleType);
2056 goto Finish;
2057 }
2058 }
2059 }
2060
2061 //
2062 // Convert EFL image to PeImage
2063 //
2064 if (IsElfHeader(FileBuffer)) {
2065 VerboseMsg ("Convert the input ELF Image to Pe Image");
2066 ConvertElf(&FileBuffer, &FileLength);
2067 }
2068
2069 //
2070 // Remove reloc section from PE or TE image
2071 //
2072 if (OutImageType == FW_RELOC_STRIPEED_IMAGE) {
2073 //
2074 // Check TeImage
2075 //
2076 TeHdr = (EFI_TE_IMAGE_HEADER *) FileBuffer;
2077 if (TeHdr->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
2078 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TeHdr + 1);
2079 for (Index = 0; Index < TeHdr->NumberOfSections; Index ++, SectionHeader ++) {
2080 if (strcmp ((char *)SectionHeader->Name, ".reloc") == 0) {
2081 //
2082 // Check the reloc section is in the end of image.
2083 //
2084 if ((SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData) ==
2085 (FileLength + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER))) {
2086 //
2087 // Remove .reloc section and update TeImage Header
2088 //
2089 FileLength = FileLength - SectionHeader->SizeOfRawData;
2090 SectionHeader->SizeOfRawData = 0;
2091 SectionHeader->Misc.VirtualSize = 0;
2092 TeHdr->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
2093 TeHdr->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
2094 break;
2095 }
2096 }
2097 }
2098 } else {
2099 //
2100 // Check PE Image
2101 //
2102 DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
2103 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
2104 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer);
2105 if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
2106 Error (NULL, 0, 3000, "Invalid", "TE and DOS header signatures were not found in %s image.", mInImageName);
2107 goto Finish;
2108 }
2109 DosHdr = NULL;
2110 } else {
2111 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + DosHdr->e_lfanew);
2112 if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
2113 Error (NULL, 0, 3000, "Invalid", "PE header signature was not found in %s image.", mInImageName);
2114 goto Finish;
2115 }
2116 }
2117 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2118 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
2119 if (strcmp ((char *)SectionHeader->Name, ".reloc") == 0) {
2120 //
2121 // Check the reloc section is in the end of image.
2122 //
2123 if ((SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData) == FileLength) {
2124 //
2125 // Remove .reloc section and update PeImage Header
2126 //
2127 FileLength = FileLength - SectionHeader->SizeOfRawData;
2128
2129 PeHdr->Pe32.FileHeader.Characteristics |= EFI_IMAGE_FILE_RELOCS_STRIPPED;
2130 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2131 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader;
2132 Optional32->SizeOfImage -= SectionHeader->SizeOfRawData;
2133 Optional32->SizeOfInitializedData -= SectionHeader->SizeOfRawData;
2134 if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
2135 Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
2136 Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
2137 }
2138 }
2139 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
2140 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader;
2141 Optional64->SizeOfImage -= SectionHeader->SizeOfRawData;
2142 Optional64->SizeOfInitializedData -= SectionHeader->SizeOfRawData;
2143 if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
2144 Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
2145 Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
2146 }
2147 }
2148 SectionHeader->Misc.VirtualSize = 0;
2149 SectionHeader->SizeOfRawData = 0;
2150 break;
2151 }
2152 }
2153 }
2154 }
2155 //
2156 // Write file
2157 //
2158 goto WriteFile;
2159 }
2160 //
2161 // Read the dos & pe hdrs of the image
2162 //
2163 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
2164 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
2165 // NO DOS header, check for PE/COFF header
2166 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer);
2167 if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
2168 Error (NULL, 0, 3000, "Invalid", "DOS header signature was not found in %s image.", mInImageName);
2169 goto Finish;
2170 }
2171 DosHdr = NULL;
2172 } else {
2173
2174 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + DosHdr->e_lfanew);
2175 if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
2176 Error (NULL, 0, 3000, "Invalid", "PE header signature was not found in %s image.", mInImageName);
2177 goto Finish;
2178 }
2179 }
2180
2181 if (PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) {
2182 // Some tools kick out IMAGE_FILE_MACHINE_ARM (0x1c0) vs IMAGE_FILE_MACHINE_ARMT (0x1c2)
2183 // so patch back to the offical UEFI value.
2184 PeHdr->Pe32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMT;
2185 }
2186
2187 //
2188 // Extract bin data from Pe image.
2189 //
2190 if (OutImageType == FW_BIN_IMAGE) {
2191 if (FileLength < PeHdr->Pe32.OptionalHeader.SizeOfHeaders) {
2192 Error (NULL, 0, 3000, "Invalid", "FileSize of %s is not a legal size.", mInImageName);
2193 goto Finish;
2194 }
2195 //
2196 // Output bin data from exe file
2197 //
2198 if (fpOut != NULL) {
2199 fwrite (FileBuffer + PeHdr->Pe32.OptionalHeader.SizeOfHeaders, 1, FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders, fpOut);
2200 }
2201 if (fpInOut != NULL) {
2202 fwrite (FileBuffer + PeHdr->Pe32.OptionalHeader.SizeOfHeaders, 1, FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders, fpInOut);
2203 }
2204 VerboseMsg ("the size of output file is %d bytes", FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders);
2205 goto Finish;
2206 }
2207
2208 //
2209 // Zero Debug Information of Pe Image
2210 //
2211 if (OutImageType == FW_ZERO_DEBUG_IMAGE) {
2212 Status = ZeroDebugData (FileBuffer, TRUE);
2213 if (EFI_ERROR (Status)) {
2214 Error (NULL, 0, 3000, "Invalid", "Zero DebugData Error status is 0x%lx", (UINTN) Status);
2215 goto Finish;
2216 }
2217
2218 if (fpOut != NULL) {
2219 fwrite (FileBuffer, 1, FileLength, fpOut);
2220 }
2221 if (fpInOut != NULL) {
2222 fwrite (FileBuffer, 1, FileLength, fpInOut);
2223 }
2224 VerboseMsg ("the size of output file is %d bytes", FileLength);
2225 goto Finish;
2226 }
2227
2228 //
2229 // Set Time Stamp of Pe Image
2230 //
2231 if (OutImageType == FW_SET_STAMP_IMAGE) {
2232 Status = SetStamp (FileBuffer, TimeStamp);
2233 if (EFI_ERROR (Status)) {
2234 goto Finish;
2235 }
2236
2237 if (fpOut != NULL) {
2238 fwrite (FileBuffer, 1, FileLength, fpOut);
2239 }
2240 if (fpInOut != NULL) {
2241 fwrite (FileBuffer, 1, FileLength, fpInOut);
2242 }
2243 VerboseMsg ("the size of output file is %d bytes", FileLength);
2244 goto Finish;
2245 }
2246
2247 //
2248 // Extract acpi data from pe image.
2249 //
2250 if (OutImageType == FW_ACPI_IMAGE) {
2251 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2252 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
2253 if (strcmp ((char *)SectionHeader->Name, ".data") == 0 || strcmp ((char *)SectionHeader->Name, ".sdata") == 0) {
2254 //
2255 // Check Acpi Table
2256 //
2257 if (SectionHeader->Misc.VirtualSize < SectionHeader->SizeOfRawData) {
2258 FileLength = SectionHeader->Misc.VirtualSize;
2259 } else {
2260 FileLength = SectionHeader->SizeOfRawData;
2261 }
2262
2263 if (CheckAcpiTable (FileBuffer + SectionHeader->PointerToRawData, FileLength) != STATUS_SUCCESS) {
2264 Error (NULL, 0, 3000, "Invalid", "ACPI table check failed in %s.", mInImageName);
2265 goto Finish;
2266 }
2267
2268 //
2269 // Output Apci data to file
2270 //
2271 if (fpOut != NULL) {
2272 fwrite (FileBuffer + SectionHeader->PointerToRawData, 1, FileLength, fpOut);
2273 }
2274 if (fpInOut != NULL) {
2275 fwrite (FileBuffer + SectionHeader->PointerToRawData, 1, FileLength, fpInOut);
2276 }
2277 VerboseMsg ("the size of output file is %d bytes", FileLength);
2278 goto Finish;
2279 }
2280 }
2281 Error (NULL, 0, 3000, "Invalid", "failed to get ACPI table from %s.", mInImageName);
2282 goto Finish;
2283 }
2284 //
2285 // Zero all unused fields of the DOS header
2286 //
2287 if (DosHdr != NULL) {
2288 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
2289 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
2290 DosHdr->e_magic = BackupDosHdr.e_magic;
2291 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
2292
2293 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (UINT32 ) DosHdr->e_lfanew; Index++) {
2294 FileBuffer[Index] = DosHdr->e_cp;
2295 }
2296 }
2297
2298 //
2299 // Initialize TeImage Header
2300 //
2301 memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER));
2302 TEImageHeader.Signature = EFI_TE_IMAGE_HEADER_SIGNATURE;
2303 TEImageHeader.Machine = PeHdr->Pe32.FileHeader.Machine;
2304 TEImageHeader.NumberOfSections = (UINT8) PeHdr->Pe32.FileHeader.NumberOfSections;
2305 TEImageHeader.StrippedSize = (UINT16) ((UINTN) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader) - (UINTN) FileBuffer);
2306 TEImageHeader.Subsystem = (UINT8) Type;
2307
2308 //
2309 // Patch the PE header
2310 //
2311 PeHdr->Pe32.OptionalHeader.Subsystem = (UINT16) Type;
2312
2313 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2314 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader;
2315 Optional32->MajorLinkerVersion = 0;
2316 Optional32->MinorLinkerVersion = 0;
2317 Optional32->MajorOperatingSystemVersion = 0;
2318 Optional32->MinorOperatingSystemVersion = 0;
2319 Optional32->MajorImageVersion = 0;
2320 Optional32->MinorImageVersion = 0;
2321 Optional32->MajorSubsystemVersion = 0;
2322 Optional32->MinorSubsystemVersion = 0;
2323 Optional32->Win32VersionValue = 0;
2324 Optional32->CheckSum = 0;
2325 Optional32->SizeOfStackReserve = 0;
2326 Optional32->SizeOfStackCommit = 0;
2327 Optional32->SizeOfHeapReserve = 0;
2328 Optional32->SizeOfHeapCommit = 0;
2329
2330 TEImageHeader.AddressOfEntryPoint = Optional32->AddressOfEntryPoint;
2331 TEImageHeader.BaseOfCode = Optional32->BaseOfCode;
2332 TEImageHeader.ImageBase = (UINT64) (Optional32->ImageBase);
2333
2334 if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
2335 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
2336 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
2337 }
2338
2339 if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
2340 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
2341 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
2342 }
2343
2344 //
2345 // Zero .pdata section data.
2346 //
2347 if (!KeepExceptionTableFlag && Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION &&
2348 Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0 &&
2349 Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0) {
2350 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2351 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
2352 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) {
2353 //
2354 // Zero .pdata Section data
2355 //
2356 memset (FileBuffer + SectionHeader->PointerToRawData, 0, SectionHeader->SizeOfRawData);
2357 //
2358 // Zero .pdata Section header name
2359 //
2360 memset (SectionHeader->Name, 0, sizeof (SectionHeader->Name));
2361 //
2362 // Zero Execption Table
2363 //
2364 Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
2365 Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
2366 DebugMsg (NULL, 0, 9, "Zero the .pdata section for PE image", NULL);
2367 break;
2368 }
2369 }
2370 }
2371
2372 //
2373 // Strip zero padding at the end of the .reloc section
2374 //
2375 if (!KeepZeroPendingFlag && Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
2376 if (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) {
2377 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2378 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
2379 //
2380 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
2381 //
2382 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) {
2383 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
2384 AllignedRelocSize = (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));
2385 //
2386 // Check to see if there is zero padding at the end of the base relocations
2387 //
2388 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
2389 //
2390 // Check to see if the base relocations are at the end of the file
2391 //
2392 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
2393 //
2394 // All the required conditions are met to strip the zero padding of the end of the base relocations section
2395 //
2396 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
2397 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
2398 SectionHeader->SizeOfRawData = AllignedRelocSize;
2399 FileLength = Optional32->SizeOfImage;
2400 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);
2401 }
2402 }
2403 }
2404 }
2405 }
2406 }
2407 } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
2408 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader;
2409 Optional64->MajorLinkerVersion = 0;
2410 Optional64->MinorLinkerVersion = 0;
2411 Optional64->MajorOperatingSystemVersion = 0;
2412 Optional64->MinorOperatingSystemVersion = 0;
2413 Optional64->MajorImageVersion = 0;
2414 Optional64->MinorImageVersion = 0;
2415 Optional64->MajorSubsystemVersion = 0;
2416 Optional64->MinorSubsystemVersion = 0;
2417 Optional64->Win32VersionValue = 0;
2418 Optional64->CheckSum = 0;
2419 Optional64->SizeOfStackReserve = 0;
2420 Optional64->SizeOfStackCommit = 0;
2421 Optional64->SizeOfHeapReserve = 0;
2422 Optional64->SizeOfHeapCommit = 0;
2423
2424 TEImageHeader.AddressOfEntryPoint = Optional64->AddressOfEntryPoint;
2425 TEImageHeader.BaseOfCode = Optional64->BaseOfCode;
2426 TEImageHeader.ImageBase = (UINT64) (Optional64->ImageBase);
2427
2428 if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
2429 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
2430 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
2431 }
2432
2433 if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
2434 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
2435 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
2436 }
2437
2438 //
2439 // Zero the .pdata section for X64 machine and don't check the Debug Directory is empty
2440 // For Itaninum and X64 Image, remove .pdata section.
2441 //
2442 if ((!KeepExceptionTableFlag && PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64) || PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) {
2443 if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION &&
2444 Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0 &&
2445 Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0) {
2446 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2447 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
2448 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) {
2449 //
2450 // Zero .pdata Section header name
2451 //
2452 memset (SectionHeader->Name, 0, sizeof (SectionHeader->Name));
2453
2454 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);
2455 for (Index1 = 0; Index1 < Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {
2456 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2457 for (Index2 = 0; Index2 < PeHdr->Pe32.FileHeader.NumberOfSections; Index2++, SectionHeader++) {
2458 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {
2459 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));
2460 if (UnwindInfo->Version == 1) {
2461 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));
2462 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));
2463 }
2464 }
2465 }
2466 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));
2467 }
2468 //
2469 // Zero Execption Table
2470 //
2471 Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
2472 Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
2473 DebugMsg (NULL, 0, 9, "Zero the .pdata section if the machine type is X64 for PE32+ image", NULL);
2474 break;
2475 }
2476 }
2477 }
2478 }
2479
2480 //
2481 // Strip zero padding at the end of the .reloc section
2482 //
2483 if (!KeepZeroPendingFlag && Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
2484 if (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) {
2485 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2486 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
2487 //
2488 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
2489 //
2490 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) {
2491 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
2492 AllignedRelocSize = (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));
2493 //
2494 // Check to see if there is zero padding at the end of the base relocations
2495 //
2496 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
2497 //
2498 // Check to see if the base relocations are at the end of the file
2499 //
2500 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
2501 //
2502 // All the required conditions are met to strip the zero padding of the end of the base relocations section
2503 //
2504 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
2505 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
2506 SectionHeader->SizeOfRawData = AllignedRelocSize;
2507 FileLength = Optional64->SizeOfImage;
2508 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);
2509 }
2510 }
2511 }
2512 }
2513 }
2514 }
2515 } else {
2516 Error (NULL, 0, 3000, "Invalid", "Magic 0x%x of PeImage %s is unknown.", PeHdr->Pe32.OptionalHeader.Magic, mInImageName);
2517 goto Finish;
2518 }
2519
2520 if (((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) == 0) && \
2521 (TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0) && \
2522 (TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0)) {
2523 //
2524 // PeImage can be loaded into memory, but it has no relocation section.
2525 // Fix TeImage Header to set VA of relocation data directory to not zero, the size is still zero.
2526 //
2527 if (Optional32 != NULL) {
2528 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->SizeOfImage - sizeof (EFI_IMAGE_BASE_RELOCATION);
2529 } else if (Optional64 != NULL) {
2530 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->SizeOfImage - sizeof (EFI_IMAGE_BASE_RELOCATION);
2531 }
2532 }
2533
2534 //
2535 // Zero ExceptionTable Xdata
2536 //
2537 if (!KeepExceptionTableFlag) {
2538 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);
2539 ZeroXdataSection(mInImageName, FileBuffer, SectionHeader, PeHdr->Pe32.FileHeader.NumberOfSections);
2540 }
2541
2542 //
2543 // Zero Time/Data field
2544 //
2545 ZeroDebugData (FileBuffer, FALSE);
2546
2547 if (OutImageType == FW_TE_IMAGE) {
2548 if ((PeHdr->Pe32.FileHeader.NumberOfSections &~0xFF) || (Type &~0xFF)) {
2549 //
2550 // Pack the subsystem and NumberOfSections into 1 byte. Make sure they fit both.
2551 //
2552 Error (NULL, 0, 3000, "Invalid", "Image's subsystem or NumberOfSections of PeImage %s cannot be packed into 1 byte.", mInImageName);
2553 goto Finish;
2554 }
2555
2556 if ((PeHdr->Pe32.OptionalHeader.SectionAlignment != PeHdr->Pe32.OptionalHeader.FileAlignment)) {
2557 //
2558 // TeImage has the same section alignment and file alignment.
2559 //
2560 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment of PeImage %s do not match, they must be equal for a TeImage.", mInImageName);
2561 goto Finish;
2562 }
2563
2564 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",
2565 TEImageHeader.Machine, TEImageHeader.NumberOfSections, TEImageHeader.StrippedSize, TEImageHeader.AddressOfEntryPoint, TEImageHeader.BaseOfCode, TEImageHeader.ImageBase);
2566 //
2567 // Update Image to TeImage
2568 //
2569 if (fpOut != NULL) {
2570 fwrite (&TEImageHeader, 1, sizeof (EFI_TE_IMAGE_HEADER), fpOut);
2571 fwrite (FileBuffer + TEImageHeader.StrippedSize, 1, FileLength - TEImageHeader.StrippedSize, fpOut);
2572 }
2573 if (fpInOut != NULL) {
2574 fwrite (&TEImageHeader, 1, sizeof (EFI_TE_IMAGE_HEADER), fpInOut);
2575 fwrite (FileBuffer + TEImageHeader.StrippedSize, 1, FileLength - TEImageHeader.StrippedSize, fpInOut);
2576 }
2577 VerboseMsg ("the size of output file is %d bytes", FileLength - TEImageHeader.StrippedSize);
2578 goto Finish;
2579 }
2580 WriteFile:
2581 //
2582 // Update Image to EfiImage
2583 //
2584 if (fpOut != NULL) {
2585 fwrite (FileBuffer, 1, FileLength, fpOut);
2586 }
2587 if (fpInOut != NULL) {
2588 fwrite (FileBuffer, 1, FileLength, fpInOut);
2589 }
2590 VerboseMsg ("the size of output file is %d bytes", FileLength);
2591
2592 Finish:
2593 if (fpInOut != NULL) {
2594 if (GetUtilityStatus () != STATUS_SUCCESS) {
2595 //
2596 // when file updates failed, original file is still recoveried.
2597 //
2598 fwrite (FileBuffer, 1, FileLength, fpInOut);
2599 }
2600 //
2601 // Write converted data into fpInOut file and close input file.
2602 //
2603 fclose (fpInOut);
2604 }
2605
2606 if (FileBuffer != NULL) {
2607 free (FileBuffer);
2608 }
2609
2610 if (InputFileName != NULL) {
2611 free (InputFileName);
2612 }
2613
2614 if (fpOut != NULL) {
2615 //
2616 // Write converted data into fpOut file and close output file.
2617 //
2618 fclose (fpOut);
2619 if (GetUtilityStatus () != STATUS_SUCCESS) {
2620 if (OutputFileBuffer == NULL) {
2621 remove (OutImageName);
2622 } else {
2623 fpOut = fopen (OutImageName, "wb");
2624 fwrite (OutputFileBuffer, 1, OutputFileLength, fpOut);
2625 fclose (fpOut);
2626 free (OutputFileBuffer);
2627 }
2628 }
2629 }
2630
2631 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
2632
2633 return GetUtilityStatus ();
2634 }
2635
2636 STATIC
2637 EFI_STATUS
2638 ZeroDebugData (
2639 IN OUT UINT8 *FileBuffer,
2640 BOOLEAN ZeroDebugFlag
2641 )
2642 /*++
2643
2644 Routine Description:
2645
2646 Zero debug information in PeImage.
2647
2648 Arguments:
2649
2650 FileBuffer - Pointer to PeImage.
2651 ZeroDebugFlag - TRUE to zero Debug information, FALSE to only zero time/stamp
2652
2653 Returns:
2654
2655 EFI_ABORTED - PeImage is invalid.
2656 EFI_SUCCESS - Zero debug data successfully.
2657
2658 --*/
2659 {
2660 UINT32 Index;
2661 UINT32 DebugDirectoryEntryRva;
2662 UINT32 DebugDirectoryEntryFileOffset;
2663 UINT32 ExportDirectoryEntryRva;
2664 UINT32 ExportDirectoryEntryFileOffset;
2665 UINT32 ResourceDirectoryEntryRva;
2666 UINT32 ResourceDirectoryEntryFileOffset;
2667 EFI_IMAGE_DOS_HEADER *DosHdr;
2668 EFI_IMAGE_FILE_HEADER *FileHdr;
2669 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr;
2670 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr;
2671 EFI_IMAGE_SECTION_HEADER *SectionHeader;
2672 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
2673 UINT32 *NewTimeStamp;
2674
2675 //
2676 // Init variable.
2677 //
2678 DebugDirectoryEntryRva = 0;
2679 ExportDirectoryEntryRva = 0;
2680 ResourceDirectoryEntryRva = 0;
2681 DebugDirectoryEntryFileOffset = 0;
2682 ExportDirectoryEntryFileOffset = 0;
2683 ResourceDirectoryEntryFileOffset = 0;
2684 DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
2685 FileHdr = (EFI_IMAGE_FILE_HEADER *) (FileBuffer + DosHdr->e_lfanew + sizeof (UINT32));
2686
2687
2688 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
2689 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
2690 // NO DOS header, must start with PE/COFF header
2691 FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32));
2692 } else {
2693 FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32));
2694 }
2695
2696 //
2697 // Get Debug, Export and Resource EntryTable RVA address.
2698 // Resource Directory entry need to review.
2699 //
2700 if (FileHdr->Machine == EFI_IMAGE_MACHINE_IA32) {
2701 Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
2702 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader);
2703 if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \
2704 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) {
2705 ExportDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
2706 }
2707 if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \
2708 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) {
2709 ResourceDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
2710 }
2711 if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \
2712 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) {
2713 DebugDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
2714 if (ZeroDebugFlag) {
2715 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0;
2716 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0;
2717 }
2718 }
2719 } else {
2720 Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
2721 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader);
2722 if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \
2723 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) {
2724 ExportDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
2725 }
2726 if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \
2727 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) {
2728 ResourceDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
2729 }
2730 if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \
2731 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) {
2732 DebugDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
2733 if (ZeroDebugFlag) {
2734 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0;
2735 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0;
2736 }
2737 }
2738 }
2739
2740 //
2741 // Get DirectoryEntryTable file offset.
2742 //
2743 for (Index = 0; Index < FileHdr->NumberOfSections; Index ++, SectionHeader ++) {
2744 if (DebugDirectoryEntryRva >= SectionHeader->VirtualAddress &&
2745 DebugDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) {
2746 DebugDirectoryEntryFileOffset =
2747 DebugDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData;
2748 }
2749 if (ExportDirectoryEntryRva >= SectionHeader->VirtualAddress &&
2750 ExportDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) {
2751 ExportDirectoryEntryFileOffset =
2752 ExportDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData;
2753 }
2754 if (ResourceDirectoryEntryRva >= SectionHeader->VirtualAddress &&
2755 ResourceDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) {
2756 ResourceDirectoryEntryFileOffset =
2757 ResourceDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData;
2758 }
2759 }
2760
2761 //
2762 //Zero Debug Data and TimeStamp
2763 //
2764 FileHdr->TimeDateStamp = 0;
2765
2766 if (ExportDirectoryEntryFileOffset != 0) {
2767 NewTimeStamp = (UINT32 *) (FileBuffer + ExportDirectoryEntryFileOffset + sizeof (UINT32));
2768 *NewTimeStamp = 0;
2769 }
2770
2771 if (ResourceDirectoryEntryFileOffset != 0) {
2772 NewTimeStamp = (UINT32 *) (FileBuffer + ResourceDirectoryEntryFileOffset + sizeof (UINT32));
2773 *NewTimeStamp = 0;
2774 }
2775
2776 if (DebugDirectoryEntryFileOffset != 0) {
2777 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (FileBuffer + DebugDirectoryEntryFileOffset);
2778 DebugEntry->TimeDateStamp = 0;
2779 if (ZeroDebugFlag) {
2780 memset (FileBuffer + DebugEntry->FileOffset, 0, DebugEntry->SizeOfData);
2781 memset (DebugEntry, 0, sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
2782 }
2783 }
2784
2785 return EFI_SUCCESS;
2786 }
2787
2788 STATIC
2789 EFI_STATUS
2790 SetStamp (
2791 IN OUT UINT8 *FileBuffer,
2792 IN CHAR8 *TimeStamp
2793 )
2794 /*++
2795
2796 Routine Description:
2797
2798 Set new time stamp into PeImage FileHdr and Directory table:
2799 Debug, Export and Resource.
2800
2801 Arguments:
2802
2803 FileBuffer - Pointer to PeImage.
2804 TimeStamp - Time stamp string.
2805
2806 Returns:
2807
2808 EFI_INVALID_PARAMETER - TimeStamp format is not recognized.
2809 EFI_SUCCESS - Set new time stamp in this image successfully.
2810
2811 --*/
2812 {
2813 struct tm stime;
2814 struct tm *ptime;
2815 time_t newtime;
2816 UINT32 Index;
2817 UINT32 DebugDirectoryEntryRva;
2818 UINT32 DebugDirectoryEntryFileOffset;
2819 UINT32 ExportDirectoryEntryRva;
2820 UINT32 ExportDirectoryEntryFileOffset;
2821 UINT32 ResourceDirectoryEntryRva;
2822 UINT32 ResourceDirectoryEntryFileOffset;
2823 EFI_IMAGE_DOS_HEADER *DosHdr;
2824 EFI_IMAGE_FILE_HEADER *FileHdr;
2825 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr;
2826 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr;
2827 EFI_IMAGE_SECTION_HEADER *SectionHeader;
2828 UINT32 *NewTimeStamp;
2829
2830 //
2831 // Init variable.
2832 //
2833 DebugDirectoryEntryRva = 0;
2834 ExportDirectoryEntryRva = 0;
2835 ResourceDirectoryEntryRva = 0;
2836 //
2837 // Get time and date that will be set.
2838 //
2839 if (TimeStamp == NULL) {
2840 Error (NULL, 0, 3000, "Invalid", "TimeStamp cannot be NULL.");
2841 return EFI_INVALID_PARAMETER;
2842 }
2843 //
2844 // compare the value with "NOW", if yes, current system time is set.
2845 //
2846 if (stricmp (TimeStamp, "NOW") == 0) {
2847 //
2848 // get system current time and date
2849 //
2850 time (&newtime);
2851 } else {
2852 //
2853 // Check Time Format strictly yyyy-mm-dd 00:00:00
2854 //
2855 for (Index = 0; TimeStamp[Index] != '\0' && Index < 20; Index ++) {
2856 if (Index == 4 || Index == 7) {
2857 if (TimeStamp[Index] == '-') {
2858 continue;
2859 }
2860 } else if (Index == 13 || Index == 16) {
2861 if (TimeStamp[Index] == ':') {
2862 continue;
2863 }
2864 } else if (Index == 10 && TimeStamp[Index] == ' ') {
2865 continue;
2866 } else if ((TimeStamp[Index] < '0') || (TimeStamp[Index] > '9')) {
2867 break;
2868 }
2869 }
2870
2871 if (Index < 19 || TimeStamp[19] != '\0') {
2872 Error (NULL, 0, 1003, "Invalid option value", "Incorrect Time \"%s\"\n Correct Format \"yyyy-mm-dd 00:00:00\"", TimeStamp);
2873 return EFI_INVALID_PARAMETER;
2874 }
2875
2876 //
2877 // get the date and time from TimeStamp
2878 //
2879 if (sscanf (TimeStamp, "%d-%d-%d %d:%d:%d",
2880 &stime.tm_year,
2881 &stime.tm_mon,
2882 &stime.tm_mday,
2883 &stime.tm_hour,
2884 &stime.tm_min,
2885 &stime.tm_sec
2886 ) != 6) {
2887 Error (NULL, 0, 1003, "Invalid option value", "Incorrect Tiem \"%s\"\n Correct Format \"yyyy-mm-dd 00:00:00\"", TimeStamp);
2888 return EFI_INVALID_PARAMETER;
2889 }
2890
2891 //
2892 // in struct, Month (0 - 11; Jan = 0). So decrease 1 from it
2893 //
2894 if (stime.tm_mon <= 0 || stime.tm_mday <=0) {
2895 Error (NULL, 0, 3000, "Invalid", "%s Invalid date!", TimeStamp);
2896 return EFI_INVALID_PARAMETER;
2897 }
2898 stime.tm_mon -= 1;
2899
2900 //
2901 // in struct, Year (current year minus 1900)
2902 // and only the dates can be handled from Jan 1, 1970 to Jan 18, 2038
2903 //
2904 //
2905 // convert 0 -> 100 (2000), 1 -> 101 (2001), ..., 38 -> 138 (2038)
2906 //
2907 if (stime.tm_year >= 1970 && stime.tm_year <= 2038) {
2908 //
2909 // convert 1970 -> 70, 2000 -> 100, ...
2910 //
2911 stime.tm_year -= 1900;
2912 } else {
2913 Error (NULL, 0, 3000, "Invalid", "%s Invalid or unsupported datetime!", TimeStamp);
2914 return EFI_INVALID_PARAMETER;
2915 }
2916
2917 //
2918 // convert the date and time to time_t format
2919 //
2920 newtime = mktime (&stime);
2921 if (newtime == (time_t) - 1) {
2922 Error (NULL, 0, 3000, "Invalid", "%s Invalid or unsupported datetime!", TimeStamp);
2923 return EFI_INVALID_PARAMETER;
2924 }
2925 }
2926
2927 ptime = localtime (&newtime);
2928 DebugMsg (NULL, 0, 9, "New Image Time Stamp", "%04d-%02d-%02d %02d:%02d:%02d",
2929 ptime->tm_year + 1900, ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
2930 //
2931 // Set new time and data into PeImage.
2932 //
2933 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
2934 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
2935 // NO DOS header, must start with PE/COFF header
2936 FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32));
2937 } else {
2938 FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32));
2939 }
2940
2941 //
2942 // Get Debug, Export and Resource EntryTable RVA address.
2943 // Resource Directory entry need to review.
2944 //
2945 if (FileHdr->Machine == EFI_IMAGE_MACHINE_IA32) {
2946 Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
2947 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader);
2948 if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \
2949 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) {
2950 ExportDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
2951 }
2952 if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \
2953 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) {
2954 ResourceDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
2955 }
2956 if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \
2957 Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) {
2958 DebugDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
2959 }
2960 } else {
2961 Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
2962 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader);
2963 if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \
2964 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) {
2965 ExportDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
2966 }
2967 if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \
2968 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) {
2969 ResourceDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
2970 }
2971 if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \
2972 Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) {
2973 DebugDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
2974 }
2975 }
2976
2977 //
2978 // Get DirectoryEntryTable file offset.
2979 //
2980 for (Index = 0; Index < FileHdr->NumberOfSections; Index ++, SectionHeader ++) {
2981 if (DebugDirectoryEntryRva >= SectionHeader->VirtualAddress &&
2982 DebugDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) {
2983 DebugDirectoryEntryFileOffset =
2984 DebugDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData;
2985 }
2986 if (ExportDirectoryEntryRva >= SectionHeader->VirtualAddress &&
2987 ExportDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) {
2988 ExportDirectoryEntryFileOffset =
2989 ExportDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData;
2990 }
2991 if (ResourceDirectoryEntryRva >= SectionHeader->VirtualAddress &&
2992 ResourceDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) {
2993 ResourceDirectoryEntryFileOffset =
2994 ResourceDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData;
2995 }
2996 }
2997
2998 //
2999 // Set new stamp
3000 //
3001 FileHdr->TimeDateStamp = (UINT32) newtime;
3002
3003 if (ExportDirectoryEntryRva != 0) {
3004 NewTimeStamp = (UINT32 *) (FileBuffer + ExportDirectoryEntryFileOffset + sizeof (UINT32));
3005 *NewTimeStamp = (UINT32) newtime;
3006 }
3007
3008 if (ResourceDirectoryEntryRva != 0) {
3009 NewTimeStamp = (UINT32 *) (FileBuffer + ResourceDirectoryEntryFileOffset + sizeof (UINT32));
3010 *NewTimeStamp = (UINT32) newtime;
3011 }
3012
3013 if (DebugDirectoryEntryRva != 0) {
3014 NewTimeStamp = (UINT32 *) (FileBuffer + DebugDirectoryEntryFileOffset + sizeof (UINT32));
3015 *NewTimeStamp = (UINT32) newtime;
3016 }
3017
3018 return EFI_SUCCESS;
3019 }
3020
3021 STATIC
3022 STATUS
3023 MicrocodeReadData (
3024 FILE *InFptr,
3025 UINT32 *Data
3026 )
3027 /*++
3028
3029 Routine Description:
3030 Read a 32-bit microcode data value from a text file and convert to raw binary form.
3031
3032 Arguments:
3033 InFptr - file pointer to input text file
3034 Data - pointer to where to return the data parsed
3035
3036 Returns:
3037 STATUS_SUCCESS - no errors or warnings, Data contains valid information
3038 STATUS_ERROR - errors were encountered
3039
3040 --*/
3041 {
3042 CHAR8 Line[MAX_LINE_LEN];
3043 CHAR8 *cptr;
3044
3045 Line[MAX_LINE_LEN - 1] = 0;
3046 while (1) {
3047 if (fgets (Line, MAX_LINE_LEN, InFptr) == NULL) {
3048 return STATUS_ERROR;
3049 }
3050 //
3051 // If it was a binary file, then it may have overwritten our null terminator
3052 //
3053 if (Line[MAX_LINE_LEN - 1] != 0) {
3054 return STATUS_ERROR;
3055 }
3056
3057 //
3058 // strip space
3059 //
3060 for (cptr = Line; *cptr && isspace(*cptr); cptr++) {
3061 }
3062
3063 // Skip Blank Lines and Comment Lines
3064 if ((strlen(cptr) != 0) && (*cptr != ';')) {
3065 break;
3066 }
3067 }
3068
3069 // Look for
3070 // dd 000000001h ; comment
3071 // dd XXXXXXXX
3072 // DD XXXXXXXXX
3073 // DD XXXXXXXXX
3074 //
3075 if ((tolower(cptr[0]) == 'd') && (tolower(cptr[1]) == 'd') && isspace (cptr[2])) {
3076 //
3077 // Skip blanks and look for a hex digit
3078 //
3079 cptr += 3;
3080 for (; *cptr && isspace(*cptr); cptr++) {
3081 }
3082 if (isxdigit (*cptr)) {
3083 if (sscanf (cptr, "%X", Data) != 1) {
3084 return STATUS_ERROR;
3085 }
3086 }
3087 return STATUS_SUCCESS;
3088 }
3089
3090 return STATUS_ERROR;
3091 }