]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/Source/TianoTools/FwImage/fwimage.c
Fixed FwImage/fwimage.c to guarantee that the raw size of a section is a multiple...
[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
878ddf1f 167 BOOLEAN TimeStampPresent;\r
0411bcaf 168 UINTN AllignedRelocSize;\r
3edf127e 169 UINTN Delta;\r
170 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
171 UINT8 *FileBuffer;\r
172 UINTN FileLength;\r
878ddf1f 173\r
174 SetUtilityName (UTILITY_NAME);\r
175 //\r
176 // Assign to fix compile warning\r
177 //\r
178 OutImageName = NULL;\r
179 Type = 0;\r
180 Ext = 0;\r
181 TimeStamp = 0;\r
182 TimeStampPresent = FALSE;\r
183\r
184 //\r
185 // Look for -t time-date option first. If the time is "0", then\r
186 // skip it.\r
187 //\r
188 if ((argc > 2) && !strcmp (argv[1], "-t")) {\r
189 TimeStampPresent = TRUE;\r
190 if (strcmp (argv[2], "0") != 0) {\r
191 //\r
192 // Convert the string to a value\r
193 //\r
194 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));\r
195 if (sscanf(\r
196 argv[2], "%d/%d/%d,%d:%d:%d",\r
197 &TimeStruct.tm_mon, /* months since January - [0,11] */\r
198 &TimeStruct.tm_mday, /* day of the month - [1,31] */\r
199 &TimeStruct.tm_year, /* years since 1900 */\r
200 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */\r
201 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */\r
202 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */\r
203 ) != 6) {\r
204 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");\r
205 return STATUS_ERROR;\r
206 }\r
207 //\r
208 // Now fixup some of the fields\r
209 //\r
210 TimeStruct.tm_mon--;\r
211 TimeStruct.tm_year -= 1900;\r
212 //\r
213 // Sanity-check values?\r
214 // Convert\r
215 //\r
216 TimeStamp = mktime (&TimeStruct);\r
217 if (TimeStamp == (time_t) - 1) {\r
218 Error (NULL, 0, 0, argv[2], "failed to convert time");\r
219 return STATUS_ERROR;\r
220 }\r
221 }\r
222 //\r
223 // Skip over the args\r
224 //\r
225 argc -= 2;\r
226 argv += 2;\r
227 }\r
228 //\r
229 // Check for enough args\r
230 //\r
231 if (argc < 3) {\r
232 Usage ();\r
233 return STATUS_ERROR;\r
234 }\r
235\r
236 if (argc == 4) {\r
237 OutImageName = argv[3];\r
238 }\r
239 //\r
240 // Get new image type\r
241 //\r
242 p = argv[1];\r
243 if (*p == '/' || *p == '\\') {\r
244 p += 1;\r
245 }\r
246\r
8a286638 247 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {\r
878ddf1f 248 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
249 Ext = ".efi";\r
250\r
8a286638 251 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {\r
878ddf1f 252 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
253 Ext = ".efi";\r
254\r
8a286638 255 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {\r
878ddf1f 256 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;\r
257 Ext = ".efi";\r
258\r
8a286638 259 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {\r
878ddf1f 260 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;\r
261 Ext = ".efi";\r
8a286638 262 } else if (stricmp (p, "SEC") == 0) {\r
878ddf1f 263 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
264 Ext = ".sec";\r
265 } else if (stricmp (p, "peim") == 0 ||\r
8a286638 266 stricmp (p, "BASE") == 0 ||\r
878ddf1f 267 stricmp (p, "PEI_CORE") == 0 ||\r
8a286638 268 stricmp (p, "PEIM") == 0 ||\r
269 stricmp (p, "DXE_SMM_DRIVER") == 0 ||\r
270 stricmp (p, "TOOL") == 0 ||\r
271 stricmp (p, "UEFI_APPLICATION") == 0 ||\r
272 stricmp (p, "USER_DEFINED") == 0 ||\r
273 stricmp (p, "UEFI_DRIVER") == 0 ||\r
274 stricmp (p, "DXE_CORE") == 0\r
878ddf1f 275 ) {\r
276 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
277 Ext = ".pei";\r
278 } else {\r
8a286638 279 printf ("%s", p);\r
878ddf1f 280 Usage ();\r
281 return STATUS_ERROR;\r
282 }\r
283 //\r
284 // open source file\r
285 //\r
286 fpIn = fopen (argv[2], "rb");\r
287 if (!fpIn) {\r
288 Error (NULL, 0, 0, argv[2], "failed to open input file for reading");\r
289 return STATUS_ERROR;\r
290 }\r
3edf127e 291\r
292 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
293\r
878ddf1f 294 //\r
295 // Read the dos & pe hdrs of the image\r
296 //\r
3edf127e 297 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
298 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
878ddf1f 299 Error (NULL, 0, 0, argv[2], "DOS header signature not found in source image");\r
300 fclose (fpIn);\r
301 return STATUS_ERROR;\r
302 }\r
303\r
3edf127e 304 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
305 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
878ddf1f 306 Error (NULL, 0, 0, argv[2], "PE header signature not found in source image");\r
307 fclose (fpIn);\r
308 return STATUS_ERROR;\r
309 }\r
3edf127e 310\r
878ddf1f 311 //\r
312 // open output file\r
313 //\r
314 strcpy (outname, argv[2]);\r
315 pe = NULL;\r
316 for (p = outname; *p; p++) {\r
317 if (*p == '.') {\r
318 pe = p;\r
319 }\r
320 }\r
321\r
322 if (!pe) {\r
323 pe = p;\r
324 }\r
325\r
326 strcpy (pe, Ext);\r
327\r
328 if (!OutImageName) {\r
329 OutImageName = outname;\r
330 }\r
331\r
332 fpOut = fopen (OutImageName, "w+b");\r
333 if (!fpOut) {\r
334 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");\r
335 fclose (fpIn);\r
336 return STATUS_ERROR;\r
337 }\r
3edf127e 338\r
878ddf1f 339 //\r
340 // Zero all unused fields of the DOS header\r
341 //\r
3edf127e 342 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
343 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
344 DosHdr->e_magic = BackupDosHdr.e_magic;\r
345 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
346\r
347 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {\r
348 FileBuffer[Index] = DosHdr->e_cp;\r
878ddf1f 349 }\r
3edf127e 350\r
878ddf1f 351 //\r
352 // Path the PE header\r
353 //\r
3edf127e 354 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
878ddf1f 355 if (TimeStampPresent) {\r
3edf127e 356 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
357 }\r
358\r
3edf127e 359 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
360 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
361 Optional32->MajorLinkerVersion = 0;\r
362 Optional32->MinorLinkerVersion = 0;\r
363 Optional32->MajorOperatingSystemVersion = 0;\r
364 Optional32->MinorOperatingSystemVersion = 0;\r
365 Optional32->MajorImageVersion = 0;\r
366 Optional32->MinorImageVersion = 0;\r
367 Optional32->MajorSubsystemVersion = 0;\r
368 Optional32->MinorSubsystemVersion = 0;\r
369 Optional32->Win32VersionValue = 0;\r
370 Optional32->CheckSum = 0;\r
371 Optional32->SizeOfStackReserve = 0;\r
372 Optional32->SizeOfStackCommit = 0;\r
373 Optional32->SizeOfHeapReserve = 0;\r
374 Optional32->SizeOfHeapCommit = 0;\r
375\r
376 //\r
377 // Zero the .pdata section if the machine type is X64 and the Debug Directoty entry is empty\r
378 //\r
379 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
380 if (Optional32->NumberOfRvaAndSizes >= 4) {\r
381 if (Optional32->NumberOfRvaAndSizes < 7 || (Optional32->NumberOfRvaAndSizes >= 7 && Optional32->DataDirectory[6].Size == 0)) {\r
382 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
383 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
384 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[3].VirtualAddress) {\r
385 for (Index1 = 0; Index1 < Optional32->DataDirectory[3].Size; Index1++) {\r
386 FileBuffer[SectionHeader->PointerToRawData + Index1] = 0;\r
387 }\r
388 }\r
389 }\r
390 Optional32->DataDirectory[3].Size = 0;\r
391 Optional32->DataDirectory[3].VirtualAddress = 0;\r
392 }\r
393 }\r
394 }\r
395\r
396 //\r
397 // Strip zero padding at the end of the .reloc section \r
398 //\r
399 if (Optional32->NumberOfRvaAndSizes >= 6) {\r
400 if (Optional32->DataDirectory[5].Size != 0) {\r
401 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
402 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 403 //\r
404 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
405 //\r
3edf127e 406 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
0411bcaf 407 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;\r
408 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));\r
409 //\r
410 // Check to see if there is zero padding at the end of the base relocations\r
411 //\r
412 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
413 //\r
414 // Check to see if the base relocations are at the end of the file\r
415 //\r
416 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {\r
417 //\r
418 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
419 //\r
420 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
421 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
422 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
423 FileLength = Optional32->SizeOfImage;\r
424 }\r
425 }\r
3edf127e 426 }\r
427 }\r
428 }\r
429 }\r
430 } \r
431 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
432 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
433 Optional64->MajorLinkerVersion = 0;\r
434 Optional64->MinorLinkerVersion = 0;\r
435 Optional64->MajorOperatingSystemVersion = 0;\r
436 Optional64->MinorOperatingSystemVersion = 0;\r
437 Optional64->MajorImageVersion = 0;\r
438 Optional64->MinorImageVersion = 0;\r
439 Optional64->MajorSubsystemVersion = 0;\r
440 Optional64->MinorSubsystemVersion = 0;\r
441 Optional64->Win32VersionValue = 0;\r
442 Optional64->CheckSum = 0;\r
443 Optional64->SizeOfStackReserve = 0;\r
444 Optional64->SizeOfStackCommit = 0;\r
445 Optional64->SizeOfHeapReserve = 0;\r
446 Optional64->SizeOfHeapCommit = 0;\r
447\r
448 //\r
449 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
450 //\r
451 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
452 if (Optional64->NumberOfRvaAndSizes >= 4) {\r
453 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
454 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
455 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
456 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
457 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size; Index1++) {\r
458 FileBuffer[SectionHeader->PointerToRawData + Index1] = 0;\r
459 }\r
460 }\r
461 }\r
462 Optional64->DataDirectory[3].Size = 0;\r
463 Optional64->DataDirectory[3].VirtualAddress = 0;\r
464 }\r
465 }\r
466 }\r
467\r
468 //\r
469 // Strip zero padding at the end of the .reloc section \r
470 //\r
471 if (Optional64->NumberOfRvaAndSizes >= 6) {\r
472 if (Optional64->DataDirectory[5].Size != 0) {\r
473 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
474 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 475 //\r
476 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
477 //\r
3edf127e 478 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
0411bcaf 479 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;\r
480 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));\r
481 //\r
482 // Check to see if there is zero padding at the end of the base relocations\r
483 //\r
484 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
485 //\r
486 // Check to see if the base relocations are at the end of the file\r
487 //\r
488 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {\r
489 //\r
490 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
491 //\r
492 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
493 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
494 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
495 FileLength = Optional64->SizeOfImage;\r
496 }\r
497 }\r
3edf127e 498 }\r
499 }\r
500 }\r
501 }\r
502 }\r
503\r
3edf127e 504 FWriteFile (fpOut, FileBuffer, FileLength);\r
878ddf1f 505\r
506 //\r
507 // Done\r
508 //\r
509 fclose (fpIn);\r
510 fclose (fpOut);\r
511 //\r
512 // printf ("Created %s\n", OutImageName);\r
513 //\r
514 return STATUS_SUCCESS;\r
515}\r