]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/CCode/Source/FwImage/fwimage.c
0f231488a3482ddffeaa68200ae4dc96840a5297
[mirror_edk2.git] / Tools / CCode / Source / 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 //
39 // Version of this utility
40 //
41 #define UTILITY_NAME "FwImage"
42 #define UTILITY_MAJOR_VERSION 1
43 #define UTILITY_MINOR_VERSION 0
44
45 #ifdef __GNUC__
46 typedef unsigned long ULONG;
47 typedef unsigned char UCHAR;
48 typedef unsigned char *PUCHAR;
49 typedef unsigned short USHORT;
50 #endif
51
52 static
53 void
54 Version (
55 VOID
56 )
57 {
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");
60 }
61
62
63 VOID
64 Usage (
65 VOID
66 )
67 {
68 Version();
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]");
73 }
74
75 static
76 STATUS
77 FCopyFile (
78 FILE *in,
79 FILE *out
80 )
81 {
82 ULONG filesize;
83 ULONG offset;
84 ULONG length;
85 UCHAR Buffer[8 * 1024];
86
87 fseek (in, 0, SEEK_END);
88 filesize = ftell (in);
89
90 fseek (in, 0, SEEK_SET);
91 fseek (out, 0, SEEK_SET);
92
93 offset = 0;
94 while (offset < filesize) {
95 length = sizeof (Buffer);
96 if (filesize - offset < length) {
97 length = filesize - offset;
98 }
99
100 fread (Buffer, length, 1, in);
101 fwrite (Buffer, length, 1, out);
102 offset += length;
103 }
104
105 if ((ULONG) ftell (out) != filesize) {
106 Error (NULL, 0, 0, "write error", NULL);
107 return STATUS_ERROR;
108 }
109
110 return STATUS_SUCCESS;
111 }
112
113 static
114 STATUS
115 FReadFile (
116 FILE *in,
117 VOID **Buffer,
118 UINTN *Length
119 )
120 {
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;
127 }
128
129 static
130 STATUS
131 FWriteFile (
132 FILE *out,
133 VOID *Buffer,
134 UINTN Length
135 )
136 {
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);
141 return STATUS_ERROR;
142 }
143 free (Buffer);
144 return STATUS_SUCCESS;
145 }
146
147 int
148 main (
149 int argc,
150 char *argv[]
151 )
152 /*++
153
154 Routine Description:
155
156 Main function.
157
158 Arguments:
159
160 argc - Number of command line parameters.
161 argv - Array of pointers to command line parameter strings.
162
163 Returns:
164 STATUS_SUCCESS - Utility exits successfully.
165 STATUS_ERROR - Some error occurred during execution.
166
167 --*/
168 {
169 ULONG Type;
170 PUCHAR Ext;
171 PUCHAR p;
172 PUCHAR pe;
173 PUCHAR OutImageName;
174 UCHAR outname[500];
175 FILE *fpIn;
176 FILE *fpOut;
177 VOID *ZeroBuffer;
178 EFI_IMAGE_DOS_HEADER *DosHdr;
179 EFI_IMAGE_NT_HEADERS *PeHdr;
180 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
181 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
182 time_t TimeStamp;
183 struct tm TimeStruct;
184 EFI_IMAGE_DOS_HEADER BackupDosHdr;
185 ULONG Index;
186 ULONG Index1;
187 ULONG Index2;
188 ULONG Index3;
189 BOOLEAN TimeStampPresent;
190 UINTN AllignedRelocSize;
191 UINTN Delta;
192 EFI_IMAGE_SECTION_HEADER *SectionHeader;
193 UINT8 *FileBuffer;
194 UINTN FileLength;
195 RUNTIME_FUNCTION *RuntimeFunction;
196 UNWIND_INFO *UnwindInfo;
197
198 SetUtilityName (UTILITY_NAME);
199 //
200 // Assign to fix compile warning
201 //
202 OutImageName = NULL;
203 Type = 0;
204 Ext = 0;
205 TimeStamp = 0;
206 TimeStampPresent = FALSE;
207
208 if (argc < 1) {
209 Usage();
210 return STATUS_ERROR;
211 }
212
213 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
214 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
215 Usage();
216 return STATUS_ERROR;
217 }
218
219 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
220 Version();
221 return STATUS_ERROR;
222 }
223
224 //
225 // Look for -t time-date option first. If the time is "0", then
226 // skip it.
227 //
228 if ((argc > 2) && !strcmp (argv[1], "-t")) {
229 TimeStampPresent = TRUE;
230 if (strcmp (argv[2], "0") != 0) {
231 //
232 // Convert the string to a value
233 //
234 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));
235 if (sscanf(
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] */
243 ) != 6) {
244 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
245 return STATUS_ERROR;
246 }
247 //
248 // Now fixup some of the fields
249 //
250 TimeStruct.tm_mon--;
251 TimeStruct.tm_year -= 1900;
252 //
253 // Sanity-check values?
254 // Convert
255 //
256 TimeStamp = mktime (&TimeStruct);
257 if (TimeStamp == (time_t) - 1) {
258 Error (NULL, 0, 0, argv[2], "failed to convert time");
259 return STATUS_ERROR;
260 }
261 }
262 //
263 // Skip over the args
264 //
265 argc -= 2;
266 argv += 2;
267 }
268 //
269 // Check for enough args
270 //
271 if (argc < 3) {
272 Usage ();
273 return STATUS_ERROR;
274 }
275
276 if (argc == 4) {
277 OutImageName = argv[3];
278 }
279 //
280 // Get new image type
281 //
282 p = argv[1];
283 if (*p == '/' || *p == '\\') {
284 p += 1;
285 }
286
287 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {
288 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
289 Ext = ".efi";
290
291 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {
292 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
293 Ext = ".efi";
294
295 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {
296 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
297 Ext = ".efi";
298
299 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {
300 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
301 Ext = ".efi";
302 } else if (stricmp (p, "SEC") == 0) {
303 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
304 Ext = ".sec";
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
315 ) {
316 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
317 Ext = ".pei";
318 } else {
319 printf ("%s", p);
320 Usage ();
321 return STATUS_ERROR;
322 }
323 //
324 // open source file
325 //
326 fpIn = fopen (argv[2], "rb");
327 if (!fpIn) {
328 Error (NULL, 0, 0, argv[2], "failed to open input file for reading");
329 return STATUS_ERROR;
330 }
331
332 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);
333
334 //
335 // Read the dos & pe hdrs of the image
336 //
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");
340 fclose (fpIn);
341 return STATUS_ERROR;
342 }
343
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");
347 fclose (fpIn);
348 return STATUS_ERROR;
349 }
350
351 //
352 // open output file
353 //
354 strcpy (outname, argv[2]);
355 pe = NULL;
356 for (p = outname; *p; p++) {
357 if (*p == '.') {
358 pe = p;
359 }
360 }
361
362 if (!pe) {
363 pe = p;
364 }
365
366 strcpy (pe, Ext);
367
368 if (!OutImageName) {
369 OutImageName = outname;
370 }
371
372 fpOut = fopen (OutImageName, "w+b");
373 if (!fpOut) {
374 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");
375 fclose (fpIn);
376 return STATUS_ERROR;
377 }
378
379 //
380 // Zero all unused fields of the DOS header
381 //
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;
386
387 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {
388 FileBuffer[Index] = DosHdr->e_cp;
389 }
390
391 //
392 // Path the PE header
393 //
394 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;
395 if (TimeStampPresent) {
396 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;
397 }
398
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;
415
416 //
417 // Strip zero padding at the end of the .reloc section
418 //
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++) {
423 //
424 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
425 //
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));
429 //
430 // Check to see if there is zero padding at the end of the base relocations
431 //
432 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
433 //
434 // Check to see if the base relocations are at the end of the file
435 //
436 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
437 //
438 // All the required conditions are met to strip the zero padding of the end of the base relocations section
439 //
440 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
441 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
442 SectionHeader->SizeOfRawData = AllignedRelocSize;
443 FileLength = Optional32->SizeOfImage;
444 }
445 }
446 }
447 }
448 }
449 }
450 }
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;
467
468 //
469 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
470 //
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));
486 }
487 }
488 }
489 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));
490 }
491
492 break;
493 }
494 }
495 Optional64->DataDirectory[3].Size = 0;
496 Optional64->DataDirectory[3].VirtualAddress = 0;
497 }
498 }
499 }
500
501 //
502 // Strip zero padding at the end of the .reloc section
503 //
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++) {
508 //
509 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
510 //
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));
514 //
515 // Check to see if there is zero padding at the end of the base relocations
516 //
517 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
518 //
519 // Check to see if the base relocations are at the end of the file
520 //
521 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
522 //
523 // All the required conditions are met to strip the zero padding of the end of the base relocations section
524 //
525 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
526 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
527 SectionHeader->SizeOfRawData = AllignedRelocSize;
528 FileLength = Optional64->SizeOfImage;
529 }
530 }
531 }
532 }
533 }
534 }
535 }
536
537 FWriteFile (fpOut, FileBuffer, FileLength);
538
539 //
540 // Done
541 //
542 fclose (fpIn);
543 fclose (fpOut);
544 //
545 // printf ("Created %s\n", OutImageName);
546 //
547 return STATUS_SUCCESS;
548 }