3 Copyright (c) 2002 Intel Corporation. All rights reserved
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
18 A utility that extracts the .DATA section from a PE/COFF image.
26 #include <UefiBaseTypes.h>
28 #include <CommonLib.h>
29 #include "EfiImage.h" // for PE32 structure definitions
30 #include "EfiUtilityMsgs.h"
33 // Version of this utility
35 #define UTILITY_NAME "GenAcpiTable"
36 #define UTILITY_VERSION "v0.11"
39 // Define the max length of a filename
42 #define DEFAULT_OUTPUT_EXTENSION ".acpi"
45 // Use this to track our command-line options and globals
48 INT8 OutFileName
[MAX_PATH
];
49 INT8 InFileName
[MAX_PATH
];
53 // Use these to convert from machine type value to a named type
60 static STRING_LOOKUP mMachineTypes
[] = {
61 EFI_IMAGE_MACHINE_IA32
,
63 EFI_IMAGE_MACHINE_IA64
,
65 EFI_IMAGE_MACHINE_EBC
,
71 static STRING_LOOKUP mSubsystemTypes
[] = {
72 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
74 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
75 "EFI boot service driver",
76 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
82 // Function prototypes
130 Argc - standard C main() argument count
132 Argv - standard C main() argument list
140 // GC_TODO: ] - add argument and description to function comment
144 SetUtilityName (UTILITY_NAME
);
146 // Parse the command line arguments
148 if (ParseCommandLine (Argc
, Argv
)) {
152 // Make sure we don't have the same filename for input and output files
154 if (stricmp (mOptions
.OutFileName
, mOptions
.InFileName
) == 0) {
155 Error (NULL
, 0, 0, mOptions
.OutFileName
, "input and output file names must be different");
161 ProcessFile (mOptions
.InFileName
, mOptions
.OutFileName
);
163 Status
= GetUtilityStatus ();
177 Process a PE32 EFI file.
181 InFileName - Name of the PE32 EFI file to process.
182 OutFileName - Name of the output file for the processed data.
197 EFI_IMAGE_FILE_HEADER FileHeader
;
198 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32
;
199 EFI_IMAGE_SECTION_HEADER SectionHeader
;
201 long SaveFilePosition
;
206 Status
= STATUS_ERROR
;
208 // Try to open the input file
210 if ((InFptr
= fopen (InFileName
, "rb")) == NULL
) {
211 Error (NULL
, 0, 0, InFileName
, "failed to open input file for reading");
215 // Double-check the file to make sure it's what we expect it to be
217 if (CheckPE32File (InFileName
, InFptr
, &MachineType
, &SubSystem
) != STATUS_SUCCESS
) {
221 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit
222 // offset (from the start of the file) to the PE signature, which always
223 // follows the MSDOS stub. The PE signature is immediately followed by the
227 if (fseek (InFptr
, 0x3C, SEEK_SET
) != 0) {
228 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature in file", NULL
);
232 if (fread (&PESigOffset
, sizeof (PESigOffset
), 1, InFptr
) != 1) {
233 Error (NULL
, 0, 0, InFileName
, "failed to read PE signature offset from file");
237 if (fseek (InFptr
, PESigOffset
+ 4, SEEK_SET
) != 0) {
238 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature");
242 // We should now be at the COFF file header. Read it in and verify it's
243 // of an image type we support.
245 if (fread (&FileHeader
, sizeof (EFI_IMAGE_FILE_HEADER
), 1, InFptr
) != 1) {
246 Error (NULL
, 0, 0, InFileName
, "failed to read file header from image");
250 if ((FileHeader
.Machine
!= EFI_IMAGE_MACHINE_IA32
) && (FileHeader
.Machine
!= EFI_IMAGE_MACHINE_IA64
) && (FileHeader
.Machine
!= EFI_IMAGE_MACHINE_X64
)) {
251 Error (NULL
, 0, 0, InFileName
, "image is of an unsupported machine type 0x%X", (UINT32
) FileHeader
.Machine
);
255 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+
257 SaveFilePosition
= ftell (InFptr
);
258 if (fread (&OptionalHeader32
, sizeof (EFI_IMAGE_OPTIONAL_HEADER32
), 1, InFptr
) != 1) {
259 Error (NULL
, 0, 0, InFileName
, "failed to read optional header from input file");
263 if (OptionalHeader32
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
264 if (fseek (InFptr
, SaveFilePosition
, SEEK_SET
) != 0) {
265 Error (NULL
, 0, 0, InFileName
, "failed to seek to .data section");
269 if (fread (&OptionalHeader32
, sizeof (EFI_IMAGE_OPTIONAL_HEADER64
), 1, InFptr
) != 1) {
270 Error (NULL
, 0, 0, InFileName
, "failed to read optional header from input file");
275 // Search for the ".data" section
277 for (Index
= 0; Index
< FileHeader
.NumberOfSections
; Index
++) {
278 if (fread (&SectionHeader
, sizeof (EFI_IMAGE_SECTION_HEADER
), 1, InFptr
) != 1) {
279 Error (NULL
, 0, 0, InFileName
, "failed to read optional header from input file");
283 if (strcmp (SectionHeader
.Name
, ".data") == 0) {
284 if (fseek (InFptr
, SectionHeader
.PointerToRawData
, SEEK_SET
) != 0) {
285 Error (NULL
, 0, 0, InFileName
, "failed to seek to .data section");
289 Buffer
= (UINT8
*) malloc (SectionHeader
.Misc
.VirtualSize
);
290 if (Buffer
== NULL
) {
291 Status
= EFI_OUT_OF_RESOURCES
;
294 if (fread (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, InFptr
) != 1) {
295 Error (NULL
, 0, 0, InFileName
, "failed to .data section");
299 // Now open our output file
301 if ((OutFptr
= fopen (OutFileName
, "wb")) == NULL
) {
302 Error (NULL
, 0, 0, OutFileName
, "failed to open output file for writing");
306 if (fwrite (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, OutFptr
) != 1) {
307 Error (NULL
, 0, 0, OutFileName
, "failed to write .data section");
311 Status
= STATUS_SUCCESS
;
316 Status
= STATUS_ERROR
;
319 if (InFptr
!= NULL
) {
323 // Close the output file. If there was an error, delete the output file so
324 // that a subsequent build will rebuild it.
326 if (OutFptr
!= NULL
) {
328 if (GetUtilityStatus () == STATUS_ERROR
) {
329 remove (OutFileName
);
334 // Free up our buffer
336 if (Buffer
!= NULL
) {
355 GC_TODO: Add function description
359 FileName - GC_TODO: add argument description
360 Fptr - GC_TODO: add argument description
361 MachineType - GC_TODO: add argument description
362 SubSystem - GC_TODO: add argument description
366 GC_TODO: add return values
374 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
375 PE32 image file, and then return the machine type in the supplied pointer.
379 Fptr File pointer to the already-opened PE32 file
380 MachineType Location to stuff the machine type of the PE32 file. This is needed
381 because the image may be Itanium-based, IA32, or EBC.
389 EFI_IMAGE_DOS_HEADER DosHeader
;
390 EFI_IMAGE_FILE_HEADER FileHdr
;
391 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
395 Status
= STATUS_ERROR
;
397 // Position to the start of the file
399 fseek (Fptr
, 0, SEEK_SET
);
401 // Read the DOS header
403 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
404 Error (NULL
, 0, 0, FileName
, "failed to read the DOS stub from the input file");
408 // Check the magic number (0x5A4D)
410 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
411 Error (NULL
, 0, 0, FileName
, "input file does not appear to be a PE32 image (magic number)");
415 // Position into the file and check the PE signature
417 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
418 if (fread (&PESig
, sizeof (PESig
), 1, Fptr
) != 1) {
419 Error (NULL
, 0, 0, FileName
, "failed to read PE signature bytes");
423 // Check the PE signature in the header "PE\0\0"
425 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
426 Error (NULL
, 0, 0, FileName
, "file does not appear to be a PE32 image (signature)");
430 // Read the file header
432 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
433 Error (NULL
, 0, 0, FileName
, "failed to read PE file header from input file");
437 // Read the optional header so we can get the subsystem
439 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
440 Error (NULL
, 0, 0, FileName
, "failed to read COFF optional header from input file");
444 *SubSystem
= OptionalHdr
.Subsystem
;
448 Status
= STATUS_SUCCESS
;
450 fseek (Fptr
, 0, SEEK_SET
);
464 Given the Argc/Argv program arguments, and a pointer to an options structure,
465 parse the command-line options and check their validity.
470 Argc - standard C main() argument count
471 Argv - standard C main() argument list
475 STATUS_SUCCESS success
479 // GC_TODO: ] - add argument and description to function comment
482 // Clear out the options
484 memset ((char *) &mOptions
, 0, sizeof (mOptions
));
486 // Skip over the program name
496 strcpy (mOptions
.InFileName
, Argv
[0]);
503 strcpy (mOptions
.OutFileName
, Argv
[0]);
505 return STATUS_SUCCESS
;
517 Print usage information for this utility.
530 static const char *Msg
[] = {
531 UTILITY_NAME
" version "UTILITY_VERSION
" - Generate ACPI Table image utility",
532 " Generate an ACPI Table image from an EFI PE32 image",
533 " Usage: "UTILITY_NAME
" InFileName OutFileName",
535 " InFileName - name of the input PE32 file",
536 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION
,
540 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
541 fprintf (stdout
, "%s\n", Msg
[Index
]);