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
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.
18 A utility that extracts the .DATA section from a PE/COFF image.
26 #include <Common/UefiBaseTypes.h>
27 #include <Common/EfiImage.h> // for PE32 structure definitions
29 #include "CommonLib.h"
30 #include "EfiUtilityMsgs.h"
33 // Acpi Table definition
39 #include "MemoryMappedConfigurationSpaceAccessTable.h"
42 // Version of this utility
44 #define UTILITY_NAME "GenAcpiTable"
45 #define UTILITY_MAJOR_VERSION 0
46 #define UTILITY_MINOR_VERSION 11
49 // Define the max length of a filename
52 #define DEFAULT_OUTPUT_EXTENSION ".acpi"
55 // Use this to track our command-line options and globals
58 INT8 OutFileName
[MAX_PATH
];
59 INT8 InFileName
[MAX_PATH
];
63 // Use these to convert from machine type value to a named type
70 static STRING_LOOKUP mMachineTypes
[] = {
71 EFI_IMAGE_MACHINE_IA32
,
73 EFI_IMAGE_MACHINE_IA64
,
75 EFI_IMAGE_MACHINE_EBC
,
81 static STRING_LOOKUP mSubsystemTypes
[] = {
82 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
84 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
85 "EFI boot service driver",
86 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
92 // Function prototypes
153 Argc - standard C main() argument count
155 Argv - standard C main() argument list
163 // GC_TODO: ] - add argument and description to function comment
167 SetUtilityName (UTILITY_NAME
);
169 // Parse the command line arguments
171 if (ParseCommandLine (Argc
, Argv
)) {
175 // Make sure we don't have the same filename for input and output files
177 if (stricmp (mOptions
.OutFileName
, mOptions
.InFileName
) == 0) {
178 Error (NULL
, 0, 0, mOptions
.OutFileName
, "input and output file names must be different");
184 ProcessFile (mOptions
.InFileName
, mOptions
.OutFileName
);
186 Status
= GetUtilityStatus ();
200 Process a PE32 EFI file.
204 InFileName - Name of the PE32 EFI file to process.
205 OutFileName - Name of the output file for the processed data.
220 EFI_IMAGE_FILE_HEADER FileHeader
;
221 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32
;
222 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64
;
223 EFI_IMAGE_SECTION_HEADER SectionHeader
;
225 long SaveFilePosition
;
230 Status
= STATUS_ERROR
;
232 // Try to open the input file
234 if ((InFptr
= fopen (InFileName
, "rb")) == NULL
) {
235 Error (NULL
, 0, 0, InFileName
, "failed to open input file for reading");
239 // Double-check the file to make sure it's what we expect it to be
241 if (CheckPE32File (InFileName
, InFptr
, &MachineType
, &SubSystem
) != STATUS_SUCCESS
) {
245 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit
246 // offset (from the start of the file) to the PE signature, which always
247 // follows the MSDOS stub. The PE signature is immediately followed by the
251 if (fseek (InFptr
, 0x3C, SEEK_SET
) != 0) {
252 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature in file", NULL
);
256 if (fread (&PESigOffset
, sizeof (PESigOffset
), 1, InFptr
) != 1) {
257 Error (NULL
, 0, 0, InFileName
, "failed to read PE signature offset from file");
261 if (fseek (InFptr
, PESigOffset
+ 4, SEEK_SET
) != 0) {
262 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature");
266 // We should now be at the COFF file header. Read it in and verify it's
267 // of an image type we support.
269 if (fread (&FileHeader
, sizeof (EFI_IMAGE_FILE_HEADER
), 1, InFptr
) != 1) {
270 Error (NULL
, 0, 0, InFileName
, "failed to read file header from image");
274 if ((FileHeader
.Machine
!= EFI_IMAGE_MACHINE_IA32
) && (FileHeader
.Machine
!= EFI_IMAGE_MACHINE_IA64
) && (FileHeader
.Machine
!= EFI_IMAGE_MACHINE_X64
)) {
275 Error (NULL
, 0, 0, InFileName
, "image is of an unsupported machine type 0x%X", (UINT32
) FileHeader
.Machine
);
279 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+
281 SaveFilePosition
= ftell (InFptr
);
282 if (fread (&OptionalHeader32
, sizeof (EFI_IMAGE_OPTIONAL_HEADER32
), 1, InFptr
) != 1) {
283 Error (NULL
, 0, 0, InFileName
, "failed to read optional header from input file");
287 if (OptionalHeader32
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
288 if (fseek (InFptr
, SaveFilePosition
, SEEK_SET
) != 0) {
289 Error (NULL
, 0, 0, InFileName
, "failed to seek to .data section");
293 if (fread (&OptionalHeader64
, sizeof (EFI_IMAGE_OPTIONAL_HEADER64
), 1, InFptr
) != 1) {
294 Error (NULL
, 0, 0, InFileName
, "failed to read optional header from input file");
299 // Search for the ".data" section
301 for (Index
= 0; Index
< FileHeader
.NumberOfSections
; Index
++) {
302 if (fread (&SectionHeader
, sizeof (EFI_IMAGE_SECTION_HEADER
), 1, InFptr
) != 1) {
303 Error (NULL
, 0, 0, InFileName
, "failed to read optional header from input file");
307 if (strcmp (SectionHeader
.Name
, ".data") == 0 || strcmp (SectionHeader
.Name
, ".sdata") == 0) {
308 if (fseek (InFptr
, SectionHeader
.PointerToRawData
, SEEK_SET
) != 0) {
309 Error (NULL
, 0, 0, InFileName
, "failed to seek to .data section");
313 Buffer
= (UINT8
*) malloc (SectionHeader
.Misc
.VirtualSize
);
314 if (Buffer
== NULL
) {
315 Status
= EFI_OUT_OF_RESOURCES
;
318 if (fread (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, InFptr
) != 1) {
319 Error (NULL
, 0, 0, InFileName
, "failed to .data section");
326 if (CheckAcpiTable (Buffer
, SectionHeader
.Misc
.VirtualSize
) != STATUS_SUCCESS
) {
327 Error (NULL
, 0, 0, InFileName
, "failed to check ACPI table");
332 // Now open our output file
334 if ((OutFptr
= fopen (OutFileName
, "wb")) == NULL
) {
335 Error (NULL
, 0, 0, OutFileName
, "failed to open output file for writing");
339 if (fwrite (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, OutFptr
) != 1) {
340 Error (NULL
, 0, 0, OutFileName
, "failed to write .data section");
344 Status
= STATUS_SUCCESS
;
349 Status
= STATUS_ERROR
;
352 if (InFptr
!= NULL
) {
356 // Close the output file. If there was an error, delete the output file so
357 // that a subsequent build will rebuild it.
359 if (OutFptr
!= NULL
) {
361 if (GetUtilityStatus () == STATUS_ERROR
) {
362 remove (OutFileName
);
367 // Free up our buffer
369 if (Buffer
!= NULL
) {
390 AcpiTable Buffer for AcpiSection
391 Length AcpiSection Length
400 EFI_ACPI_DESCRIPTION_HEADER
*AcpiHeader
;
401 EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
402 UINT32 ExpectedLength
;
404 AcpiHeader
= (EFI_ACPI_DESCRIPTION_HEADER
*)AcpiTable
;
407 // Generic check for AcpiTable length.
409 if (AcpiHeader
->Length
> Length
) {
410 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass AcpiTable Length check");
415 // Currently, we only check must-have tables: FADT, FACS, DSDT,
416 // and some important tables: MADT, MCFG.
418 switch (AcpiHeader
->Signature
) {
421 // "FACP" Fixed ACPI Description Table
423 case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
:
424 switch (AcpiHeader
->Revision
) {
425 case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION
:
426 ExpectedLength
= sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE
);
428 case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION
:
429 ExpectedLength
= sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE
);
431 case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION
:
432 ExpectedLength
= sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE
);
435 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass FACP revision check");
438 if (ExpectedLength
!= AcpiHeader
->Length
) {
439 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass FACP Length check");
445 // "FACS" Firmware ACPI Control Structure
447 case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE
:
448 Facs
= (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*)AcpiTable
;
449 if ((Facs
->Version
!= 0) &&
450 (Facs
->Version
!= EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION
) &&
451 (Facs
->Version
!= EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION
)){
452 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass FACS version check");
455 if ((Facs
->Length
!= sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
)) &&
456 (Facs
->Length
!= sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
)) &&
457 (Facs
->Length
!= sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
))) {
458 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass FACS Length check");
464 // "DSDT" Differentiated System Description Table
466 case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
467 if (AcpiHeader
->Revision
> EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION
) {
468 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass DSDT revision check");
471 if (AcpiHeader
->Length
<= sizeof(EFI_ACPI_DESCRIPTION_HEADER
)) {
472 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass DSDT Length check");
478 // "APIC" Multiple APIC Description Table
480 case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE
:
481 if ((AcpiHeader
->Revision
!= EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
) &&
482 (AcpiHeader
->Revision
!= EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
) &&
483 (AcpiHeader
->Revision
!= EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
)) {
484 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass APIC revision check");
487 if (AcpiHeader
->Length
<= sizeof(EFI_ACPI_DESCRIPTION_HEADER
) + sizeof(UINT32
) + sizeof(UINT32
)) {
488 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass APIC Length check");
494 // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table
496 case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE
:
497 if (AcpiHeader
->Revision
!= EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION
) {
498 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass MCFG revision check");
501 if (AcpiHeader
->Length
<= sizeof(EFI_ACPI_DESCRIPTION_HEADER
) + sizeof(UINT64
)) {
502 Error (NULL
, 0, 0, "CheckAcpiTable", "failed to pass MCFG Length check");
508 // Other table pass check
514 return STATUS_SUCCESS
;
529 GC_TODO: Add function description
533 FileName - GC_TODO: add argument description
534 Fptr - GC_TODO: add argument description
535 MachineType - GC_TODO: add argument description
536 SubSystem - GC_TODO: add argument description
540 GC_TODO: add return values
548 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
549 PE32 image file, and then return the machine type in the supplied pointer.
553 Fptr File pointer to the already-opened PE32 file
554 MachineType Location to stuff the machine type of the PE32 file. This is needed
555 because the image may be Itanium-based, IA32, or EBC.
563 EFI_IMAGE_DOS_HEADER DosHeader
;
564 EFI_IMAGE_FILE_HEADER FileHdr
;
565 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
569 Status
= STATUS_ERROR
;
571 // Position to the start of the file
573 fseek (Fptr
, 0, SEEK_SET
);
575 // Read the DOS header
577 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
578 Error (NULL
, 0, 0, FileName
, "failed to read the DOS stub from the input file");
582 // Check the magic number (0x5A4D)
584 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
585 Error (NULL
, 0, 0, FileName
, "input file does not appear to be a PE32 image (magic number)");
589 // Position into the file and check the PE signature
591 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
592 if (fread (&PESig
, sizeof (PESig
), 1, Fptr
) != 1) {
593 Error (NULL
, 0, 0, FileName
, "failed to read PE signature bytes");
597 // Check the PE signature in the header "PE\0\0"
599 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
600 Error (NULL
, 0, 0, FileName
, "file does not appear to be a PE32 image (signature)");
604 // Read the file header
606 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
607 Error (NULL
, 0, 0, FileName
, "failed to read PE file header from input file");
611 // Read the optional header so we can get the subsystem
613 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
614 Error (NULL
, 0, 0, FileName
, "failed to read COFF optional header from input file");
618 *SubSystem
= OptionalHdr
.Subsystem
;
622 Status
= STATUS_SUCCESS
;
624 fseek (Fptr
, 0, SEEK_SET
);
638 Given the Argc/Argv program arguments, and a pointer to an options structure,
639 parse the command-line options and check their validity.
644 Argc - standard C main() argument count
645 Argv - standard C main() argument list
649 STATUS_SUCCESS success
653 // GC_TODO: ] - add argument and description to function comment
656 // Clear out the options
658 memset ((char *) &mOptions
, 0, sizeof (mOptions
));
660 // Skip over the program name
670 if ((strcmp(Argv
[0], "-h") == 0) || (strcmp(Argv
[0], "--help") == 0) ||
671 (strcmp(Argv
[0], "-?") == 0) || (strcmp(Argv
[0], "/?") == 0)) {
676 if ((strcmp(Argv
[0], "-V") == 0) || (strcmp(Argv
[0], "--version") == 0)) {
686 strcpy (mOptions
.InFileName
, Argv
[0]);
693 strcpy (mOptions
.OutFileName
, Argv
[0]);
695 return STATUS_SUCCESS
;
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
);
705 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
718 Print usage information for this utility.
731 static const char *Msg
[] = {
732 "\nUsage: "UTILITY_NAME
" {-h|--help|-?|/?|-V|--version} InFileName OutFileName",
734 " InFileName - name of the input PE32 file",
735 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION
,
740 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
741 fprintf (stdout
, "%s\n", Msg
[Index
]);