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