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