3 Copyright (c) 2004 - 2010, 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"
33 #define UTILITY_VERSION "v1.0"
36 IMAGE_NT_HEADERS32 PeHeader32
;
37 IMAGE_NT_HEADERS64 PeHeader64
;
47 UTILITY_NAME
" "UTILITY_VERSION
" - Intel Firmware Image Utility",
48 " Copyright (C), 2004 - 2008 Intel Corporation",
50 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
51 " Built from "UTILITY_BUILD
", project of "UTILITY_VENDOR
,
56 " "UTILITY_NAME
" [OPTION]... FWTYPE SOURCE [DEST]",
58 " Converts a pe32/pe32+ SOURCE to DEST with FWTYPE image type.",
60 " FWTYPE Can be one of APPLICATION, BS_DRIVER, RT_DRIVER, SAL_RT_DRIVER,",
61 " COMBINED_PEIM_DRIVER, SECURITY_CORE, PEI_CORE, PE32_PEIM and",
63 " -t time-date Add Time Stamp for output image",
64 " -e Not clear ExceptionTable for output image",
65 " -r Not strip zero pending of .reloc for output image",
69 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
70 fprintf (stdout
, "%s\n", Str
[Index
]);
82 fseek (in
, 0, SEEK_END
);
84 *Buffer
= malloc (*Length
);
85 fseek (in
, 0, SEEK_SET
);
86 fread (*Buffer
, *Length
, 1, in
);
87 return STATUS_SUCCESS
;
98 fseek (out
, 0, SEEK_SET
);
99 fwrite (Buffer
, Length
, 1, out
);
100 if ((ULONG
) ftell (out
) != Length
) {
101 Error (NULL
, 0, 0, "write error", NULL
);
105 return STATUS_SUCCESS
;
110 IN UINT8
*FileBuffer
,
111 IN EFI_IMAGE_DOS_HEADER
*DosHdr
,
119 UINT32 SectionOffset
;
120 UINT16 SectionNumber
;
121 UINT32 SectionNameSize
;
122 EFI_IMAGE_SECTION_HEADER
*Section
;
131 // Search .pdata section
133 if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
134 if ((PeHdr
->PeHeader32
.OptionalHeader
.NumberOfRvaAndSizes
> IMAGE_DIRECTORY_ENTRY_EXCEPTION
) &&
135 (PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
!= 0) &&
136 (PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
!= 0)) {
138 PdataRVA
= PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
;
139 PdataRVASize
= PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
;
141 PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
= 0;
142 PeHdr
->PeHeader32
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
= 0;
144 SectionOffset
= sizeof(PeHdr
->PeHeader32
);
147 if ((PeHdr
->PeHeader64
.OptionalHeader
.NumberOfRvaAndSizes
> IMAGE_DIRECTORY_ENTRY_EXCEPTION
) &&
148 (PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
!= 0) &&
149 (PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
!= 0)) {
151 PdataRVA
= PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
;
152 PdataRVASize
= PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
;
154 PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].VirtualAddress
= 0;
155 PeHdr
->PeHeader64
.OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXCEPTION
].Size
= 0;
157 SectionOffset
= sizeof(PeHdr
->PeHeader64
);
161 if ((PdataRVASize
!= 0) && (PdataRVA
!= 0)) {
163 SectionNumber
= PeHdr
->PeHeader32
.FileHeader
.NumberOfSections
;
164 SectionNameSize
= sizeof(Section
->Name
);
165 while (SectionNumber
> 0) {
166 Section
= (EFI_IMAGE_SECTION_HEADER
*) &FileBuffer
[DosHdr
->e_lfanew
+ SectionOffset
];
167 if (strcmp (Section
->Name
, ".pdata") == 0) {
169 // Zero .pdata Section Header Name
172 FileBuffer
+ DosHdr
->e_lfanew
+ SectionOffset
,
177 // Zero .pdata Secton raw data
179 PdataOffset
= Section
->PointerToRawData
;
180 PdataSize
= Section
->SizeOfRawData
;
181 memset (FileBuffer
+ PdataOffset
, 0, PdataSize
);
185 SectionOffset
+= sizeof(EFI_IMAGE_SECTION_HEADER
);
193 StripZeroPendingReloc (
194 IN UINT8
*FileBuffer
,
195 IN OUT UINTN
*FileLength
,
196 IN EFI_IMAGE_DOS_HEADER
*DosHdr
,
200 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
201 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
202 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
203 UINTN AllignedRelocSize
;
206 if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
207 Optional32
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHdr
->PeHeader32
.OptionalHeader
;
208 if ((Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) &&
209 (Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)) {
210 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->PeHeader32
.FileHeader
.SizeOfOptionalHeader
);
211 for (Index
= 0; Index
< PeHdr
->PeHeader32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
213 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
215 if (strcmp (SectionHeader
->Name
, ".reloc") == 0) {
216 SectionHeader
->Misc
.VirtualSize
= Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
218 AllignedRelocSize
= (Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
+
219 Optional32
->FileAlignment
- 1) & (~(Optional32
->FileAlignment
- 1));
221 // Check to see if there is zero padding at the end of the base relocations
223 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
225 // Check to see if the base relocations are at the end of the file
227 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional32
->SizeOfImage
) {
229 // All the required conditions are met to strip the zero padding of the end of the base relocations section
231 Optional32
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
232 Optional32
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
233 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
234 *FileLength
= Optional32
->SizeOfImage
;
241 Optional64
= (EFI_IMAGE_OPTIONAL_HEADER64
*)&PeHdr
->PeHeader64
.OptionalHeader
;
242 if ((Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) &&
243 (Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)) {
244 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->PeHeader64
.FileHeader
.SizeOfOptionalHeader
);
245 for (Index
= 0; Index
< PeHdr
->PeHeader64
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
247 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
249 if (strcmp (SectionHeader
->Name
, ".reloc") == 0) {
250 SectionHeader
->Misc
.VirtualSize
= Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
252 AllignedRelocSize
= (Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
+
253 Optional64
->FileAlignment
- 1) & (~(Optional64
->FileAlignment
- 1));
255 // Check to see if there is zero padding at the end of the base relocations
257 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
259 // Check to see if the base relocations are at the end of the file
261 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional64
->SizeOfImage
) {
263 // All the required conditions are met to strip the zero padding of the end of the base relocations section
265 Optional64
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
266 Optional64
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
267 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
268 *FileLength
= Optional64
->SizeOfImage
;
290 argc - Number of command line parameters.
291 argv - Array of pointers to command line parameter strings.
295 STATUS_SUCCESS - Utility exits successfully.
296 STATUS_ERROR - Some error occurred during execution.
308 EFI_IMAGE_DOS_HEADER
*DosHdr
;
311 struct tm TimeStruct
;
312 EFI_IMAGE_DOS_HEADER BackupDosHdr
;
314 BOOLEAN TimeStampPresent
;
315 BOOLEAN NeedClearExceptionTable
;
316 BOOLEAN NeedStripZeroPendingReloc
;
319 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
320 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
322 SetUtilityName (UTILITY_NAME
);
324 // Assign to fix compile warning
330 TimeStampPresent
= FALSE
;
332 NeedClearExceptionTable
= TRUE
;
333 NeedStripZeroPendingReloc
= TRUE
;
336 // Look for -t time-date option first. If the time is "0", then
339 if ((argc
> 2) && !strcmp (argv
[1], "-t")) {
340 TimeStampPresent
= TRUE
;
341 if (strcmp (argv
[2], "0") != 0) {
343 // Convert the string to a value
345 memset ((char *) &TimeStruct
, 0, sizeof (TimeStruct
));
347 argv
[2], "%d/%d/%d,%d:%d:%d",
348 &TimeStruct
.tm_mon
, /* months since January - [0,11] */
349 &TimeStruct
.tm_mday
, /* day of the month - [1,31] */
350 &TimeStruct
.tm_year
, /* years since 1900 */
351 &TimeStruct
.tm_hour
, /* hours since midnight - [0,23] */
352 &TimeStruct
.tm_min
, /* minutes after the hour - [0,59] */
353 &TimeStruct
.tm_sec
/* seconds after the minute - [0,59] */
355 Error (NULL
, 0, 0, argv
[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
359 // Now fixup some of the fields
362 TimeStruct
.tm_year
-= 1900;
364 // Sanity-check values?
367 TimeStamp
= mktime (&TimeStruct
);
368 if (TimeStamp
== (time_t) - 1) {
369 Error (NULL
, 0, 0, argv
[2], "failed to convert time");
374 // Skip over the args
381 // Look for -e option.
383 if ((argc
> 1) && !strcmp (argv
[1], "-e")) {
384 NeedClearExceptionTable
= FALSE
;
386 // Skip over the args
393 // Look for -r option
395 if ((argc
> 1) && !strcmp (argv
[1], "-r")) {
396 NeedStripZeroPendingReloc
= FALSE
;
398 // Skip over the args
405 // Check for enough args
413 OutImageName
= argv
[3];
416 // Get new image type
419 if (*p
== '/' || *p
== '\\') {
423 if (_stricmp (p
, "app") == 0 || _stricmp (p
, "APPLICATION") == 0) {
424 Type
= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
;
427 } else if (_stricmp (p
, "bsdrv") == 0 || _stricmp (p
, "BS_DRIVER") == 0) {
428 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
431 } else if (_stricmp (p
, "rtdrv") == 0 || _stricmp (p
, "RT_DRIVER") == 0) {
432 Type
= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
;
435 } else if (_stricmp (p
, "rtdrv") == 0 || _stricmp (p
, "SAL_RT_DRIVER") == 0) {
436 Type
= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
;
438 } else if (_stricmp (p
, "SECURITY_CORE") == 0) {
439 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
441 } else if (_stricmp (p
, "peim") == 0 ||
442 _stricmp (p
, "PEI_CORE") == 0 ||
443 _stricmp (p
, "PE32_PEIM") == 0 ||
444 _stricmp (p
, "RELOCATABLE_PEIM") == 0 ||
445 _stricmp (p
, "combined_peim_driver") == 0
447 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
456 fpIn
= fopen (argv
[2], "rb");
458 Error (NULL
, 0, 0, argv
[2], "failed to open input file for reading");
461 FReadFile (fpIn
, (VOID
**)&FileBuffer
, &FileLength
);
463 // Read the dos & pe hdrs of the image
465 DosHdr
= (EFI_IMAGE_DOS_HEADER
*) FileBuffer
;
466 if (DosHdr
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
467 Error (NULL
, 0, 0, argv
[2], "DOS header signature not found in source image");
472 PeHdr
= (PE_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
);
473 if (PeHdr
->PeHeader32
.Signature
!= IMAGE_NT_SIGNATURE
) {
474 Error (NULL
, 0, 0, argv
[2], "PE header signature not found in source image");
481 strcpy (outname
, argv
[2]);
483 for (p
= outname
; *p
; p
++) {
496 OutImageName
= outname
;
499 fpOut
= fopen (OutImageName
, "w+b");
501 Error (NULL
, 0, 0, OutImageName
, "could not open output file for writing");
506 // Zero all unused fields of the DOS header
508 memcpy (&BackupDosHdr
, DosHdr
, sizeof (EFI_IMAGE_DOS_HEADER
));
509 memset (DosHdr
, 0, sizeof (EFI_IMAGE_DOS_HEADER
));
510 DosHdr
->e_magic
= BackupDosHdr
.e_magic
;
511 DosHdr
->e_lfanew
= BackupDosHdr
.e_lfanew
;
513 for (Index
= sizeof (EFI_IMAGE_DOS_HEADER
); Index
< (ULONG
) DosHdr
->e_lfanew
; Index
++) {
514 FileBuffer
[Index
] = (UINT8
) DosHdr
->e_cp
;
518 // Modify some fields in the PE header
522 // TimeDateStamp's offset is fixed for PE32/32+
524 if (TimeStampPresent
) {
525 PeHdr
->PeHeader32
.FileHeader
.TimeDateStamp
= (UINT32
) TimeStamp
;
529 // PE32/32+ has different optional header layout
530 // Determine format is PE32 or PE32+ before modification
532 if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
536 Optional32
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHdr
->PeHeader32
.OptionalHeader
;
538 Optional32
->MajorLinkerVersion
= 0;
539 Optional32
->MinorLinkerVersion
= 0;
540 Optional32
->MajorOperatingSystemVersion
= 0;
541 Optional32
->MinorOperatingSystemVersion
= 0;
542 Optional32
->MajorImageVersion
= 0;
543 Optional32
->MinorImageVersion
= 0;
544 Optional32
->MajorSubsystemVersion
= 0;
545 Optional32
->MinorSubsystemVersion
= 0;
546 Optional32
->Win32VersionValue
= 0;
547 Optional32
->CheckSum
= 0;
548 Optional32
->SizeOfStackReserve
= 0;
549 Optional32
->SizeOfStackCommit
= 0;
550 Optional32
->SizeOfHeapReserve
= 0;
551 Optional32
->SizeOfHeapCommit
= 0;
552 Optional32
->Subsystem
= (USHORT
) Type
;
555 // Strip zero padding at the end of the .reloc section
557 if (NeedStripZeroPendingReloc
) {
558 StripZeroPendingReloc (FileBuffer
, &FileLength
, DosHdr
, PeHdr
);
560 } else if (PeHdr
->PeHeader32
.OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
564 Optional64
= (EFI_IMAGE_OPTIONAL_HEADER64
*)&PeHdr
->PeHeader64
.OptionalHeader
;
566 Optional64
->MajorLinkerVersion
= 0;
567 Optional64
->MinorLinkerVersion
= 0;
568 Optional64
->MajorOperatingSystemVersion
= 0;
569 Optional64
->MinorOperatingSystemVersion
= 0;
570 Optional64
->MajorImageVersion
= 0;
571 Optional64
->MinorImageVersion
= 0;
572 Optional64
->MajorSubsystemVersion
= 0;
573 Optional64
->MinorSubsystemVersion
= 0;
574 Optional64
->Win32VersionValue
= 0;
575 Optional64
->CheckSum
= 0;
576 Optional64
->SizeOfStackReserve
= 0;
577 Optional64
->SizeOfStackCommit
= 0;
578 Optional64
->SizeOfHeapReserve
= 0;
579 Optional64
->SizeOfHeapCommit
= 0;
580 Optional64
->Subsystem
= (USHORT
) Type
;
583 // Strip zero padding at the end of the .reloc section
585 if (NeedStripZeroPendingReloc
) {
586 StripZeroPendingReloc (FileBuffer
, &FileLength
, DosHdr
, PeHdr
);
589 Error (NULL
, 0, 0, argv
[2], "Unsupported PE image");
596 // Zero PDATA section for smaller binary size after compression
598 if (NeedClearExceptionTable
) {
599 ZeroExceptionTable (FileBuffer
, DosHdr
, PeHdr
);
602 FWriteFile (fpOut
, FileBuffer
, FileLength
);
610 return STATUS_SUCCESS
;