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 // Version of this utility
35 #define UTILITY_NAME "GenAcpiTable"
36 #define UTILITY_MAJOR_VERSION 0
37 #define UTILITY_MINOR_VERSION 11
40 // Define the max length of a filename
43 #define DEFAULT_OUTPUT_EXTENSION ".acpi"
46 // Use this to track our command-line options and globals
49 INT8 OutFileName
[MAX_PATH
];
50 INT8 InFileName
[MAX_PATH
];
54 // Use these to convert from machine type value to a named type
61 static STRING_LOOKUP mMachineTypes
[] = {
62 EFI_IMAGE_MACHINE_IA32
,
64 EFI_IMAGE_MACHINE_IA64
,
66 EFI_IMAGE_MACHINE_EBC
,
72 static STRING_LOOKUP mSubsystemTypes
[] = {
73 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
75 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
76 "EFI boot service driver",
77 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
83 // Function prototypes
137 Argc - standard C main() argument count
139 Argv - standard C main() argument list
147 // GC_TODO: ] - add argument and description to function comment
151 SetUtilityName (UTILITY_NAME
);
153 // Parse the command line arguments
155 if (ParseCommandLine (Argc
, Argv
)) {
159 // Make sure we don't have the same filename for input and output files
161 if (stricmp (mOptions
.OutFileName
, mOptions
.InFileName
) == 0) {
162 Error (NULL
, 0, 0, mOptions
.OutFileName
, "input and output file names must be different");
168 ProcessFile (mOptions
.InFileName
, mOptions
.OutFileName
);
170 Status
= GetUtilityStatus ();
184 Process a PE32 EFI file.
188 InFileName - Name of the PE32 EFI file to process.
189 OutFileName - Name of the output file for the processed data.
204 EFI_IMAGE_FILE_HEADER FileHeader
;
205 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32
;
206 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64
;
207 EFI_IMAGE_SECTION_HEADER SectionHeader
;
209 long SaveFilePosition
;
214 Status
= STATUS_ERROR
;
216 // Try to open the input file
218 if ((InFptr
= fopen (InFileName
, "rb")) == NULL
) {
219 Error (NULL
, 0, 0, InFileName
, "failed to open input file for reading");
223 // Double-check the file to make sure it's what we expect it to be
225 if (CheckPE32File (InFileName
, InFptr
, &MachineType
, &SubSystem
) != STATUS_SUCCESS
) {
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
235 if (fseek (InFptr
, 0x3C, SEEK_SET
) != 0) {
236 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature in file", NULL
);
240 if (fread (&PESigOffset
, sizeof (PESigOffset
), 1, InFptr
) != 1) {
241 Error (NULL
, 0, 0, InFileName
, "failed to read PE signature offset from file");
245 if (fseek (InFptr
, PESigOffset
+ 4, SEEK_SET
) != 0) {
246 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature");
250 // We should now be at the COFF file header. Read it in and verify it's
251 // of an image type we support.
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");
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
);
263 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+
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");
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");
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");
283 // Search for the ".data" section
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");
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");
297 Buffer
= (UINT8
*) malloc (SectionHeader
.Misc
.VirtualSize
);
298 if (Buffer
== NULL
) {
299 Status
= EFI_OUT_OF_RESOURCES
;
302 if (fread (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, InFptr
) != 1) {
303 Error (NULL
, 0, 0, InFileName
, "failed to .data section");
307 // Now open our output file
309 if ((OutFptr
= fopen (OutFileName
, "wb")) == NULL
) {
310 Error (NULL
, 0, 0, OutFileName
, "failed to open output file for writing");
314 if (fwrite (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, OutFptr
) != 1) {
315 Error (NULL
, 0, 0, OutFileName
, "failed to write .data section");
319 Status
= STATUS_SUCCESS
;
324 Status
= STATUS_ERROR
;
327 if (InFptr
!= NULL
) {
331 // Close the output file. If there was an error, delete the output file so
332 // that a subsequent build will rebuild it.
334 if (OutFptr
!= NULL
) {
336 if (GetUtilityStatus () == STATUS_ERROR
) {
337 remove (OutFileName
);
342 // Free up our buffer
344 if (Buffer
!= NULL
) {
363 GC_TODO: Add function description
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
374 GC_TODO: add return values
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.
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.
397 EFI_IMAGE_DOS_HEADER DosHeader
;
398 EFI_IMAGE_FILE_HEADER FileHdr
;
399 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
403 Status
= STATUS_ERROR
;
405 // Position to the start of the file
407 fseek (Fptr
, 0, SEEK_SET
);
409 // Read the DOS header
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");
416 // Check the magic number (0x5A4D)
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)");
423 // Position into the file and check the PE signature
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");
431 // Check the PE signature in the header "PE\0\0"
433 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
434 Error (NULL
, 0, 0, FileName
, "file does not appear to be a PE32 image (signature)");
438 // Read the file header
440 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
441 Error (NULL
, 0, 0, FileName
, "failed to read PE file header from input file");
445 // Read the optional header so we can get the subsystem
447 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
448 Error (NULL
, 0, 0, FileName
, "failed to read COFF optional header from input file");
452 *SubSystem
= OptionalHdr
.Subsystem
;
456 Status
= STATUS_SUCCESS
;
458 fseek (Fptr
, 0, SEEK_SET
);
472 Given the Argc/Argv program arguments, and a pointer to an options structure,
473 parse the command-line options and check their validity.
478 Argc - standard C main() argument count
479 Argv - standard C main() argument list
483 STATUS_SUCCESS success
487 // GC_TODO: ] - add argument and description to function comment
490 // Clear out the options
492 memset ((char *) &mOptions
, 0, sizeof (mOptions
));
494 // Skip over the program name
504 if ((strcmp(Argv
[0], "-h") == 0) || (strcmp(Argv
[0], "--help") == 0) ||
505 (strcmp(Argv
[0], "-?") == 0) || (strcmp(Argv
[0], "/?") == 0)) {
510 if ((strcmp(Argv
[0], "-V") == 0) || (strcmp(Argv
[0], "--version") == 0)) {
520 strcpy (mOptions
.InFileName
, Argv
[0]);
527 strcpy (mOptions
.OutFileName
, Argv
[0]);
529 return STATUS_SUCCESS
;
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");
552 Print usage information for this utility.
565 static const char *Msg
[] = {
566 "\nUsage: "UTILITY_NAME
" {-h|--help|-?|/?|-V|--version} InFileName OutFileName",
568 " InFileName - name of the input PE32 file",
569 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION
,
574 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
575 fprintf (stdout
, "%s\n", Msg
[Index
]);