3 Copyright (c) 2004, 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
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+ image to an FW image type
22 #include "WinNtInclude.h"
32 #include <Common/UefiBaseTypes.h>
33 #include <Common/EfiImage.h>
35 #include "CommonLib.h"
36 #include "EfiUtilityMsgs.c"
39 // Version of this utility
41 #define UTILITY_NAME "FwImage"
42 #define UTILITY_MAJOR_VERSION 1
43 #define UTILITY_MINOR_VERSION 0
46 typedef unsigned long ULONG
;
47 typedef unsigned char UCHAR
;
48 typedef unsigned char *PUCHAR
;
49 typedef unsigned short USHORT
;
58 printf ("%s v%d.%d -EDK Utility for Converting a pe32+ image to an FW image type.\n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
);
59 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
69 printf ("\nUsage: " UTILITY_NAME
" {-t time-date} {-h|--help|-?|/?|-V|--version} \n\
70 [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\
71 DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\
72 USER_DEFINED] peimage [outimage]");
85 UCHAR Buffer
[8 * 1024];
87 fseek (in
, 0, SEEK_END
);
88 filesize
= ftell (in
);
90 fseek (in
, 0, SEEK_SET
);
91 fseek (out
, 0, SEEK_SET
);
94 while (offset
< filesize
) {
95 length
= sizeof (Buffer
);
96 if (filesize
- offset
< length
) {
97 length
= filesize
- offset
;
100 fread (Buffer
, length
, 1, in
);
101 fwrite (Buffer
, length
, 1, out
);
105 if ((ULONG
) ftell (out
) != filesize
) {
106 Error (NULL
, 0, 0, "write error", NULL
);
110 return STATUS_SUCCESS
;
121 fseek (in
, 0, SEEK_END
);
122 *Length
= ftell (in
);
123 *Buffer
= malloc (*Length
);
124 fseek (in
, 0, SEEK_SET
);
125 fread (*Buffer
, *Length
, 1, in
);
126 return STATUS_SUCCESS
;
137 fseek (out
, 0, SEEK_SET
);
138 fwrite (Buffer
, Length
, 1, out
);
139 if ((ULONG
) ftell (out
) != Length
) {
140 Error (NULL
, 0, 0, "write error", NULL
);
144 return STATUS_SUCCESS
;
160 argc - Number of command line parameters.
161 argv - Array of pointers to command line parameter strings.
164 STATUS_SUCCESS - Utility exits successfully.
165 STATUS_ERROR - Some error occurred during execution.
178 EFI_IMAGE_DOS_HEADER
*DosHdr
;
179 EFI_IMAGE_NT_HEADERS
*PeHdr
;
180 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
181 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
183 struct tm TimeStruct
;
184 EFI_IMAGE_DOS_HEADER BackupDosHdr
;
189 BOOLEAN TimeStampPresent
;
190 UINTN AllignedRelocSize
;
192 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
195 RUNTIME_FUNCTION
*RuntimeFunction
;
196 UNWIND_INFO
*UnwindInfo
;
198 SetUtilityName (UTILITY_NAME
);
200 // Assign to fix compile warning
206 TimeStampPresent
= FALSE
;
213 if ((strcmp(argv
[1], "-h") == 0) || (strcmp(argv
[1], "--help") == 0) ||
214 (strcmp(argv
[1], "-?") == 0) || (strcmp(argv
[1], "/?") == 0)) {
219 if ((strcmp(argv
[1], "-V") == 0) || (strcmp(argv
[1], "--version") == 0)) {
225 // Look for -t time-date option first. If the time is "0", then
228 if ((argc
> 2) && !strcmp (argv
[1], "-t")) {
229 TimeStampPresent
= TRUE
;
230 if (strcmp (argv
[2], "0") != 0) {
232 // Convert the string to a value
234 memset ((char *) &TimeStruct
, 0, sizeof (TimeStruct
));
236 argv
[2], "%d/%d/%d,%d:%d:%d",
237 &TimeStruct
.tm_mon
, /* months since January - [0,11] */
238 &TimeStruct
.tm_mday
, /* day of the month - [1,31] */
239 &TimeStruct
.tm_year
, /* years since 1900 */
240 &TimeStruct
.tm_hour
, /* hours since midnight - [0,23] */
241 &TimeStruct
.tm_min
, /* minutes after the hour - [0,59] */
242 &TimeStruct
.tm_sec
/* seconds after the minute - [0,59] */
244 Error (NULL
, 0, 0, argv
[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
248 // Now fixup some of the fields
251 TimeStruct
.tm_year
-= 1900;
253 // Sanity-check values?
256 TimeStamp
= mktime (&TimeStruct
);
257 if (TimeStamp
== (time_t) - 1) {
258 Error (NULL
, 0, 0, argv
[2], "failed to convert time");
263 // Skip over the args
269 // Check for enough args
277 OutImageName
= argv
[3];
280 // Get new image type
283 if (*p
== '/' || *p
== '\\') {
287 if (stricmp (p
, "app") == 0 || stricmp (p
, "UEFI_APPLICATION") == 0) {
288 Type
= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
;
291 } else if (stricmp (p
, "bsdrv") == 0 || stricmp (p
, "DXE_DRIVER") == 0) {
292 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
295 } else if (stricmp (p
, "rtdrv") == 0 || stricmp (p
, "DXE_RUNTIME_DRIVER") == 0) {
296 Type
= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
;
299 } else if (stricmp (p
, "rtdrv") == 0 || stricmp (p
, "DXE_SAL_DRIVER") == 0) {
300 Type
= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
;
302 } else if (stricmp (p
, "SEC") == 0) {
303 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
305 } else if (stricmp (p
, "peim") == 0 ||
306 stricmp (p
, "BASE") == 0 ||
307 stricmp (p
, "PEI_CORE") == 0 ||
308 stricmp (p
, "PEIM") == 0 ||
309 stricmp (p
, "DXE_SMM_DRIVER") == 0 ||
310 stricmp (p
, "TOOL") == 0 ||
311 stricmp (p
, "UEFI_APPLICATION") == 0 ||
312 stricmp (p
, "USER_DEFINED") == 0 ||
313 stricmp (p
, "UEFI_DRIVER") == 0 ||
314 stricmp (p
, "DXE_CORE") == 0
316 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
326 fpIn
= fopen (argv
[2], "rb");
328 Error (NULL
, 0, 0, argv
[2], "failed to open input file for reading");
332 FReadFile (fpIn
, (VOID
**)&FileBuffer
, &FileLength
);
335 // Read the dos & pe hdrs of the image
337 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)FileBuffer
;
338 if (DosHdr
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
339 Error (NULL
, 0, 0, argv
[2], "DOS header signature not found in source image");
344 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)(FileBuffer
+ DosHdr
->e_lfanew
);
345 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
346 Error (NULL
, 0, 0, argv
[2], "PE header signature not found in source image");
354 strcpy (outname
, argv
[2]);
356 for (p
= outname
; *p
; p
++) {
369 OutImageName
= outname
;
372 fpOut
= fopen (OutImageName
, "w+b");
374 Error (NULL
, 0, 0, OutImageName
, "could not open output file for writing");
380 // Zero all unused fields of the DOS header
382 memcpy (&BackupDosHdr
, DosHdr
, sizeof (EFI_IMAGE_DOS_HEADER
));
383 memset (DosHdr
, 0, sizeof (EFI_IMAGE_DOS_HEADER
));
384 DosHdr
->e_magic
= BackupDosHdr
.e_magic
;
385 DosHdr
->e_lfanew
= BackupDosHdr
.e_lfanew
;
387 for (Index
= sizeof (EFI_IMAGE_DOS_HEADER
); Index
< (ULONG
) DosHdr
->e_lfanew
; Index
++) {
388 FileBuffer
[Index
] = DosHdr
->e_cp
;
392 // Path the PE header
394 PeHdr
->OptionalHeader
.Subsystem
= (USHORT
) Type
;
395 if (TimeStampPresent
) {
396 PeHdr
->FileHeader
.TimeDateStamp
= (UINT32
) TimeStamp
;
399 if (PeHdr
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
400 Optional32
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHdr
->OptionalHeader
;
401 Optional32
->MajorLinkerVersion
= 0;
402 Optional32
->MinorLinkerVersion
= 0;
403 Optional32
->MajorOperatingSystemVersion
= 0;
404 Optional32
->MinorOperatingSystemVersion
= 0;
405 Optional32
->MajorImageVersion
= 0;
406 Optional32
->MinorImageVersion
= 0;
407 Optional32
->MajorSubsystemVersion
= 0;
408 Optional32
->MinorSubsystemVersion
= 0;
409 Optional32
->Win32VersionValue
= 0;
410 Optional32
->CheckSum
= 0;
411 Optional32
->SizeOfStackReserve
= 0;
412 Optional32
->SizeOfStackCommit
= 0;
413 Optional32
->SizeOfHeapReserve
= 0;
414 Optional32
->SizeOfHeapCommit
= 0;
417 // Strip zero padding at the end of the .reloc section
419 if (Optional32
->NumberOfRvaAndSizes
>= 6) {
420 if (Optional32
->DataDirectory
[5].Size
!= 0) {
421 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
422 for (Index
= 0; Index
< PeHdr
->FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
424 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
426 if (SectionHeader
->VirtualAddress
== Optional32
->DataDirectory
[5].VirtualAddress
) {
427 SectionHeader
->Misc
.VirtualSize
= Optional32
->DataDirectory
[5].Size
;
428 AllignedRelocSize
= (Optional32
->DataDirectory
[5].Size
+ Optional32
->FileAlignment
- 1) & (~(Optional32
->FileAlignment
- 1));
430 // Check to see if there is zero padding at the end of the base relocations
432 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
434 // Check to see if the base relocations are at the end of the file
436 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional32
->SizeOfImage
) {
438 // All the required conditions are met to strip the zero padding of the end of the base relocations section
440 Optional32
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
441 Optional32
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
442 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
443 FileLength
= Optional32
->SizeOfImage
;
451 if (PeHdr
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
452 Optional64
= (EFI_IMAGE_OPTIONAL_HEADER64
*)&PeHdr
->OptionalHeader
;
453 Optional64
->MajorLinkerVersion
= 0;
454 Optional64
->MinorLinkerVersion
= 0;
455 Optional64
->MajorOperatingSystemVersion
= 0;
456 Optional64
->MinorOperatingSystemVersion
= 0;
457 Optional64
->MajorImageVersion
= 0;
458 Optional64
->MinorImageVersion
= 0;
459 Optional64
->MajorSubsystemVersion
= 0;
460 Optional64
->MinorSubsystemVersion
= 0;
461 Optional64
->Win32VersionValue
= 0;
462 Optional64
->CheckSum
= 0;
463 Optional64
->SizeOfStackReserve
= 0;
464 Optional64
->SizeOfStackCommit
= 0;
465 Optional64
->SizeOfHeapReserve
= 0;
466 Optional64
->SizeOfHeapCommit
= 0;
469 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
471 if (PeHdr
->FileHeader
.Machine
== 0x8664) { // X64
472 if (Optional64
->NumberOfRvaAndSizes
>= 4) {
473 if (Optional64
->NumberOfRvaAndSizes
< 7 || (Optional64
->NumberOfRvaAndSizes
>= 7 && Optional64
->DataDirectory
[6].Size
== 0)) {
474 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
475 for (Index
= 0; Index
< PeHdr
->FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
476 if (SectionHeader
->VirtualAddress
== Optional64
->DataDirectory
[3].VirtualAddress
) {
477 RuntimeFunction
= (RUNTIME_FUNCTION
*)(FileBuffer
+ SectionHeader
->PointerToRawData
);
478 for (Index1
= 0; Index1
< Optional64
->DataDirectory
[3].Size
/ sizeof (RUNTIME_FUNCTION
); Index1
++, RuntimeFunction
++) {
479 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
480 for (Index2
= 0; Index2
< PeHdr
->FileHeader
.NumberOfSections
; Index2
++, SectionHeader
++) {
481 if (RuntimeFunction
->UnwindInfoAddress
> SectionHeader
->VirtualAddress
&& RuntimeFunction
->UnwindInfoAddress
< (SectionHeader
->VirtualAddress
+ SectionHeader
->SizeOfRawData
)) {
482 UnwindInfo
= (UNWIND_INFO
*)(FileBuffer
+ SectionHeader
->PointerToRawData
+ (RuntimeFunction
->UnwindInfoAddress
- SectionHeader
->VirtualAddress
));
483 if (UnwindInfo
->Version
== 1) {
484 memset (UnwindInfo
+ 1, 0, UnwindInfo
->CountOfUnwindCodes
* sizeof (UINT16
));
485 memset (UnwindInfo
, 0, sizeof (UNWIND_INFO
));
489 memset (RuntimeFunction
, 0, sizeof (RUNTIME_FUNCTION
));
495 Optional64
->DataDirectory
[3].Size
= 0;
496 Optional64
->DataDirectory
[3].VirtualAddress
= 0;
502 // Strip zero padding at the end of the .reloc section
504 if (Optional64
->NumberOfRvaAndSizes
>= 6) {
505 if (Optional64
->DataDirectory
[5].Size
!= 0) {
506 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
507 for (Index
= 0; Index
< PeHdr
->FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
509 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
511 if (SectionHeader
->VirtualAddress
== Optional64
->DataDirectory
[5].VirtualAddress
) {
512 SectionHeader
->Misc
.VirtualSize
= Optional64
->DataDirectory
[5].Size
;
513 AllignedRelocSize
= (Optional64
->DataDirectory
[5].Size
+ Optional64
->FileAlignment
- 1) & (~(Optional64
->FileAlignment
- 1));
515 // Check to see if there is zero padding at the end of the base relocations
517 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
519 // Check to see if the base relocations are at the end of the file
521 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional64
->SizeOfImage
) {
523 // All the required conditions are met to strip the zero padding of the end of the base relocations section
525 Optional64
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
526 Optional64
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
527 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
528 FileLength
= Optional64
->SizeOfImage
;
537 FWriteFile (fpOut
, FileBuffer
, FileLength
);
545 // printf ("Created %s\n", OutImageName);
547 return STATUS_SUCCESS
;