3 Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR>
4 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
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.
18 Converts a pe32/pe32+ image to an FW image type
28 #include "TianoCommon.h"
30 #include "EfiUtilityMsgs.c"
32 #define UTILITY_NAME "FwImage"
35 IMAGE_NT_HEADERS32 PeHeader32
;
36 IMAGE_NT_HEADERS64 PeHeader64
;
44 printf ("Usage: " UTILITY_NAME
" {-t time-date} {-e} {-r} [APPLICATION|BS_DRIVER|RT_DRIVER|SAL_RT_DRIVER|COMBINED_PEIM_DRIVER|SECURITY_CORE|PEI_CORE|PE32_PEIM|RELOCATABLE_PEIM] peimage [outimage]\n");
45 printf (" -t: Add Time Stamp for output image\n");
46 printf (" -e: Not clear ExceptionTable for output image\n");
47 printf (" -r: Not strip zero pending of .reloc for output image\n");
58 fseek (in
, 0, SEEK_END
);
60 *Buffer
= malloc (*Length
);
61 fseek (in
, 0, SEEK_SET
);
62 fread (*Buffer
, *Length
, 1, in
);
63 return STATUS_SUCCESS
;
74 fseek (out
, 0, SEEK_SET
);
75 fwrite (Buffer
, Length
, 1, out
);
76 if ((ULONG
) ftell (out
) != Length
) {
77 Error (NULL
, 0, 0, "write error", NULL
);
81 return STATUS_SUCCESS
;
87 IN EFI_IMAGE_DOS_HEADER
*DosHdr
,
97 UINT32 SectionNameSize
;
98 EFI_IMAGE_SECTION_HEADER
*Section
;
107 // Search .pdata section
109 if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
110 if ((PeHdr
->PeHeader32
.OptionalHeader
.NumberOfRvaAndSizes
> IMAGE_DIRECTORY_ENTRY_EXCEPTION
) &&
111 (PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
!= 0) &&
112 (PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
!= 0)) {
114 PdataRVA
= PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
;
115 PdataRVASize
= PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
;
117 PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
= 0;
118 PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
= 0;
120 SectionOffset
= sizeof(PeHdr
->PeHeader32
);
123 if ((PeHdr
->PeHeader64
.OptionalHeader
.NumberOfRvaAndSizes
> IMAGE_DIRECTORY_ENTRY_EXCEPTION
) &&
124 (PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
!= 0) &&
125 (PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
!= 0)) {
127 PdataRVA
= PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
;
128 PdataRVASize
= PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
;
130 PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
= 0;
131 PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
= 0;
133 SectionOffset
= sizeof(PeHdr
->PeHeader64
);
137 if ((PdataRVASize
!= 0) && (PdataRVA
!= 0)) {
139 SectionNumber
= PeHdr
->PeHeader32
.FileHeader
.NumberOfSections
;
140 SectionNameSize
= sizeof(Section
->Name
);
141 while (SectionNumber
> 0) {
142 Section
= (EFI_IMAGE_SECTION_HEADER
*) &FileBuffer
[DosHdr
->e_lfanew
+ SectionOffset
];
143 if (strcmp (Section
->Name
, ".pdata") == 0) {
145 // Zero .pdata Section Header Name
148 FileBuffer
+ DosHdr
->e_lfanew
+ SectionOffset
,
153 // Zero .pdata Secton raw data
155 PdataOffset
= Section
->PointerToRawData
;
156 PdataSize
= Section
->SizeOfRawData
;
157 memset (FileBuffer
+ PdataOffset
, 0, PdataSize
);
161 SectionOffset
+= sizeof(EFI_IMAGE_SECTION_HEADER
);
169 StripZeroPendingReloc (
170 IN UINT8
*FileBuffer
,
171 IN OUT UINTN
*FileLength
,
172 IN EFI_IMAGE_DOS_HEADER
*DosHdr
,
176 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
177 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
178 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
179 UINTN AllignedRelocSize
;
182 if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
183 Optional32
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHdr
->PeHeader32
.OptionalHeader
;
184 if ((Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) &&
185 (Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)) {
186 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->PeHeader32
.FileHeader
.SizeOfOptionalHeader
);
187 for (Index
= 0; Index
< PeHdr
->PeHeader32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
189 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
191 if (strcmp (SectionHeader
->Name
, ".reloc") == 0) {
192 SectionHeader
->Misc
.VirtualSize
= Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
194 AllignedRelocSize
= (Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
+
195 Optional32
->FileAlignment
- 1) & (~(Optional32
->FileAlignment
- 1));
197 // Check to see if there is zero padding at the end of the base relocations
199 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
201 // Check to see if the base relocations are at the end of the file
203 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional32
->SizeOfImage
) {
205 // All the required conditions are met to strip the zero padding of the end of the base relocations section
207 Optional32
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
208 Optional32
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
209 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
210 *FileLength
= Optional32
->SizeOfImage
;
217 Optional64
= (EFI_IMAGE_OPTIONAL_HEADER64
*)&PeHdr
->PeHeader64
.OptionalHeader
;
218 if ((Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) &&
219 (Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)) {
220 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->PeHeader64
.FileHeader
.SizeOfOptionalHeader
);
221 for (Index
= 0; Index
< PeHdr
->PeHeader64
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
223 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
225 if (strcmp (SectionHeader
->Name
, ".reloc") == 0) {
226 SectionHeader
->Misc
.VirtualSize
= Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
228 AllignedRelocSize
= (Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
+
229 Optional64
->FileAlignment
- 1) & (~(Optional64
->FileAlignment
- 1));
231 // Check to see if there is zero padding at the end of the base relocations
233 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
235 // Check to see if the base relocations are at the end of the file
237 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional64
->SizeOfImage
) {
239 // All the required conditions are met to strip the zero padding of the end of the base relocations section
241 Optional64
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
242 Optional64
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
243 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
244 *FileLength
= Optional64
->SizeOfImage
;
266 argc - Number of command line parameters.
267 argv - Array of pointers to command line parameter strings.
271 STATUS_SUCCESS - Utility exits successfully.
272 STATUS_ERROR - Some error occurred during execution.
284 EFI_IMAGE_DOS_HEADER
*DosHdr
;
287 struct tm TimeStruct
;
288 EFI_IMAGE_DOS_HEADER BackupDosHdr
;
290 BOOLEAN TimeStampPresent
;
291 BOOLEAN NeedClearExceptionTable
;
292 BOOLEAN NeedStripZeroPendingReloc
;
295 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
296 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
298 SetUtilityName (UTILITY_NAME
);
300 // Assign to fix compile warning
306 TimeStampPresent
= FALSE
;
308 NeedClearExceptionTable
= TRUE
;
309 NeedStripZeroPendingReloc
= TRUE
;
312 // Look for -t time-date option first. If the time is "0", then
315 if ((argc
> 2) && !strcmp (argv
[1], "-t")) {
316 TimeStampPresent
= TRUE
;
317 if (strcmp (argv
[2], "0") != 0) {
319 // Convert the string to a value
321 memset ((char *) &TimeStruct
, 0, sizeof (TimeStruct
));
323 argv
[2], "%d/%d/%d,%d:%d:%d",
324 &TimeStruct
.tm_mon
, /* months since January - [0,11] */
325 &TimeStruct
.tm_mday
, /* day of the month - [1,31] */
326 &TimeStruct
.tm_year
, /* years since 1900 */
327 &TimeStruct
.tm_hour
, /* hours since midnight - [0,23] */
328 &TimeStruct
.tm_min
, /* minutes after the hour - [0,59] */
329 &TimeStruct
.tm_sec
/* seconds after the minute - [0,59] */
331 Error (NULL
, 0, 0, argv
[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
335 // Now fixup some of the fields
338 TimeStruct
.tm_year
-= 1900;
340 // Sanity-check values?
343 TimeStamp
= mktime (&TimeStruct
);
344 if (TimeStamp
== (time_t) - 1) {
345 Error (NULL
, 0, 0, argv
[2], "failed to convert time");
350 // Skip over the args
357 // Look for -e option.
359 if ((argc
> 1) && !strcmp (argv
[1], "-e")) {
360 NeedClearExceptionTable
= FALSE
;
362 // Skip over the args
369 // Look for -r option
371 if ((argc
> 1) && !strcmp (argv
[1], "-r")) {
372 NeedStripZeroPendingReloc
= FALSE
;
374 // Skip over the args
381 // Check for enough args
389 OutImageName
= argv
[3];
392 // Get new image type
395 if (*p
== '/' || *p
== '\\') {
399 if (_stricmp (p
, "app") == 0 || _stricmp (p
, "APPLICATION") == 0) {
400 Type
= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
;
403 } else if (_stricmp (p
, "bsdrv") == 0 || _stricmp (p
, "BS_DRIVER") == 0) {
404 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
407 } else if (_stricmp (p
, "rtdrv") == 0 || _stricmp (p
, "RT_DRIVER") == 0) {
408 Type
= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
;
411 } else if (_stricmp (p
, "rtdrv") == 0 || _stricmp (p
, "SAL_RT_DRIVER") == 0) {
412 Type
= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
;
414 } else if (_stricmp (p
, "SECURITY_CORE") == 0) {
415 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
417 } else if (_stricmp (p
, "peim") == 0 ||
418 _stricmp (p
, "PEI_CORE") == 0 ||
419 _stricmp (p
, "PE32_PEIM") == 0 ||
420 _stricmp (p
, "RELOCATABLE_PEIM") == 0 ||
421 _stricmp (p
, "combined_peim_driver") == 0
423 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
432 fpIn
= fopen (argv
[2], "rb");
434 Error (NULL
, 0, 0, argv
[2], "failed to open input file for reading");
437 FReadFile (fpIn
, (VOID
**)&FileBuffer
, &FileLength
);
439 // Read the dos & pe hdrs of the image
441 DosHdr
= (EFI_IMAGE_DOS_HEADER
*) FileBuffer
;
442 if (DosHdr
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
443 Error (NULL
, 0, 0, argv
[2], "DOS header signature not found in source image");
448 PeHdr
= (PE_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
);
449 if (PeHdr
->PeHeader32
.Signature
!= IMAGE_NT_SIGNATURE
) {
450 Error (NULL
, 0, 0, argv
[2], "PE header signature not found in source image");
457 strcpy (outname
, argv
[2]);
459 for (p
= outname
; *p
; p
++) {
472 OutImageName
= outname
;
475 fpOut
= fopen (OutImageName
, "w+b");
477 Error (NULL
, 0, 0, OutImageName
, "could not open output file for writing");
482 // Zero all unused fields of the DOS header
484 memcpy (&BackupDosHdr
, DosHdr
, sizeof (EFI_IMAGE_DOS_HEADER
));
485 memset (DosHdr
, 0, sizeof (EFI_IMAGE_DOS_HEADER
));
486 DosHdr
->e_magic
= BackupDosHdr
.e_magic
;
487 DosHdr
->e_lfanew
= BackupDosHdr
.e_lfanew
;
489 for (Index
= sizeof (EFI_IMAGE_DOS_HEADER
); Index
< (ULONG
) DosHdr
->e_lfanew
; Index
++) {
490 FileBuffer
[Index
] = (UINT8
) DosHdr
->e_cp
;
494 // Modify some fields in the PE header
498 // TimeDateStamp's offset is fixed for PE32/32+
500 if (TimeStampPresent
) {
501 PeHdr
->PeHeader32
.FileHeader
.TimeDateStamp
= (UINT32
) TimeStamp
;
505 // PE32/32+ has different optional header layout
506 // Determine format is PE32 or PE32+ before modification
508 if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
512 Optional32
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHdr
->PeHeader32
.OptionalHeader
;
514 Optional32
->MajorLinkerVersion
= 0;
515 Optional32
->MinorLinkerVersion
= 0;
516 Optional32
->MajorOperatingSystemVersion
= 0;
517 Optional32
->MinorOperatingSystemVersion
= 0;
518 Optional32
->MajorImageVersion
= 0;
519 Optional32
->MinorImageVersion
= 0;
520 Optional32
->MajorSubsystemVersion
= 0;
521 Optional32
->MinorSubsystemVersion
= 0;
522 Optional32
->Win32VersionValue
= 0;
523 Optional32
->CheckSum
= 0;
524 Optional32
->SizeOfStackReserve
= 0;
525 Optional32
->SizeOfStackCommit
= 0;
526 Optional32
->SizeOfHeapReserve
= 0;
527 Optional32
->SizeOfHeapCommit
= 0;
528 Optional32
->Subsystem
= (USHORT
) Type
;
531 // Strip zero padding at the end of the .reloc section
533 if (NeedStripZeroPendingReloc
) {
534 StripZeroPendingReloc (FileBuffer
, &FileLength
, DosHdr
, PeHdr
);
536 } else if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
540 Optional64
= (EFI_IMAGE_OPTIONAL_HEADER64
*)&PeHdr
->PeHeader64
.OptionalHeader
;
542 Optional64
->MajorLinkerVersion
= 0;
543 Optional64
->MinorLinkerVersion
= 0;
544 Optional64
->MajorOperatingSystemVersion
= 0;
545 Optional64
->MinorOperatingSystemVersion
= 0;
546 Optional64
->MajorImageVersion
= 0;
547 Optional64
->MinorImageVersion
= 0;
548 Optional64
->MajorSubsystemVersion
= 0;
549 Optional64
->MinorSubsystemVersion
= 0;
550 Optional64
->Win32VersionValue
= 0;
551 Optional64
->CheckSum
= 0;
552 Optional64
->SizeOfStackReserve
= 0;
553 Optional64
->SizeOfStackCommit
= 0;
554 Optional64
->SizeOfHeapReserve
= 0;
555 Optional64
->SizeOfHeapCommit
= 0;
556 Optional64
->Subsystem
= (USHORT
) Type
;
559 // Strip zero padding at the end of the .reloc section
561 if (NeedStripZeroPendingReloc
) {
562 StripZeroPendingReloc (FileBuffer
, &FileLength
, DosHdr
, PeHdr
);
565 Error (NULL
, 0, 0, argv
[2], "Unsupported PE image");
572 // Zero PDATA section for smaller binary size after compression
574 if (NeedClearExceptionTable
) {
575 ZeroExceptionTable (FileBuffer
, DosHdr
, PeHdr
);
578 FWriteFile (fpOut
, FileBuffer
, FileLength
);
586 return STATUS_SUCCESS
;