Add checking code for GenAcpiTable tools.
[people/mcb30/edk2.git] / edk2 / Tools / CCode / Source / GenAcpiTable / GenAcpiTable.c
1 /*++\r
2 \r
3 Copyright (c)  2004-2006 Intel Corporation. All rights reserved\r
4 This program and the accompanying materials are licensed and made available \r
5 under the terms and conditions of the BSD License which accompanies this \r
6 distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   GenAcpiTable.c\r
15   \r
16 Abstract:\r
17 \r
18   A utility that extracts the .DATA section from a PE/COFF image.\r
19 \r
20 --*/\r
21 \r
22 #include <stdio.h>\r
23 #include <string.h>\r
24 #include <stdlib.h>\r
25 \r
26 #include <Common/UefiBaseTypes.h>\r
27 #include <Common/EfiImage.h> // for PE32 structure definitions\r
28 \r
29 #include "CommonLib.h"\r
30 #include "EfiUtilityMsgs.h"\r
31 \r
32 //\r
33 // Acpi Table definition\r
34 //\r
35 #include "Acpi.h"\r
36 #include "Acpi1_0.h"\r
37 #include "Acpi2_0.h"\r
38 #include "Acpi3_0.h"\r
39 #include "MemoryMappedConfigurationSpaceAccessTable.h"\r
40 \r
41 //\r
42 // Version of this utility\r
43 //\r
44 #define UTILITY_NAME  "GenAcpiTable"\r
45 #define UTILITY_MAJOR_VERSION 0\r
46 #define UTILITY_MINOR_VERSION 11\r
47 \r
48 //\r
49 // Define the max length of a filename\r
50 //\r
51 #define MAX_PATH                  256\r
52 #define DEFAULT_OUTPUT_EXTENSION  ".acpi"\r
53 \r
54 //\r
55 // Use this to track our command-line options and globals\r
56 //\r
57 struct {\r
58   INT8  OutFileName[MAX_PATH];\r
59   INT8  InFileName[MAX_PATH];\r
60 } mOptions;\r
61 \r
62 //\r
63 // Use these to convert from machine type value to a named type\r
64 //\r
65 typedef struct {\r
66   UINT16  Value;\r
67   INT8    *Name;\r
68 } STRING_LOOKUP;\r
69 \r
70 static STRING_LOOKUP  mMachineTypes[] = {\r
71   EFI_IMAGE_MACHINE_IA32,\r
72   "IA32",\r
73   EFI_IMAGE_MACHINE_IA64,\r
74   "IA64",\r
75   EFI_IMAGE_MACHINE_EBC,\r
76   "EBC",\r
77   0,\r
78   NULL\r
79 };\r
80 \r
81 static STRING_LOOKUP  mSubsystemTypes[] = {\r
82   EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,\r
83   "EFI application",\r
84   EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,\r
85   "EFI boot service driver",\r
86   EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,\r
87   "EFI runtime driver",\r
88   0,\r
89   NULL\r
90 };\r
91 //\r
92 //  Function prototypes\r
93 //\r
94 static\r
95 void\r
96 Version (\r
97   VOID\r
98   );\r
99 \r
100 static\r
101 void\r
102 Usage (\r
103   VOID\r
104   );\r
105 \r
106 static\r
107 STATUS\r
108 ParseCommandLine (\r
109   int       Argc,\r
110   char      *Argv[]\r
111   );\r
112 \r
113 static\r
114 STATUS\r
115 CheckAcpiTable (\r
116   VOID      *AcpiTable,\r
117   UINT32    Length\r
118   );\r
119 \r
120 static\r
121 STATUS\r
122 CheckPE32File (\r
123   INT8      *FileName,\r
124   FILE      *Fptr,\r
125   UINT16    *MachineType,\r
126   UINT16    *SubSystem\r
127   );\r
128 \r
129 static\r
130 STATUS\r
131 ProcessFile (\r
132   INT8      *InFileName,\r
133   INT8      *OutFileName\r
134   );\r
135 \r
136 static\r
137 void\r
138 DumpImage (\r
139   INT8      *FileName\r
140   );\r
141 \r
142 main (\r
143   int   Argc,\r
144   char  *Argv[]\r
145   )\r
146 /*++\r
147 \r
148 Routine Description:\r
149   \r
150 \r
151 Arguments:\r
152 \r
153   Argc            - standard C main() argument count\r
154 \r
155   Argv            - standard C main() argument list\r
156 \r
157 Returns:\r
158 \r
159   0             success\r
160   non-zero      otherwise\r
161 \r
162 --*/\r
163 // GC_TODO:    ] - add argument and description to function comment\r
164 {\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   // Make sure we don't have the same filename for input and output files\r
176   //\r
177   if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) {\r
178     Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different");\r
179     goto Finish;\r
180   }\r
181   //\r
182   // Process the file\r
183   //\r
184   ProcessFile (mOptions.InFileName, mOptions.OutFileName);\r
185 Finish:\r
186   Status = GetUtilityStatus ();\r
187   return Status;\r
188 }\r
189 \r
190 static\r
191 STATUS\r
192 ProcessFile (\r
193   INT8      *InFileName,\r
194   INT8      *OutFileName\r
195   )\r
196 /*++\r
197 \r
198 Routine Description:\r
199   \r
200   Process a PE32 EFI file.\r
201 \r
202 Arguments:\r
203 \r
204   InFileName - Name of the PE32 EFI file to process.\r
205   OutFileName - Name of the output file for the processed data.\r
206 \r
207 Returns:\r
208 \r
209   0 - successful\r
210 \r
211 --*/\r
212 {\r
213   STATUS                      Status;\r
214   UINTN                       Index;\r
215   FILE                        *InFptr;\r
216   FILE                        *OutFptr;\r
217   UINT16                      MachineType;\r
218   UINT16                      SubSystem;\r
219   UINT32                      PESigOffset;\r
220   EFI_IMAGE_FILE_HEADER       FileHeader;\r
221   EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32;\r
222   EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64;\r
223   EFI_IMAGE_SECTION_HEADER    SectionHeader;\r
224   UINT8                       *Buffer;\r
225   long                        SaveFilePosition;\r
226 \r
227   InFptr  = NULL;\r
228   OutFptr = NULL;\r
229   Buffer  = NULL;\r
230   Status  = STATUS_ERROR;\r
231   //\r
232   // Try to open the input file\r
233   //\r
234   if ((InFptr = fopen (InFileName, "rb")) == NULL) {\r
235     Error (NULL, 0, 0, InFileName, "failed to open input file for reading");\r
236     return STATUS_ERROR;\r
237   }\r
238   //\r
239   // Double-check the file to make sure it's what we expect it to be\r
240   //\r
241   if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) {\r
242     goto Finish;\r
243   }\r
244   //\r
245   // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit\r
246   // offset (from the start of the file) to the PE signature, which always\r
247   // follows the MSDOS stub. The PE signature is immediately followed by the\r
248   // COFF file header.\r
249   //\r
250   //\r
251   if (fseek (InFptr, 0x3C, SEEK_SET) != 0) {\r
252     Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL);\r
253     goto Finish;\r
254   }\r
255 \r
256   if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) {\r
257     Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file");\r
258     goto Finish;\r
259   }\r
260 \r
261   if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) {\r
262     Error (NULL, 0, 0, InFileName, "failed to seek to PE signature");\r
263     goto Finish;\r
264   }\r
265   //\r
266   // We should now be at the COFF file header. Read it in and verify it's\r
267   // of an image type we support.\r
268   //\r
269   if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) {\r
270     Error (NULL, 0, 0, InFileName, "failed to read file header from image");\r
271     goto Finish;\r
272   }\r
273 \r
274   if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64) && (FileHeader.Machine != EFI_IMAGE_MACHINE_X64)) {\r
275     Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine);\r
276     goto Finish;\r
277   }\r
278   //\r
279   // Read in the optional header. Assume PE32, and if not, then re-read as PE32+\r
280   //\r
281   SaveFilePosition = ftell (InFptr);\r
282   if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) {\r
283     Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
284     goto Finish;\r
285   }\r
286 \r
287   if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
288     if (fseek (InFptr, SaveFilePosition, SEEK_SET) != 0) {\r
289       Error (NULL, 0, 0, InFileName, "failed to seek to .data section");\r
290       goto Finish;\r
291     }\r
292 \r
293     if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) {\r
294       Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
295       goto Finish;\r
296     }\r
297   }\r
298   //\r
299   // Search for the ".data" section\r
300   //\r
301   for (Index = 0; Index < FileHeader.NumberOfSections; Index++) {\r
302     if (fread (&SectionHeader, sizeof (EFI_IMAGE_SECTION_HEADER), 1, InFptr) != 1) {\r
303       Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
304       goto Finish;\r
305     }\r
306 \r
307     if (strcmp (SectionHeader.Name, ".data") == 0 || strcmp (SectionHeader.Name, ".sdata") == 0) {\r
308       if (fseek (InFptr, SectionHeader.PointerToRawData, SEEK_SET) != 0) {\r
309         Error (NULL, 0, 0, InFileName, "failed to seek to .data section");\r
310         goto Finish;\r
311       }\r
312 \r
313       Buffer = (UINT8 *) malloc (SectionHeader.Misc.VirtualSize);\r
314       if (Buffer == NULL) {\r
315         Status = EFI_OUT_OF_RESOURCES;\r
316         goto Finish;\r
317       }\r
318       if (fread (Buffer, SectionHeader.Misc.VirtualSize, 1, InFptr) != 1) {\r
319         Error (NULL, 0, 0, InFileName, "failed to .data section");\r
320         goto Finish;\r
321       }\r
322 \r
323       //\r
324       // Check Acpi Table\r
325       //\r
326       if (CheckAcpiTable (Buffer, SectionHeader.Misc.VirtualSize) != STATUS_SUCCESS) {\r
327         Error (NULL, 0, 0, InFileName, "failed to check ACPI table");\r
328         goto Finish;\r
329       }\r
330 \r
331       //\r
332       // Now open our output file\r
333       //\r
334       if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
335         Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");\r
336         goto Finish;\r
337       }\r
338 \r
339       if (fwrite (Buffer, SectionHeader.Misc.VirtualSize, 1, OutFptr) != 1) {\r
340         Error (NULL, 0, 0, OutFileName, "failed to write .data section");\r
341         goto Finish;\r
342       }\r
343 \r
344       Status = STATUS_SUCCESS;\r
345       goto Finish;\r
346     }\r
347   }\r
348 \r
349   Status = STATUS_ERROR;\r
350 \r
351 Finish:\r
352   if (InFptr != NULL) {\r
353     fclose (InFptr);\r
354   }\r
355   //\r
356   // Close the output file. If there was an error, delete the output file so\r
357   // that a subsequent build will rebuild it.\r
358   //\r
359   if (OutFptr != NULL) {\r
360     fclose (OutFptr);\r
361     if (GetUtilityStatus () == STATUS_ERROR) {\r
362       remove (OutFileName);\r
363     }\r
364   }\r
365 \r
366   //\r
367   // Free up our buffer\r
368   //\r
369   if (Buffer != NULL) {\r
370     free (Buffer);\r
371   }\r
372 \r
373   return Status;\r
374 }\r
375 \r
376 static\r
377 STATUS\r
378 CheckAcpiTable (\r
379   VOID      *AcpiTable,\r
380   UINT32    Length\r
381   )\r
382 /*++\r
383 \r
384 Routine Description:\r
385   \r
386   Check Acpi Table \r
387 \r
388 Arguments:\r
389 \r
390   AcpiTable     Buffer for AcpiSection\r
391   Length        AcpiSection Length\r
392 \r
393 Returns:\r
394 \r
395   0             success\r
396   non-zero      otherwise\r
397 \r
398 --*/\r
399 {\r
400   EFI_ACPI_DESCRIPTION_HEADER                   *AcpiHeader;\r
401   EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;\r
402   UINT32                                        ExpectedLength;\r
403 \r
404   AcpiHeader = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable;\r
405 \r
406   //\r
407   // Generic check for AcpiTable length.\r
408   //\r
409   if (AcpiHeader->Length > Length) {\r
410     Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass AcpiTable Length check");\r
411     return STATUS_ERROR;\r
412   }\r
413 \r
414   //\r
415   // Currently, we only check must-have tables: FADT, FACS, DSDT,\r
416   // and some important tables: MADT, MCFG.\r
417   //\r
418   switch (AcpiHeader->Signature) {\r
419 \r
420   //\r
421   // "FACP" Fixed ACPI Description Table\r
422   //\r
423   case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:\r
424     switch (AcpiHeader->Revision) {\r
425     case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:\r
426       ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE);\r
427       break;\r
428     case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:\r
429       ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE);\r
430       break;\r
431     case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:\r
432       ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE);\r
433       break;\r
434     default:\r
435       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACP revision check");\r
436       return STATUS_ERROR;\r
437     }\r
438     if (ExpectedLength != AcpiHeader->Length) {\r
439       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACP Length check");\r
440       return STATUS_ERROR;\r
441     }\r
442     break;\r
443 \r
444   //\r
445   // "FACS" Firmware ACPI Control Structure\r
446   //\r
447   case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:\r
448     Facs = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable;\r
449     if ((Facs->Version != 0) &&\r
450         (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
451         (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)){\r
452       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACS version check");\r
453       return STATUS_ERROR;\r
454     }\r
455     if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&\r
456         (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&\r
457         (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) {\r
458       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACS Length check");\r
459       return STATUS_ERROR;\r
460     }\r
461     break;\r
462 \r
463   //\r
464   // "DSDT" Differentiated System Description Table\r
465   //\r
466   case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:\r
467     if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) {\r
468       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass DSDT revision check");\r
469       return STATUS_ERROR;\r
470     }\r
471     if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {\r
472       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass DSDT Length check");\r
473       return STATUS_ERROR;\r
474     }\r
475     break;\r
476 \r
477   //\r
478   // "APIC" Multiple APIC Description Table\r
479   //\r
480   case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:\r
481     if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&\r
482         (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&\r
483         (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) {\r
484       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass APIC revision check");\r
485       return STATUS_ERROR;\r
486     }\r
487     if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32)) {\r
488       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass APIC Length check");\r
489       return STATUS_ERROR;\r
490     }\r
491     break;\r
492 \r
493   //\r
494   // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table\r
495   //\r
496   case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:\r
497     if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) {\r
498       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass MCFG revision check");\r
499       return STATUS_ERROR;\r
500     }\r
501     if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64)) {\r
502       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass MCFG Length check");\r
503       return STATUS_ERROR;\r
504     }\r
505     break;\r
506 \r
507   //\r
508   // Other table pass check\r
509   //\r
510   default:\r
511     break;\r
512   }\r
513 \r
514   return STATUS_SUCCESS;\r
515 }\r
516 \r
517 static\r
518 STATUS\r
519 CheckPE32File (\r
520   INT8      *FileName,\r
521   FILE      *Fptr,\r
522   UINT16    *MachineType,\r
523   UINT16    *SubSystem\r
524   )\r
525 /*++\r
526 \r
527 Routine Description:\r
528 \r
529   GC_TODO: Add function description\r
530 \r
531 Arguments:\r
532 \r
533   FileName    - GC_TODO: add argument description\r
534   Fptr        - GC_TODO: add argument description\r
535   MachineType - GC_TODO: add argument description\r
536   SubSystem   - GC_TODO: add argument description\r
537 \r
538 Returns:\r
539 \r
540   GC_TODO: add return values\r
541 \r
542 --*/\r
543 {\r
544   /*++\r
545 \r
546 Routine Description:\r
547   \r
548   Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
549   PE32 image file, and then return the machine type in the supplied pointer.\r
550 \r
551 Arguments:\r
552 \r
553   Fptr          File pointer to the already-opened PE32 file\r
554   MachineType   Location to stuff the machine type of the PE32 file. This is needed\r
555                 because the image may be Itanium-based, IA32, or EBC.\r
556 \r
557 Returns:\r
558 \r
559   0             success\r
560   non-zero      otherwise\r
561 \r
562 --*/\r
563   EFI_IMAGE_DOS_HEADER      DosHeader;\r
564   EFI_IMAGE_FILE_HEADER     FileHdr;\r
565   EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;\r
566   UINT32                    PESig;\r
567   STATUS                    Status;\r
568 \r
569   Status = STATUS_ERROR;\r
570   //\r
571   // Position to the start of the file\r
572   //\r
573   fseek (Fptr, 0, SEEK_SET);\r
574   //\r
575   // Read the DOS header\r
576   //\r
577   if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
578     Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file");\r
579     goto Finish;\r
580   }\r
581   //\r
582   // Check the magic number (0x5A4D)\r
583   //\r
584   if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
585     Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)");\r
586     goto Finish;\r
587   }\r
588   //\r
589   // Position into the file and check the PE signature\r
590   //\r
591   fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
592   if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {\r
593     Error (NULL, 0, 0, FileName, "failed to read PE signature bytes");\r
594     goto Finish;\r
595   }\r
596   //\r
597   // Check the PE signature in the header "PE\0\0"\r
598   //\r
599   if (PESig != EFI_IMAGE_NT_SIGNATURE) {\r
600     Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)");\r
601     goto Finish;\r
602   }\r
603   //\r
604   // Read the file header\r
605   //\r
606   if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {\r
607     Error (NULL, 0, 0, FileName, "failed to read PE file header from input file");\r
608     goto Finish;\r
609   }\r
610   //\r
611   // Read the optional header so we can get the subsystem\r
612   //\r
613   if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {\r
614     Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file");\r
615     goto Finish;\r
616   }\r
617 \r
618   *SubSystem = OptionalHdr.Subsystem;\r
619   //\r
620   // Good to go\r
621   //\r
622   Status = STATUS_SUCCESS;\r
623 Finish:\r
624   fseek (Fptr, 0, SEEK_SET);\r
625   return Status;\r
626 }\r
627 \r
628 static\r
629 int\r
630 ParseCommandLine (\r
631   int         Argc,\r
632   char        *Argv[]\r
633   )\r
634 /*++\r
635 \r
636 Routine 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
642 Arguments:\r
643 \r
644   Argc            - standard C main() argument count\r
645   Argv            - standard C main() argument list\r
646 \r
647 Returns:\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 (Argc < 1) {\r
666     Usage();\r
667     return STATUS_ERROR;\r
668   }\r
669   \r
670   if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||\r
671       (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {\r
672     Usage();\r
673     return STATUS_ERROR;\r
674   }\r
675   \r
676   if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {\r
677     Version();\r
678     return STATUS_ERROR;\r
679   }\r
680 \r
681   if (Argc != 2) {\r
682     Usage ();\r
683     return STATUS_ERROR;\r
684   }\r
685 \r
686   strcpy (mOptions.InFileName, Argv[0]);\r
687   //\r
688   // Next argument\r
689   //\r
690   Argv++;\r
691   Argc--;\r
692 \r
693   strcpy (mOptions.OutFileName, Argv[0]);\r
694 \r
695   return STATUS_SUCCESS;\r
696 }\r
697 \r
698 static\r
699 void\r
700 Version (\r
701   VOID\r
702   )\r
703 {\r
704   printf ("%s v%d.%d -EDK Utility for generating ACPI Table image from an EFI PE32 image.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
705   printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
706 }\r
707 \r
708 \r
709 static\r
710 void\r
711 Usage (\r
712   VOID\r
713   )\r
714 /*++\r
715 \r
716 Routine Description:\r
717   \r
718   Print usage information for this utility.\r
719 \r
720 Arguments:\r
721 \r
722   None.\r
723 \r
724 Returns:\r
725 \r
726   Nothing.\r
727 \r
728 --*/\r
729 {\r
730   int               Index;\r
731   static const char *Msg[] = {\r
732     "\nUsage: "UTILITY_NAME " {-h|--help|-?|/?|-V|--version} InFileName OutFileName",\r
733     "  where:",\r
734     "    InFileName  - name of the input PE32 file",\r
735     "    OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION,\r
736     NULL\r
737   };\r
738   \r
739   Version();\r
740   for (Index = 0; Msg[Index] != NULL; Index++) {\r
741     fprintf (stdout, "%s\n", Msg[Index]);\r
742   }\r
743 }\r