Add EntryPointLib class once ImageEntryPoint is found in inf file.
[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
3edf127e 168 UINTN RelocSize;\r
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
359 RelocSize = 0;\r
360 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
361 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
362 Optional32->MajorLinkerVersion = 0;\r
363 Optional32->MinorLinkerVersion = 0;\r
364 Optional32->MajorOperatingSystemVersion = 0;\r
365 Optional32->MinorOperatingSystemVersion = 0;\r
366 Optional32->MajorImageVersion = 0;\r
367 Optional32->MinorImageVersion = 0;\r
368 Optional32->MajorSubsystemVersion = 0;\r
369 Optional32->MinorSubsystemVersion = 0;\r
370 Optional32->Win32VersionValue = 0;\r
371 Optional32->CheckSum = 0;\r
372 Optional32->SizeOfStackReserve = 0;\r
373 Optional32->SizeOfStackCommit = 0;\r
374 Optional32->SizeOfHeapReserve = 0;\r
375 Optional32->SizeOfHeapCommit = 0;\r
376\r
377 //\r
378 // Zero the .pdata section if the machine type is X64 and the Debug Directoty entry is empty\r
379 //\r
380 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
381 if (Optional32->NumberOfRvaAndSizes >= 4) {\r
382 if (Optional32->NumberOfRvaAndSizes < 7 || (Optional32->NumberOfRvaAndSizes >= 7 && Optional32->DataDirectory[6].Size == 0)) {\r
383 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
384 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
385 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[3].VirtualAddress) {\r
386 for (Index1 = 0; Index1 < Optional32->DataDirectory[3].Size; Index1++) {\r
387 FileBuffer[SectionHeader->PointerToRawData + Index1] = 0;\r
388 }\r
389 }\r
390 }\r
391 Optional32->DataDirectory[3].Size = 0;\r
392 Optional32->DataDirectory[3].VirtualAddress = 0;\r
393 }\r
394 }\r
395 }\r
396\r
397 //\r
398 // Strip zero padding at the end of the .reloc section \r
399 //\r
400 if (Optional32->NumberOfRvaAndSizes >= 6) {\r
401 if (Optional32->DataDirectory[5].Size != 0) {\r
402 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
403 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
404 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
405 FileLength = SectionHeader->PointerToRawData + Optional32->DataDirectory[5].Size;\r
406 FileLength = (FileLength + 7) & 0xfffffff8;\r
407 RelocSize = FileLength - SectionHeader->PointerToRawData;\r
408 }\r
409 }\r
410 }\r
411 }\r
412 } \r
413 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
414 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
415 Optional64->MajorLinkerVersion = 0;\r
416 Optional64->MinorLinkerVersion = 0;\r
417 Optional64->MajorOperatingSystemVersion = 0;\r
418 Optional64->MinorOperatingSystemVersion = 0;\r
419 Optional64->MajorImageVersion = 0;\r
420 Optional64->MinorImageVersion = 0;\r
421 Optional64->MajorSubsystemVersion = 0;\r
422 Optional64->MinorSubsystemVersion = 0;\r
423 Optional64->Win32VersionValue = 0;\r
424 Optional64->CheckSum = 0;\r
425 Optional64->SizeOfStackReserve = 0;\r
426 Optional64->SizeOfStackCommit = 0;\r
427 Optional64->SizeOfHeapReserve = 0;\r
428 Optional64->SizeOfHeapCommit = 0;\r
429\r
430 //\r
431 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
432 //\r
433 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
434 if (Optional64->NumberOfRvaAndSizes >= 4) {\r
435 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
436 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
437 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
438 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
439 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size; Index1++) {\r
440 FileBuffer[SectionHeader->PointerToRawData + Index1] = 0;\r
441 }\r
442 }\r
443 }\r
444 Optional64->DataDirectory[3].Size = 0;\r
445 Optional64->DataDirectory[3].VirtualAddress = 0;\r
446 }\r
447 }\r
448 }\r
449\r
450 //\r
451 // Strip zero padding at the end of the .reloc section \r
452 //\r
453 if (Optional64->NumberOfRvaAndSizes >= 6) {\r
454 if (Optional64->DataDirectory[5].Size != 0) {\r
455 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
456 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
457 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
458 FileLength = SectionHeader->PointerToRawData + Optional64->DataDirectory[5].Size;\r
459 FileLength = (FileLength + 7) & 0xfffffff8;\r
460 RelocSize = FileLength - SectionHeader->PointerToRawData;\r
461 }\r
462 }\r
463 }\r
464 }\r
465 }\r
466\r
467 if (RelocSize != 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
470 if (strcmp(SectionHeader->Name, ".reloc") == 0) {\r
471 SectionHeader->Misc.VirtualSize = (RelocSize + 0x1f) & 0xffffffe0;\r
472 SectionHeader->SizeOfRawData = RelocSize;\r
473 }\r
474 }\r
878ddf1f 475 }\r
476\r
3edf127e 477 FWriteFile (fpOut, FileBuffer, FileLength);\r
878ddf1f 478\r
479 //\r
480 // Done\r
481 //\r
482 fclose (fpIn);\r
483 fclose (fpOut);\r
484 //\r
485 // printf ("Created %s\n", OutImageName);\r
486 //\r
487 return STATUS_SUCCESS;\r
488}\r