]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/GenTEImage/GenTEImage.c
Correct TeImage file format and Clean up PeiRebase tool to remove unused code and...
[mirror_edk2.git] / Tools / CCode / Source / GenTEImage / GenTEImage.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 1999-2006 Intel Corporation. All rights reserved\r
4This program and the accompanying materials are licensed and made available \r
5under the terms and conditions of the BSD License which accompanies this \r
6distribution. 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
d25c4bf0 11\r
12Module Name:\r
13\r
14 GenTEImage.c\r
15 \r
16Abstract:\r
17\r
18 Utility program to shrink a PE32 image down by replacing\r
19 the DOS, PE, and optional headers with a minimal header.\r
20\r
21--*/\r
22\r
23#include <stdio.h>\r
24#include <string.h>\r
25#include <stdlib.h>\r
26\r
ce53a8c3 27#include <Common/UefiBaseTypes.h>\r
28#include <Common/EfiImage.h> // for PE32 structure definitions\r
51d48c26 29\r
ce53a8c3 30#include "CommonLib.h"\r
d25c4bf0 31#include "EfiUtilityMsgs.h"\r
32\r
33//\r
34// Version of this utility\r
35//\r
36#define UTILITY_NAME "GenTEImage"\r
db608e6b 37#define UTILITY_MAJOR_VERSION 0\r
38#define UTILITY_MINOR_VERSION 11\r
d25c4bf0 39\r
40//\r
41// Define the max length of a filename\r
42//\r
43#define MAX_PATH 256\r
44#define DEFAULT_OUTPUT_EXTENSION ".te"\r
45\r
46//\r
47// Use this to track our command-line options and globals\r
48//\r
49struct {\r
50 INT8 OutFileName[MAX_PATH];\r
51 INT8 InFileName[MAX_PATH];\r
52 INT8 Verbose;\r
53 INT8 Dump;\r
54} mOptions;\r
55\r
56//\r
57// Use these to convert from machine type value to a named type\r
58//\r
59typedef struct {\r
60 UINT16 Value;\r
61 INT8 *Name;\r
62} STRING_LOOKUP;\r
63\r
64static STRING_LOOKUP mMachineTypes[] = {\r
65 EFI_IMAGE_MACHINE_IA32,\r
66 "IA32",\r
67 EFI_IMAGE_MACHINE_IA64,\r
68 "IA64",\r
69 EFI_IMAGE_MACHINE_EBC,\r
70 "EBC",\r
71 0,\r
72 NULL\r
73};\r
74\r
75static STRING_LOOKUP mSubsystemTypes[] = {\r
76 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,\r
77 "EFI application",\r
78 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,\r
79 "EFI boot service driver",\r
80 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,\r
81 "EFI runtime driver",\r
82 0,\r
83 NULL\r
84};\r
85//\r
86// Function prototypes\r
87//\r
db608e6b 88static\r
89void\r
90Version (\r
91 VOID\r
92 );\r
93\r
d25c4bf0 94static\r
95void\r
96Usage (\r
97 VOID\r
98 );\r
99\r
100static\r
101STATUS\r
102ParseCommandLine (\r
103 int Argc,\r
104 char *Argv[]\r
105 );\r
106\r
107static\r
108STATUS\r
109CheckPE32File (\r
110 INT8 *FileName,\r
111 FILE *Fptr,\r
112 UINT16 *MachineType,\r
113 UINT16 *SubSystem\r
114 );\r
115\r
116static\r
117STATUS\r
118ProcessFile (\r
119 INT8 *InFileName,\r
120 INT8 *OutFileName\r
121 );\r
122\r
123static\r
124void\r
125DumpImage (\r
126 INT8 *FileName\r
127 );\r
128\r
129static\r
130INT8 *\r
131GetMachineTypeStr (\r
132 UINT16 MachineType\r
133 );\r
134\r
135static\r
136INT8 *\r
137GetSubsystemTypeStr (\r
138 UINT16 SubsystemType\r
139 );\r
140\r
141main (\r
142 int Argc,\r
143 char *Argv[]\r
144 )\r
145/*++\r
146\r
147Routine Description:\r
148 \r
149\r
150Arguments:\r
151\r
152 Argc - standard C main() argument count\r
153\r
154 Argv - standard C main() argument list\r
155\r
156Returns:\r
157\r
158 0 success\r
159 non-zero otherwise\r
160\r
161--*/\r
162// GC_TODO: ] - add argument and description to function comment\r
163{\r
164 INT8 *Ext;\r
165 UINT32 Status;\r
166\r
167 SetUtilityName (UTILITY_NAME);\r
168 //\r
169 // Parse the command line arguments\r
170 //\r
171 if (ParseCommandLine (Argc, Argv)) {\r
172 return STATUS_ERROR;\r
173 }\r
174 //\r
175 // If dumping an image, then do that and quit\r
176 //\r
177 if (mOptions.Dump) {\r
178 DumpImage (mOptions.InFileName);\r
179 goto Finish;\r
180 }\r
181 //\r
182 // Determine the output filename. Either what they specified on\r
183 // the command line, or the first input filename with a different extension.\r
184 //\r
185 if (!mOptions.OutFileName[0]) {\r
186 strcpy (mOptions.OutFileName, mOptions.InFileName);\r
187 //\r
188 // Find the last . on the line and replace the filename extension with\r
189 // the default\r
190 //\r
191 for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
192 (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');\r
193 Ext--\r
194 )\r
195 ;\r
196 //\r
197 // If dot here, then insert extension here, otherwise append\r
198 //\r
199 if (*Ext != '.') {\r
200 Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
201 }\r
202\r
203 strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
204 }\r
205 //\r
206 // Make sure we don't have the same filename for input and output files\r
207 //\r
208 if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) {\r
209 Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different");\r
210 goto Finish;\r
211 }\r
212 //\r
213 // Process the file\r
214 //\r
215 ProcessFile (mOptions.InFileName, mOptions.OutFileName);\r
216Finish:\r
217 Status = GetUtilityStatus ();\r
218 return Status;\r
219}\r
220\r
221static\r
222STATUS\r
223ProcessFile (\r
224 INT8 *InFileName,\r
225 INT8 *OutFileName\r
226 )\r
227/*++\r
228\r
229Routine Description:\r
230 \r
231 Process a PE32 EFI file.\r
232\r
233Arguments:\r
234 \r
235 InFileName - the file name pointer to the input file\r
236 OutFileName - the file name pointer to the output file\r
237\r
238Returns:\r
239\r
240 STATUS_SUCCESS - the process has been finished successfully\r
241 STATUS_ERROR - error occured during the processing\r
242\r
243--*/\r
244{\r
245 STATUS Status;\r
246 FILE *InFptr;\r
247 FILE *OutFptr;\r
248 UINT16 MachineType;\r
249 UINT16 SubSystem;\r
250 EFI_TE_IMAGE_HEADER TEImageHeader;\r
251 UINT32 PESigOffset;\r
252 EFI_IMAGE_FILE_HEADER FileHeader;\r
253 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32;\r
254 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64;\r
255 UINT32 BytesStripped;\r
256 UINT32 FileSize;\r
257 UINT8 *Buffer;\r
258 long SaveFilePosition;\r
259\r
260 InFptr = NULL;\r
261 OutFptr = NULL;\r
262 Buffer = NULL;\r
263 Status = STATUS_ERROR;\r
264\r
265 //\r
266 // Try to open the input file\r
267 //\r
268 if ((InFptr = fopen (InFileName, "rb")) == NULL) {\r
269 Error (NULL, 0, 0, InFileName, "failed to open input file for reading");\r
270 return STATUS_ERROR;\r
271 }\r
272 //\r
273 // Double-check the file to make sure it's what we expect it to be\r
274 //\r
5b664244 275\r
d25c4bf0 276 if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) {\r
277 goto Finish;\r
278 }\r
279 //\r
280 // Initialize our new header\r
281 //\r
282 memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER));\r
283\r
284 //\r
285 // Seek to the end to get the file size\r
286 //\r
287 fseek (InFptr, 0, SEEK_END);\r
288 FileSize = ftell (InFptr);\r
289 fseek (InFptr, 0, SEEK_SET);\r
290\r
291 //\r
292 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit\r
293 // offset (from the start of the file) to the PE signature, which always\r
294 // follows the MSDOS stub. The PE signature is immediately followed by the\r
295 // COFF file header.\r
296 //\r
297 //\r
298 if (fseek (InFptr, 0x3C, SEEK_SET) != 0) {\r
299 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL);\r
300 goto Finish;\r
301 }\r
302\r
303 if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) {\r
304 Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file");\r
305 goto Finish;\r
306 }\r
307\r
308 if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) {\r
309 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature");\r
310 goto Finish;\r
311 }\r
312 //\r
313 // We should now be at the COFF file header. Read it in and verify it's\r
314 // of an image type we support.\r
315 //\r
316 if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) {\r
317 Error (NULL, 0, 0, InFileName, "failed to read file header from image");\r
318 goto Finish;\r
319 }\r
320\r
321 if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64)) {\r
322 Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine);\r
323 goto Finish;\r
324 }\r
325 //\r
326 // Calculate the total number of bytes we're going to strip off. The '4' is for the\r
327 // PE signature PE\0\0. Then sanity check the size.\r
328 //\r
329 BytesStripped = PESigOffset + 4 + sizeof (EFI_IMAGE_FILE_HEADER) + FileHeader.SizeOfOptionalHeader;\r
330 if (BytesStripped >= FileSize) {\r
331 Error (NULL, 0, 0, InFileName, "attempt to strip more bytes than the total file size");\r
332 goto Finish;\r
333 }\r
334\r
335 if (BytesStripped &~0xFFFF) {\r
336 Error (NULL, 0, 0, InFileName, "attempt to strip more than 64K bytes", NULL);\r
337 goto Finish;\r
338 }\r
339\r
340 TEImageHeader.StrippedSize = (UINT16) BytesStripped;\r
341\r
342 //\r
343 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+\r
344 //\r
345 SaveFilePosition = ftell (InFptr);\r
346 if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) {\r
347 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
348 goto Finish;\r
349 }\r
350\r
351 if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
352 //\r
353 // Fill in our new header with required data directory entries\r
354 //\r
355 TEImageHeader.AddressOfEntryPoint = OptionalHeader32.AddressOfEntryPoint;\r
356 //\r
357 // - BytesStripped + sizeof (EFI_TE_IMAGE_HEADER);\r
358 //\r
359 // We're going to pack the subsystem into 1 byte. Make sure it fits\r
360 //\r
361 if (OptionalHeader32.Subsystem &~0xFF) {\r
362 Error (\r
363 NULL,\r
364 0,\r
365 0,\r
366 InFileName,\r
367 NULL,\r
368 "image subsystem 0x%X cannot be packed into 1 byte",\r
369 (UINT32) OptionalHeader32.Subsystem\r
370 );\r
371 goto Finish;\r
372 }\r
373\r
374 TEImageHeader.Subsystem = (UINT8) OptionalHeader32.Subsystem;\r
375 TEImageHeader.BaseOfCode = OptionalHeader32.BaseOfCode;\r
5b664244 376 TEImageHeader.ImageBase = (UINT64) (OptionalHeader32.ImageBase);\r
d25c4bf0 377 if (OptionalHeader32.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
378 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
379 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
380 }\r
381\r
382 if (OptionalHeader32.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
383 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
384 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
385 }\r
386 } else if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
387 //\r
388 // Rewind and re-read the optional header\r
389 //\r
390 fseek (InFptr, SaveFilePosition, SEEK_SET);\r
391 if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) {\r
392 Error (NULL, 0, 0, InFileName, "failed to re-read optional header from input file");\r
393 goto Finish;\r
394 }\r
395\r
396 TEImageHeader.AddressOfEntryPoint = OptionalHeader64.AddressOfEntryPoint;\r
397 //\r
398 // - BytesStripped + sizeof (EFI_TE_IMAGE_HEADER);\r
399 //\r
400 // We're going to pack the subsystem into 1 byte. Make sure it fits\r
401 //\r
402 if (OptionalHeader64.Subsystem &~0xFF) {\r
403 Error (\r
404 NULL,\r
405 0,\r
406 0,\r
407 InFileName,\r
408 NULL,\r
409 "image subsystem 0x%X cannot be packed into 1 byte",\r
410 (UINT32) OptionalHeader64.Subsystem\r
411 );\r
412 goto Finish;\r
413 }\r
414\r
415 TEImageHeader.Subsystem = (UINT8) OptionalHeader64.Subsystem;\r
416 TEImageHeader.BaseOfCode = OptionalHeader32.BaseOfCode;\r
5b664244 417 TEImageHeader.ImageBase = (UINT64) (OptionalHeader64.ImageBase);\r
d25c4bf0 418 if (OptionalHeader64.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
419 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
420 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
421 }\r
422\r
423 if (OptionalHeader64.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
424 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
425 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
426 }\r
427 } else {\r
428 Error (\r
429 NULL,\r
430 0,\r
431 0,\r
432 InFileName,\r
433 "unsupported magic number 0x%X found in optional header",\r
434 (UINT32) OptionalHeader32.Magic\r
435 );\r
436 goto Finish;\r
437 }\r
438 //\r
439 // Fill in the remainder of our new image header\r
440 //\r
441 TEImageHeader.Signature = EFI_TE_IMAGE_HEADER_SIGNATURE;\r
442 TEImageHeader.Machine = FileHeader.Machine;\r
443 //\r
444 // We're going to pack the number of sections into a single byte. Make sure it fits.\r
445 //\r
446 if (FileHeader.NumberOfSections &~0xFF) {\r
447 Error (\r
448 NULL,\r
449 0,\r
450 0,\r
451 InFileName,\r
452 NULL,\r
453 "image's number of sections 0x%X cannot be packed into 1 byte",\r
454 (UINT32) FileHeader.NumberOfSections\r
455 );\r
456 goto Finish;\r
457 }\r
458\r
459 TEImageHeader.NumberOfSections = (UINT8) FileHeader.NumberOfSections;\r
460\r
461 //\r
462 // Now open our output file\r
463 //\r
464 if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
465 Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");\r
466 goto Finish;\r
467 }\r
468 //\r
469 // Write the TE header\r
470 //\r
471 if (fwrite (&TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER), 1, OutFptr) != 1) {\r
472 Error (NULL, 0, 0, "failed to write image header to output file", NULL);\r
473 goto Finish;\r
474 }\r
475 //\r
476 // Position into the input file, read the part we're not stripping, and\r
477 // write it out.\r
478 //\r
479 fseek (InFptr, BytesStripped, SEEK_SET);\r
480 Buffer = (UINT8 *) malloc (FileSize - BytesStripped);\r
481 if (Buffer == NULL) {\r
482 Error (NULL, 0, 0, "application error", "failed to allocate memory");\r
483 goto Finish;\r
484 }\r
485\r
486 if (fread (Buffer, FileSize - BytesStripped, 1, InFptr) != 1) {\r
487 Error (NULL, 0, 0, InFileName, "failed to read remaining contents of input file");\r
488 goto Finish;\r
489 }\r
490\r
491 if (fwrite (Buffer, FileSize - BytesStripped, 1, OutFptr) != 1) {\r
492 Error (NULL, 0, 0, OutFileName, "failed to write all bytes to output file");\r
493 goto Finish;\r
494 }\r
495\r
496 Status = STATUS_SUCCESS;\r
497\r
498Finish:\r
499 if (InFptr != NULL) {\r
500 fclose (InFptr);\r
501 }\r
502 //\r
503 // Close the output file. If there was an error, delete the output file so\r
504 // that a subsequent build will rebuild it.\r
505 //\r
506 if (OutFptr != NULL) {\r
507 fclose (OutFptr);\r
508 if (GetUtilityStatus () == STATUS_ERROR) {\r
509 remove (OutFileName);\r
510 }\r
511 }\r
512\r
513 //\r
514 // Free up our buffer\r
515 //\r
516 if (Buffer != NULL) {\r
517 free (Buffer);\r
518 }\r
519\r
520 return Status;\r
521}\r
522\r
523static\r
524STATUS\r
525CheckPE32File (\r
526 INT8 *FileName,\r
527 FILE *Fptr,\r
528 UINT16 *MachineType,\r
529 UINT16 *SubSystem\r
530 )\r
531/*++\r
532\r
533Routine Description:\r
534\r
535 GC_TODO: Add function description\r
536\r
537Arguments:\r
538\r
539 FileName - GC_TODO: add argument description\r
540 Fptr - GC_TODO: add argument description\r
541 MachineType - GC_TODO: add argument description\r
542 SubSystem - GC_TODO: add argument description\r
543\r
544Returns:\r
545\r
546 GC_TODO: add return values\r
547\r
548--*/\r
549{\r
550 /*++\r
551\r
552Routine Description:\r
553 \r
554 Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
555 PE32 image file, and then return the machine type in the supplied pointer.\r
556\r
557Arguments:\r
558\r
559 Fptr File pointer to the already-opened PE32 file\r
560 MachineType Location to stuff the machine type of the PE32 file. This is needed\r
561 because the image may be Itanium-based, IA32, or EBC.\r
562\r
563Returns:\r
564\r
565 0 success\r
566 non-zero otherwise\r
567\r
568--*/\r
569 EFI_IMAGE_DOS_HEADER DosHeader;\r
570 EFI_IMAGE_FILE_HEADER FileHdr;\r
571 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;\r
572 UINT32 PESig;\r
573 STATUS Status;\r
574\r
575 Status = STATUS_ERROR;\r
576 //\r
577 // Position to the start of the file\r
578 //\r
579 fseek (Fptr, 0, SEEK_SET);\r
580 //\r
581 // Read the DOS header\r
582 //\r
583 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
584 Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file");\r
585 goto Finish;\r
586 }\r
587 //\r
588 // Check the magic number (0x5A4D)\r
589 //\r
590 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
591 Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)");\r
592 goto Finish;\r
593 }\r
594 //\r
595 // Position into the file and check the PE signature\r
596 //\r
597 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
598 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {\r
599 Error (NULL, 0, 0, FileName, "failed to read PE signature bytes");\r
600 goto Finish;\r
601 }\r
602 //\r
603 // Check the PE signature in the header "PE\0\0"\r
604 //\r
605 if (PESig != EFI_IMAGE_NT_SIGNATURE) {\r
606 Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)");\r
607 goto Finish;\r
608 }\r
609 //\r
610 // Read the file header\r
611 //\r
612 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {\r
613 Error (NULL, 0, 0, FileName, "failed to read PE file header from input file");\r
614 goto Finish;\r
615 }\r
616 //\r
617 // Read the optional header so we can get the subsystem\r
618 //\r
619 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {\r
620 Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file");\r
621 goto Finish;\r
622 }\r
623\r
5b664244
LG
624 //\r
625 // Check FileAlginment and SectionAlignment match or not\r
626 // Because TeImage header doesn't record filealginment and sectionalignment info, \r
627 // TeImage is used for PEIM and PeiCore XIP module. \r
628 // So, check alignment match before generate TeImage to check.\r
629 //\r
630 if (OptionalHdr.SectionAlignment != OptionalHdr.FileAlignment) {\r
631 Error (NULL, 0, 0, FileName, "Section-Alignment and File-Alignment does not match");\r
632 goto Finish;\r
633 }\r
634\r
d25c4bf0 635 *SubSystem = OptionalHdr.Subsystem;\r
636 if (mOptions.Verbose) {\r
637 fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem);\r
638 }\r
639 //\r
640 // Good to go\r
641 //\r
642 Status = STATUS_SUCCESS;\r
643Finish:\r
644 fseek (Fptr, 0, SEEK_SET);\r
645 return Status;\r
646}\r
647\r
648static\r
649int\r
650ParseCommandLine (\r
651 int Argc,\r
652 char *Argv[]\r
653 )\r
654/*++\r
655\r
656Routine Description:\r
657 \r
658 Given the Argc/Argv program arguments, and a pointer to an options structure,\r
659 parse the command-line options and check their validity.\r
660\r
661\r
662Arguments:\r
663\r
664 Argc - standard C main() argument count\r
665 Argv - standard C main() argument list\r
666\r
667Returns:\r
668\r
669 STATUS_SUCCESS success\r
670 non-zero otherwise\r
671\r
672--*/\r
673// GC_TODO: ] - add argument and description to function comment\r
674{\r
675 //\r
676 // Clear out the options\r
677 //\r
678 memset ((char *) &mOptions, 0, sizeof (mOptions));\r
679 //\r
680 // Skip over the program name\r
681 //\r
682 Argc--;\r
683 Argv++;\r
684 //\r
685 // If no arguments, assume they want usage info\r
686 //\r
687 if (Argc == 0) {\r
688 Usage ();\r
689 return STATUS_ERROR;\r
690 }\r
db608e6b 691 \r
692 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||\r
693 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {\r
694 Usage();\r
695 return STATUS_ERROR;\r
696 }\r
697 \r
698 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {\r
699 Version();\r
700 return STATUS_ERROR;\r
701 }\r
702 \r
d25c4bf0 703 //\r
704 // Process until no more arguments\r
705 //\r
ca9ea8d9 706 while ((Argc > 0) && (Argv[0][0] == '-')) {\r
d25c4bf0 707 if (stricmp (Argv[0], "-o") == 0) {\r
708 //\r
709 // Output filename specified with -o\r
710 // Make sure there's another parameter\r
711 //\r
712 if (Argc > 1) {\r
713 strcpy (mOptions.OutFileName, Argv[1]);\r
714 } else {\r
715 Error (NULL, 0, 0, Argv[0], "missing output file name with option");\r
716 Usage ();\r
717 return STATUS_ERROR;\r
718 }\r
719\r
720 Argv++;\r
721 Argc--;\r
722 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
723 //\r
724 // Help option\r
725 //\r
726 Usage ();\r
727 return STATUS_ERROR;\r
728 } else if (stricmp (Argv[0], "-v") == 0) {\r
729 //\r
730 // -v for verbose\r
731 //\r
732 mOptions.Verbose = 1;\r
733 } else if (stricmp (Argv[0], "-dump") == 0) {\r
734 //\r
735 // -dump for dumping an image\r
736 //\r
737 mOptions.Dump = 1;\r
738 } else {\r
739 Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
740 Usage ();\r
741 return STATUS_ERROR;\r
742 }\r
743 //\r
744 // Next argument\r
745 //\r
746 Argv++;\r
747 Argc--;\r
748 }\r
749 //\r
750 // Better be one more arg for input file name\r
751 //\r
752 if (Argc == 0) {\r
753 Error (NULL, 0, 0, "input file name required", NULL);\r
754 Usage ();\r
755 return STATUS_ERROR;\r
756 }\r
757\r
758 if (Argc != 1) {\r
759 Error (NULL, 0, 0, Argv[1], "extra arguments on command line");\r
760 return STATUS_ERROR;\r
761 }\r
762\r
763 strcpy (mOptions.InFileName, Argv[0]);\r
764 return STATUS_SUCCESS;\r
765}\r
766\r
db608e6b 767static\r
768void \r
769Version(\r
770 void\r
771)\r
772/*++\r
773\r
774Routine Description:\r
775\r
776 Displays the standard utility information to SDTOUT\r
777\r
778Arguments:\r
779\r
780 None\r
781\r
782Returns:\r
783\r
784 None\r
785\r
786--*/\r
787{\r
788 printf ("%s v%d.%d -Utility to generate a TE image from an EFI PE32 image.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
789 printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");\r
790}\r
791\r
d25c4bf0 792static\r
793void\r
794Usage (\r
795 VOID\r
796 )\r
797/*++\r
798\r
799Routine Description:\r
800 \r
801 Print usage information for this utility.\r
802\r
803Arguments:\r
804\r
805 None.\r
806\r
807Returns:\r
808\r
809 Nothing.\r
810\r
811--*/\r
812{\r
813 int Index;\r
814 static const char *Msg[] = {\r
db608e6b 815 "\nUsage: "UTILITY_NAME " {-v} {-dump} {-h|-?} {-o OutFileName} InFileName",\r
d25c4bf0 816 " [-e|-b] [FileName(s)]",\r
817 " where:",\r
db608e6b 818 " -h,--help,-?,/? to display help messages",\r
819 " -V,--version to display version information",\r
d25c4bf0 820 " -v - for verbose output",\r
821 " -dump - to dump the input file to a text file",\r
d25c4bf0 822 " -o OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION,\r
823 " InFileName - name of the input PE32 file",\r
824 "",\r
825 NULL\r
826 };\r
db608e6b 827 \r
828 Version();\r
829 \r
d25c4bf0 830 for (Index = 0; Msg[Index] != NULL; Index++) {\r
831 fprintf (stdout, "%s\n", Msg[Index]);\r
832 }\r
833}\r
834\r
835static\r
836VOID\r
837DumpImage (\r
838 INT8 *FileName\r
839 )\r
840/*++\r
841\r
842Routine Description:\r
843 \r
844 Dump a specified image information\r
845\r
846Arguments:\r
847 \r
848 FileName - File name pointer to the image to dump\r
849\r
850Returns:\r
851\r
852 Nothing.\r
853\r
854--*/\r
855{\r
856 FILE *InFptr;\r
857 EFI_TE_IMAGE_HEADER TEImageHeader;\r
858 INT8 *NamePtr;\r
859\r
860 //\r
861 // Open the input file\r
862 //\r
863 InFptr = NULL;\r
864\r
865 if ((InFptr = fopen (FileName, "rb")) == NULL) {\r
866 Error (NULL, 0, 0, FileName, "failed to open input file for reading");\r
867 return ;\r
868 }\r
869\r
870 if (fread (&TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER), 1, InFptr) != 1) {\r
871 Error (NULL, 0, 0, FileName, "failed to read image header from input file");\r
872 goto Finish;\r
873 }\r
874\r
875 if (TEImageHeader.Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
876 Error (NULL, 0, 0, FileName, "Image does not appear to be a TE image (bad signature)");\r
877 goto Finish;\r
878 }\r
879 //\r
880 // Dump the header\r
881 //\r
882 fprintf (stdout, "Header (%d bytes):\n", sizeof (EFI_TE_IMAGE_HEADER));\r
883 fprintf (stdout, " Signature: 0x%04X (TE)\n", (UINT32) TEImageHeader.Signature);\r
884 NamePtr = GetMachineTypeStr (TEImageHeader.Machine);\r
885 fprintf (stdout, " Machine: 0x%04X (%s)\n", (UINT32) TEImageHeader.Machine, NamePtr);\r
886 NamePtr = GetSubsystemTypeStr (TEImageHeader.Subsystem);\r
887 fprintf (stdout, " Subsystem: 0x%02X (%s)\n", (UINT32) TEImageHeader.Subsystem, NamePtr);\r
888 fprintf (stdout, " Number of sections 0x%02X\n", (UINT32) TEImageHeader.NumberOfSections);\r
889 fprintf (stdout, " Stripped size: 0x%04X\n", (UINT32) TEImageHeader.StrippedSize);\r
890 fprintf (stdout, " Entry point: 0x%08X\n", TEImageHeader.AddressOfEntryPoint);\r
891 fprintf (stdout, " Base of code: 0x%08X\n", TEImageHeader.BaseOfCode);\r
892 fprintf (stdout, " Data directories:\n");\r
893 fprintf (\r
894 stdout,\r
895 " %8X [%8X] RVA [size] of Base Relocation Directory\n",\r
896 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,\r
897 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size\r
898 );\r
899 fprintf (\r
900 stdout,\r
901 " %8X [%8X] RVA [size] of Debug Directory\n",\r
902 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,\r
903 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size\r
904 );\r
905\r
906Finish:\r
907 if (InFptr != NULL) {\r
908 fclose (InFptr);\r
909 }\r
910}\r
911\r
912static\r
913INT8 *\r
914GetMachineTypeStr (\r
915 UINT16 MachineType\r
916 )\r
917/*++\r
918\r
919Routine Description:\r
920\r
921 GC_TODO: Add function description\r
922\r
923Arguments:\r
924\r
925 MachineType - GC_TODO: add argument description\r
926\r
927Returns:\r
928\r
929 GC_TODO: add return values\r
930\r
931--*/\r
932{\r
933 int Index;\r
934\r
935 for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {\r
936 if (mMachineTypes[Index].Value == MachineType) {\r
937 return mMachineTypes[Index].Name;\r
938 }\r
939 }\r
940\r
941 return "unknown";\r
942}\r
943\r
944static\r
945INT8 *\r
946GetSubsystemTypeStr (\r
947 UINT16 SubsystemType\r
948 )\r
949/*++\r
950\r
951Routine Description:\r
952\r
953 GC_TODO: Add function description\r
954\r
955Arguments:\r
956\r
957 SubsystemType - GC_TODO: add argument description\r
958\r
959Returns:\r
960\r
961 GC_TODO: add return values\r
962\r
963--*/\r
964{\r
965 int Index;\r
966\r
967 for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {\r
968 if (mSubsystemTypes[Index].Value == SubsystemType) {\r
969 return mSubsystemTypes[Index].Name;\r
970 }\r
971 }\r
972\r
973 return "unknown";\r
974}\r