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