]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/GenAcpiTable/GenAcpiTable.c
Added or modified utility version and usage display.
[mirror_edk2.git] / Tools / CCode / Source / GenAcpiTable / GenAcpiTable.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 2004-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 GenAcpiTable.c\r
15 \r
16Abstract:\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
ce53a8c3 26#include <Common/UefiBaseTypes.h>\r
27#include <Common/EfiImage.h> // for PE32 structure definitions\r
28\r
29#include "CommonLib.h"\r
d25c4bf0 30#include "EfiUtilityMsgs.h"\r
31\r
32//\r
33// Version of this utility\r
34//\r
f091efb3 35#define UTILITY_NAME "GenAcpiTable"\r
36#define UTILITY_MAJOR_VERSION 0\r
37#define UTILITY_MINOR_VERSION 11\r
d25c4bf0 38\r
39//\r
40// Define the max length of a filename\r
41//\r
42#define MAX_PATH 256\r
43#define DEFAULT_OUTPUT_EXTENSION ".acpi"\r
44\r
45//\r
46// Use this to track our command-line options and globals\r
47//\r
48struct {\r
49 INT8 OutFileName[MAX_PATH];\r
50 INT8 InFileName[MAX_PATH];\r
51} mOptions;\r
52\r
53//\r
54// Use these to convert from machine type value to a named type\r
55//\r
56typedef struct {\r
57 UINT16 Value;\r
58 INT8 *Name;\r
59} STRING_LOOKUP;\r
60\r
61static STRING_LOOKUP mMachineTypes[] = {\r
62 EFI_IMAGE_MACHINE_IA32,\r
63 "IA32",\r
64 EFI_IMAGE_MACHINE_IA64,\r
65 "IA64",\r
66 EFI_IMAGE_MACHINE_EBC,\r
67 "EBC",\r
68 0,\r
69 NULL\r
70};\r
71\r
72static STRING_LOOKUP mSubsystemTypes[] = {\r
73 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,\r
74 "EFI application",\r
75 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,\r
76 "EFI boot service driver",\r
77 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,\r
78 "EFI runtime driver",\r
79 0,\r
80 NULL\r
81};\r
82//\r
83// Function prototypes\r
84//\r
f091efb3 85static\r
86void\r
87Version (\r
88 VOID\r
89 );\r
90\r
d25c4bf0 91static\r
92void\r
93Usage (\r
94 VOID\r
95 );\r
96\r
97static\r
98STATUS\r
99ParseCommandLine (\r
100 int Argc,\r
101 char *Argv[]\r
102 );\r
103\r
104static\r
105STATUS\r
106CheckPE32File (\r
107 INT8 *FileName,\r
108 FILE *Fptr,\r
109 UINT16 *MachineType,\r
110 UINT16 *SubSystem\r
111 );\r
112\r
113static\r
114STATUS\r
115ProcessFile (\r
116 INT8 *InFileName,\r
117 INT8 *OutFileName\r
118 );\r
119\r
120static\r
121void\r
122DumpImage (\r
123 INT8 *FileName\r
124 );\r
125\r
126main (\r
127 int Argc,\r
128 char *Argv[]\r
129 )\r
130/*++\r
131\r
132Routine Description:\r
133 \r
134\r
135Arguments:\r
136\r
137 Argc - standard C main() argument count\r
138\r
139 Argv - standard C main() argument list\r
140\r
141Returns:\r
142\r
143 0 success\r
144 non-zero otherwise\r
145\r
146--*/\r
147// GC_TODO: ] - add argument and description to function comment\r
148{\r
149 UINT32 Status;\r
150\r
151 SetUtilityName (UTILITY_NAME);\r
152 //\r
153 // Parse the command line arguments\r
154 //\r
155 if (ParseCommandLine (Argc, Argv)) {\r
156 return STATUS_ERROR;\r
157 }\r
158 //\r
159 // Make sure we don't have the same filename for input and output files\r
160 //\r
161 if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) {\r
162 Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different");\r
163 goto Finish;\r
164 }\r
165 //\r
166 // Process the file\r
167 //\r
168 ProcessFile (mOptions.InFileName, mOptions.OutFileName);\r
169Finish:\r
170 Status = GetUtilityStatus ();\r
171 return Status;\r
172}\r
173\r
174static\r
175STATUS\r
176ProcessFile (\r
177 INT8 *InFileName,\r
178 INT8 *OutFileName\r
179 )\r
180/*++\r
181\r
182Routine Description:\r
183 \r
184 Process a PE32 EFI file.\r
185\r
186Arguments:\r
187\r
188 InFileName - Name of the PE32 EFI file to process.\r
189 OutFileName - Name of the output file for the processed data.\r
190\r
191Returns:\r
192\r
193 0 - successful\r
194\r
195--*/\r
196{\r
197 STATUS Status;\r
198 UINTN Index;\r
199 FILE *InFptr;\r
200 FILE *OutFptr;\r
201 UINT16 MachineType;\r
202 UINT16 SubSystem;\r
203 UINT32 PESigOffset;\r
204 EFI_IMAGE_FILE_HEADER FileHeader;\r
205 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32;\r
928fbe8f 206 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64;\r
d25c4bf0 207 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
208 UINT8 *Buffer;\r
209 long SaveFilePosition;\r
210\r
211 InFptr = NULL;\r
212 OutFptr = NULL;\r
213 Buffer = NULL;\r
214 Status = STATUS_ERROR;\r
215 //\r
216 // Try to open the input file\r
217 //\r
218 if ((InFptr = fopen (InFileName, "rb")) == NULL) {\r
219 Error (NULL, 0, 0, InFileName, "failed to open input file for reading");\r
220 return STATUS_ERROR;\r
221 }\r
222 //\r
223 // Double-check the file to make sure it's what we expect it to be\r
224 //\r
225 if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) {\r
226 goto Finish;\r
227 }\r
228 //\r
229 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit\r
230 // offset (from the start of the file) to the PE signature, which always\r
231 // follows the MSDOS stub. The PE signature is immediately followed by the\r
232 // COFF file header.\r
233 //\r
234 //\r
235 if (fseek (InFptr, 0x3C, SEEK_SET) != 0) {\r
236 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL);\r
237 goto Finish;\r
238 }\r
239\r
240 if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) {\r
241 Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file");\r
242 goto Finish;\r
243 }\r
244\r
245 if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) {\r
246 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature");\r
247 goto Finish;\r
248 }\r
249 //\r
250 // We should now be at the COFF file header. Read it in and verify it's\r
251 // of an image type we support.\r
252 //\r
253 if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) {\r
254 Error (NULL, 0, 0, InFileName, "failed to read file header from image");\r
255 goto Finish;\r
256 }\r
257\r
258 if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64) && (FileHeader.Machine != EFI_IMAGE_MACHINE_X64)) {\r
259 Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine);\r
260 goto Finish;\r
261 }\r
262 //\r
263 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+\r
264 //\r
265 SaveFilePosition = ftell (InFptr);\r
266 if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) {\r
267 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
268 goto Finish;\r
269 }\r
270\r
271 if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
272 if (fseek (InFptr, SaveFilePosition, SEEK_SET) != 0) {\r
273 Error (NULL, 0, 0, InFileName, "failed to seek to .data section");\r
274 goto Finish;\r
275 }\r
276\r
928fbe8f 277 if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) {\r
d25c4bf0 278 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
279 goto Finish;\r
280 }\r
281 }\r
282 //\r
283 // Search for the ".data" section\r
284 //\r
285 for (Index = 0; Index < FileHeader.NumberOfSections; Index++) {\r
286 if (fread (&SectionHeader, sizeof (EFI_IMAGE_SECTION_HEADER), 1, InFptr) != 1) {\r
287 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
288 goto Finish;\r
289 }\r
290\r
c6137cfd 291 if (strcmp (SectionHeader.Name, ".data") == 0 || strcmp (SectionHeader.Name, ".sdata") == 0) {\r
d25c4bf0 292 if (fseek (InFptr, SectionHeader.PointerToRawData, SEEK_SET) != 0) {\r
293 Error (NULL, 0, 0, InFileName, "failed to seek to .data section");\r
294 goto Finish;\r
295 }\r
296\r
297 Buffer = (UINT8 *) malloc (SectionHeader.Misc.VirtualSize);\r
298 if (Buffer == NULL) {\r
299 Status = EFI_OUT_OF_RESOURCES;\r
300 goto Finish;\r
301 }\r
302 if (fread (Buffer, SectionHeader.Misc.VirtualSize, 1, InFptr) != 1) {\r
303 Error (NULL, 0, 0, InFileName, "failed to .data section");\r
304 goto Finish;\r
305 }\r
306 //\r
307 // Now open our output file\r
308 //\r
309 if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
310 Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");\r
311 goto Finish;\r
312 }\r
313\r
314 if (fwrite (Buffer, SectionHeader.Misc.VirtualSize, 1, OutFptr) != 1) {\r
315 Error (NULL, 0, 0, OutFileName, "failed to write .data section");\r
316 goto Finish;\r
317 }\r
318\r
319 Status = STATUS_SUCCESS;\r
320 goto Finish;\r
321 }\r
322 }\r
323\r
324 Status = STATUS_ERROR;\r
325\r
326Finish:\r
327 if (InFptr != NULL) {\r
328 fclose (InFptr);\r
329 }\r
330 //\r
331 // Close the output file. If there was an error, delete the output file so\r
332 // that a subsequent build will rebuild it.\r
333 //\r
334 if (OutFptr != NULL) {\r
335 fclose (OutFptr);\r
336 if (GetUtilityStatus () == STATUS_ERROR) {\r
337 remove (OutFileName);\r
338 }\r
339 }\r
340\r
341 //\r
342 // Free up our buffer\r
343 //\r
344 if (Buffer != NULL) {\r
345 free (Buffer);\r
346 }\r
347\r
348 return Status;\r
349}\r
350\r
351static\r
352STATUS\r
353CheckPE32File (\r
354 INT8 *FileName,\r
355 FILE *Fptr,\r
356 UINT16 *MachineType,\r
357 UINT16 *SubSystem\r
358 )\r
359/*++\r
360\r
361Routine Description:\r
362\r
363 GC_TODO: Add function description\r
364\r
365Arguments:\r
366\r
367 FileName - GC_TODO: add argument description\r
368 Fptr - GC_TODO: add argument description\r
369 MachineType - GC_TODO: add argument description\r
370 SubSystem - GC_TODO: add argument description\r
371\r
372Returns:\r
373\r
374 GC_TODO: add return values\r
375\r
376--*/\r
377{\r
378 /*++\r
379\r
380Routine Description:\r
381 \r
382 Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
383 PE32 image file, and then return the machine type in the supplied pointer.\r
384\r
385Arguments:\r
386\r
387 Fptr File pointer to the already-opened PE32 file\r
388 MachineType Location to stuff the machine type of the PE32 file. This is needed\r
389 because the image may be Itanium-based, IA32, or EBC.\r
390\r
391Returns:\r
392\r
393 0 success\r
394 non-zero otherwise\r
395\r
396--*/\r
397 EFI_IMAGE_DOS_HEADER DosHeader;\r
398 EFI_IMAGE_FILE_HEADER FileHdr;\r
399 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;\r
400 UINT32 PESig;\r
401 STATUS Status;\r
402\r
403 Status = STATUS_ERROR;\r
404 //\r
405 // Position to the start of the file\r
406 //\r
407 fseek (Fptr, 0, SEEK_SET);\r
408 //\r
409 // Read the DOS header\r
410 //\r
411 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
412 Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file");\r
413 goto Finish;\r
414 }\r
415 //\r
416 // Check the magic number (0x5A4D)\r
417 //\r
418 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
419 Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)");\r
420 goto Finish;\r
421 }\r
422 //\r
423 // Position into the file and check the PE signature\r
424 //\r
425 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
426 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {\r
427 Error (NULL, 0, 0, FileName, "failed to read PE signature bytes");\r
428 goto Finish;\r
429 }\r
430 //\r
431 // Check the PE signature in the header "PE\0\0"\r
432 //\r
433 if (PESig != EFI_IMAGE_NT_SIGNATURE) {\r
434 Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)");\r
435 goto Finish;\r
436 }\r
437 //\r
438 // Read the file header\r
439 //\r
440 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {\r
441 Error (NULL, 0, 0, FileName, "failed to read PE file header from input file");\r
442 goto Finish;\r
443 }\r
444 //\r
445 // Read the optional header so we can get the subsystem\r
446 //\r
447 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {\r
448 Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file");\r
449 goto Finish;\r
450 }\r
451\r
452 *SubSystem = OptionalHdr.Subsystem;\r
453 //\r
454 // Good to go\r
455 //\r
456 Status = STATUS_SUCCESS;\r
457Finish:\r
458 fseek (Fptr, 0, SEEK_SET);\r
459 return Status;\r
460}\r
461\r
462static\r
463int\r
464ParseCommandLine (\r
465 int Argc,\r
466 char *Argv[]\r
467 )\r
468/*++\r
469\r
470Routine Description:\r
471 \r
472 Given the Argc/Argv program arguments, and a pointer to an options structure,\r
473 parse the command-line options and check their validity.\r
474\r
475\r
476Arguments:\r
477\r
478 Argc - standard C main() argument count\r
479 Argv - standard C main() argument list\r
480\r
481Returns:\r
482\r
483 STATUS_SUCCESS success\r
484 non-zero otherwise\r
485\r
486--*/\r
487// GC_TODO: ] - add argument and description to function comment\r
488{\r
489 //\r
490 // Clear out the options\r
491 //\r
492 memset ((char *) &mOptions, 0, sizeof (mOptions));\r
493 //\r
494 // Skip over the program name\r
495 //\r
496 Argc--;\r
497 Argv++;\r
498\r
f091efb3 499 if (Argc < 1) {\r
500 Usage();\r
501 return STATUS_ERROR;\r
502 }\r
503 \r
504 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||\r
505 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {\r
506 Usage();\r
507 return STATUS_ERROR;\r
508 }\r
509 \r
510 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {\r
511 Version();\r
512 return STATUS_ERROR;\r
513 }\r
514\r
d25c4bf0 515 if (Argc != 2) {\r
516 Usage ();\r
517 return STATUS_ERROR;\r
518 }\r
519\r
520 strcpy (mOptions.InFileName, Argv[0]);\r
521 //\r
522 // Next argument\r
523 //\r
524 Argv++;\r
525 Argc--;\r
526\r
527 strcpy (mOptions.OutFileName, Argv[0]);\r
528\r
529 return STATUS_SUCCESS;\r
530}\r
531\r
f091efb3 532static\r
533void\r
534Version (\r
535 VOID\r
536 )\r
537{\r
538 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
539 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
540}\r
541\r
542\r
d25c4bf0 543static\r
544void\r
545Usage (\r
546 VOID\r
547 )\r
548/*++\r
549\r
550Routine Description:\r
551 \r
552 Print usage information for this utility.\r
553\r
554Arguments:\r
555\r
556 None.\r
557\r
558Returns:\r
559\r
560 Nothing.\r
561\r
562--*/\r
563{\r
564 int Index;\r
565 static const char *Msg[] = {\r
f091efb3 566 "\nUsage: "UTILITY_NAME " {-h|--help|-?|/?|-V|--version} InFileName OutFileName",\r
567 " where:",\r
568 " InFileName - name of the input PE32 file",\r
569 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION,\r
d25c4bf0 570 NULL\r
571 };\r
f091efb3 572 \r
573 Version();\r
d25c4bf0 574 for (Index = 0; Msg[Index] != NULL; Index++) {\r
575 fprintf (stdout, "%s\n", Msg[Index]);\r
576 }\r
577}\r