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