Update FwImage to zero .xdata information if the image type is X64 and all debug...
[mirror_edk2.git] / Tools / Source / TianoTools / FwImage / fwimage.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2004, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 fwimage.c\r
15\r
16Abstract:\r
17\r
18 Converts a pe32+ image to an FW image type\r
19\r
20--*/\r
21\r
ce53a8c3 22#include "WinNtInclude.h"\r
23\r
878ddf1f 24#ifndef __GNUC__\r
25#include <windows.h>\r
26#endif\r
27#include <stdio.h>\r
28#include <stdlib.h>\r
29#include <string.h>\r
30#include <time.h>\r
31\r
ce53a8c3 32#include <Common/UefiBaseTypes.h>\r
33#include <Common/EfiImage.h>\r
34\r
35#include "CommonLib.h"\r
36#include "EfiUtilityMsgs.c"\r
878ddf1f 37\r
38#define UTILITY_NAME "FwImage"\r
39\r
40#ifdef __GNUC__\r
41typedef unsigned long ULONG;\r
42typedef unsigned char UCHAR;\r
43typedef unsigned char *PUCHAR;\r
44typedef unsigned short USHORT;\r
45#endif\r
46\r
47VOID\r
48Usage (\r
49 VOID\r
50 )\r
51{\r
8a286638 52 printf ("Usage: " UTILITY_NAME " {-t time-date} [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|USER_DEFINED] peimage [outimage]");\r
878ddf1f 53}\r
54\r
55static\r
56STATUS\r
57FCopyFile (\r
58 FILE *in,\r
59 FILE *out\r
60 )\r
61{\r
62 ULONG filesize;\r
63 ULONG offset;\r
64 ULONG length;\r
65 UCHAR Buffer[8 * 1024];\r
66\r
67 fseek (in, 0, SEEK_END);\r
68 filesize = ftell (in);\r
69\r
70 fseek (in, 0, SEEK_SET);\r
71 fseek (out, 0, SEEK_SET);\r
72\r
73 offset = 0;\r
74 while (offset < filesize) {\r
75 length = sizeof (Buffer);\r
76 if (filesize - offset < length) {\r
77 length = filesize - offset;\r
78 }\r
79\r
80 fread (Buffer, length, 1, in);\r
81 fwrite (Buffer, length, 1, out);\r
82 offset += length;\r
83 }\r
84\r
85 if ((ULONG) ftell (out) != filesize) {\r
86 Error (NULL, 0, 0, "write error", NULL);\r
87 return STATUS_ERROR;\r
88 }\r
89\r
90 return STATUS_SUCCESS;\r
91}\r
92\r
3edf127e 93static\r
94STATUS\r
95FReadFile (\r
96 FILE *in,\r
97 VOID **Buffer,\r
98 UINTN *Length\r
99 )\r
100{\r
101 fseek (in, 0, SEEK_END);\r
102 *Length = ftell (in);\r
103 *Buffer = malloc (*Length);\r
104 fseek (in, 0, SEEK_SET);\r
105 fread (*Buffer, *Length, 1, in);\r
106 return STATUS_SUCCESS;\r
107}\r
108\r
109static\r
110STATUS\r
111FWriteFile (\r
112 FILE *out,\r
113 VOID *Buffer,\r
114 UINTN Length\r
115 )\r
116{\r
117 fseek (out, 0, SEEK_SET);\r
118 fwrite (Buffer, Length, 1, out);\r
119 if ((ULONG) ftell (out) != Length) {\r
120 Error (NULL, 0, 0, "write error", NULL);\r
121 return STATUS_ERROR;\r
122 }\r
123 free (Buffer);\r
124 return STATUS_SUCCESS;\r
125}\r
126\r
878ddf1f 127int\r
128main (\r
129 int argc,\r
130 char *argv[]\r
131 )\r
132/*++\r
133\r
134Routine Description:\r
135\r
136 Main function.\r
137\r
138Arguments:\r
139\r
140 argc - Number of command line parameters.\r
141 argv - Array of pointers to command line parameter strings.\r
142\r
143Returns:\r
144 STATUS_SUCCESS - Utility exits successfully.\r
145 STATUS_ERROR - Some error occurred during execution.\r
146\r
147--*/\r
148{\r
149 ULONG Type;\r
150 PUCHAR Ext;\r
151 PUCHAR p;\r
152 PUCHAR pe;\r
153 PUCHAR OutImageName;\r
154 UCHAR outname[500];\r
155 FILE *fpIn;\r
156 FILE *fpOut;\r
3edf127e 157 VOID *ZeroBuffer;\r
158 EFI_IMAGE_DOS_HEADER *DosHdr;\r
159 EFI_IMAGE_NT_HEADERS *PeHdr;\r
160 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;\r
161 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;\r
878ddf1f 162 time_t TimeStamp;\r
163 struct tm TimeStruct;\r
164 EFI_IMAGE_DOS_HEADER BackupDosHdr;\r
165 ULONG Index;\r
3edf127e 166 ULONG Index1;\r
307fd197 167 ULONG Index2;\r
168 ULONG Index3;\r
878ddf1f 169 BOOLEAN TimeStampPresent;\r
0411bcaf 170 UINTN AllignedRelocSize;\r
3edf127e 171 UINTN Delta;\r
172 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
173 UINT8 *FileBuffer;\r
174 UINTN FileLength;\r
307fd197 175 RUNTIME_FUNCTION *RuntimeFunction;\r
176 UNWIND_INFO *UnwindInfo;\r
878ddf1f 177\r
178 SetUtilityName (UTILITY_NAME);\r
179 //\r
180 // Assign to fix compile warning\r
181 //\r
182 OutImageName = NULL;\r
183 Type = 0;\r
184 Ext = 0;\r
185 TimeStamp = 0;\r
186 TimeStampPresent = FALSE;\r
187\r
188 //\r
189 // Look for -t time-date option first. If the time is "0", then\r
190 // skip it.\r
191 //\r
192 if ((argc > 2) && !strcmp (argv[1], "-t")) {\r
193 TimeStampPresent = TRUE;\r
194 if (strcmp (argv[2], "0") != 0) {\r
195 //\r
196 // Convert the string to a value\r
197 //\r
198 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));\r
199 if (sscanf(\r
200 argv[2], "%d/%d/%d,%d:%d:%d",\r
201 &TimeStruct.tm_mon, /* months since January - [0,11] */\r
202 &TimeStruct.tm_mday, /* day of the month - [1,31] */\r
203 &TimeStruct.tm_year, /* years since 1900 */\r
204 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */\r
205 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */\r
206 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */\r
207 ) != 6) {\r
208 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");\r
209 return STATUS_ERROR;\r
210 }\r
211 //\r
212 // Now fixup some of the fields\r
213 //\r
214 TimeStruct.tm_mon--;\r
215 TimeStruct.tm_year -= 1900;\r
216 //\r
217 // Sanity-check values?\r
218 // Convert\r
219 //\r
220 TimeStamp = mktime (&TimeStruct);\r
221 if (TimeStamp == (time_t) - 1) {\r
222 Error (NULL, 0, 0, argv[2], "failed to convert time");\r
223 return STATUS_ERROR;\r
224 }\r
225 }\r
226 //\r
227 // Skip over the args\r
228 //\r
229 argc -= 2;\r
230 argv += 2;\r
231 }\r
232 //\r
233 // Check for enough args\r
234 //\r
235 if (argc < 3) {\r
236 Usage ();\r
237 return STATUS_ERROR;\r
238 }\r
239\r
240 if (argc == 4) {\r
241 OutImageName = argv[3];\r
242 }\r
243 //\r
244 // Get new image type\r
245 //\r
246 p = argv[1];\r
247 if (*p == '/' || *p == '\\') {\r
248 p += 1;\r
249 }\r
250\r
8a286638 251 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {\r
878ddf1f 252 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
253 Ext = ".efi";\r
254\r
8a286638 255 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {\r
878ddf1f 256 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
257 Ext = ".efi";\r
258\r
8a286638 259 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {\r
878ddf1f 260 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;\r
261 Ext = ".efi";\r
262\r
8a286638 263 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {\r
878ddf1f 264 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;\r
265 Ext = ".efi";\r
8a286638 266 } else if (stricmp (p, "SEC") == 0) {\r
878ddf1f 267 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
268 Ext = ".sec";\r
269 } else if (stricmp (p, "peim") == 0 ||\r
8a286638 270 stricmp (p, "BASE") == 0 ||\r
878ddf1f 271 stricmp (p, "PEI_CORE") == 0 ||\r
8a286638 272 stricmp (p, "PEIM") == 0 ||\r
273 stricmp (p, "DXE_SMM_DRIVER") == 0 ||\r
274 stricmp (p, "TOOL") == 0 ||\r
275 stricmp (p, "UEFI_APPLICATION") == 0 ||\r
276 stricmp (p, "USER_DEFINED") == 0 ||\r
277 stricmp (p, "UEFI_DRIVER") == 0 ||\r
278 stricmp (p, "DXE_CORE") == 0\r
878ddf1f 279 ) {\r
280 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
281 Ext = ".pei";\r
282 } else {\r
8a286638 283 printf ("%s", p);\r
878ddf1f 284 Usage ();\r
285 return STATUS_ERROR;\r
286 }\r
287 //\r
288 // open source file\r
289 //\r
290 fpIn = fopen (argv[2], "rb");\r
291 if (!fpIn) {\r
292 Error (NULL, 0, 0, argv[2], "failed to open input file for reading");\r
293 return STATUS_ERROR;\r
294 }\r
3edf127e 295\r
296 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
297\r
878ddf1f 298 //\r
299 // Read the dos & pe hdrs of the image\r
300 //\r
3edf127e 301 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
302 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
878ddf1f 303 Error (NULL, 0, 0, argv[2], "DOS header signature not found in source image");\r
304 fclose (fpIn);\r
305 return STATUS_ERROR;\r
306 }\r
307\r
3edf127e 308 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
309 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
878ddf1f 310 Error (NULL, 0, 0, argv[2], "PE header signature not found in source image");\r
311 fclose (fpIn);\r
312 return STATUS_ERROR;\r
313 }\r
3edf127e 314\r
878ddf1f 315 //\r
316 // open output file\r
317 //\r
318 strcpy (outname, argv[2]);\r
319 pe = NULL;\r
320 for (p = outname; *p; p++) {\r
321 if (*p == '.') {\r
322 pe = p;\r
323 }\r
324 }\r
325\r
326 if (!pe) {\r
327 pe = p;\r
328 }\r
329\r
330 strcpy (pe, Ext);\r
331\r
332 if (!OutImageName) {\r
333 OutImageName = outname;\r
334 }\r
335\r
336 fpOut = fopen (OutImageName, "w+b");\r
337 if (!fpOut) {\r
338 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");\r
339 fclose (fpIn);\r
340 return STATUS_ERROR;\r
341 }\r
3edf127e 342\r
878ddf1f 343 //\r
344 // Zero all unused fields of the DOS header\r
345 //\r
3edf127e 346 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
347 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
348 DosHdr->e_magic = BackupDosHdr.e_magic;\r
349 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
350\r
351 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {\r
352 FileBuffer[Index] = DosHdr->e_cp;\r
878ddf1f 353 }\r
3edf127e 354\r
878ddf1f 355 //\r
356 // Path the PE header\r
357 //\r
3edf127e 358 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
878ddf1f 359 if (TimeStampPresent) {\r
3edf127e 360 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
361 }\r
362\r
3edf127e 363 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
364 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
365 Optional32->MajorLinkerVersion = 0;\r
366 Optional32->MinorLinkerVersion = 0;\r
367 Optional32->MajorOperatingSystemVersion = 0;\r
368 Optional32->MinorOperatingSystemVersion = 0;\r
369 Optional32->MajorImageVersion = 0;\r
370 Optional32->MinorImageVersion = 0;\r
371 Optional32->MajorSubsystemVersion = 0;\r
372 Optional32->MinorSubsystemVersion = 0;\r
373 Optional32->Win32VersionValue = 0;\r
374 Optional32->CheckSum = 0;\r
375 Optional32->SizeOfStackReserve = 0;\r
376 Optional32->SizeOfStackCommit = 0;\r
377 Optional32->SizeOfHeapReserve = 0;\r
378 Optional32->SizeOfHeapCommit = 0;\r
379\r
3edf127e 380 //\r
381 // Strip zero padding at the end of the .reloc section \r
382 //\r
383 if (Optional32->NumberOfRvaAndSizes >= 6) {\r
384 if (Optional32->DataDirectory[5].Size != 0) {\r
385 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
386 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 387 //\r
388 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
389 //\r
3edf127e 390 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
0411bcaf 391 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;\r
392 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));\r
393 //\r
394 // Check to see if there is zero padding at the end of the base relocations\r
395 //\r
396 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
397 //\r
398 // Check to see if the base relocations are at the end of the file\r
399 //\r
400 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {\r
401 //\r
402 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
403 //\r
404 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
405 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
406 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
407 FileLength = Optional32->SizeOfImage;\r
408 }\r
409 }\r
3edf127e 410 }\r
411 }\r
412 }\r
413 }\r
414 } \r
415 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
416 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
417 Optional64->MajorLinkerVersion = 0;\r
418 Optional64->MinorLinkerVersion = 0;\r
419 Optional64->MajorOperatingSystemVersion = 0;\r
420 Optional64->MinorOperatingSystemVersion = 0;\r
421 Optional64->MajorImageVersion = 0;\r
422 Optional64->MinorImageVersion = 0;\r
423 Optional64->MajorSubsystemVersion = 0;\r
424 Optional64->MinorSubsystemVersion = 0;\r
425 Optional64->Win32VersionValue = 0;\r
426 Optional64->CheckSum = 0;\r
427 Optional64->SizeOfStackReserve = 0;\r
428 Optional64->SizeOfStackCommit = 0;\r
429 Optional64->SizeOfHeapReserve = 0;\r
430 Optional64->SizeOfHeapCommit = 0;\r
431\r
432 //\r
433 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
434 //\r
435 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
436 if (Optional64->NumberOfRvaAndSizes >= 4) {\r
437 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
438 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
439 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
440 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
307fd197 441 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);\r
442 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {\r
443 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
444 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {\r
445 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {\r
446 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));\r
447 if (UnwindInfo->Version == 1) {\r
448 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));\r
449 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));\r
450 }\r
451 }\r
452 }\r
453 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));\r
3edf127e 454 }\r
455 }\r
456 }\r
457 Optional64->DataDirectory[3].Size = 0;\r
458 Optional64->DataDirectory[3].VirtualAddress = 0;\r
459 }\r
460 }\r
461 }\r
462\r
463 //\r
464 // Strip zero padding at the end of the .reloc section \r
465 //\r
466 if (Optional64->NumberOfRvaAndSizes >= 6) {\r
467 if (Optional64->DataDirectory[5].Size != 0) {\r
468 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
469 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 470 //\r
471 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
472 //\r
3edf127e 473 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
0411bcaf 474 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;\r
475 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));\r
476 //\r
477 // Check to see if there is zero padding at the end of the base relocations\r
478 //\r
479 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
480 //\r
481 // Check to see if the base relocations are at the end of the file\r
482 //\r
483 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {\r
484 //\r
485 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
486 //\r
487 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
488 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
489 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
490 FileLength = Optional64->SizeOfImage;\r
491 }\r
492 }\r
3edf127e 493 }\r
494 }\r
495 }\r
496 }\r
497 }\r
498\r
3edf127e 499 FWriteFile (fpOut, FileBuffer, FileLength);\r
878ddf1f 500\r
501 //\r
502 // Done\r
503 //\r
504 fclose (fpIn);\r
505 fclose (fpOut);\r
506 //\r
507 // printf ("Created %s\n", OutImageName);\r
508 //\r
509 return STATUS_SUCCESS;\r
510}\r