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_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_OPTIONAL_HEADER64 OptionalHeader64
;
200 EFI_IMAGE_SECTION_HEADER SectionHeader
;
202 long SaveFilePosition
;
207 Status
= STATUS_ERROR
;
209 // Try to open the input file
211 if ((InFptr
= fopen (InFileName
, "rb")) == NULL
) {
212 Error (NULL
, 0, 0, InFileName
, "failed to open input file for reading");
216 // Double-check the file to make sure it's what we expect it to be
218 if (CheckPE32File (InFileName
, InFptr
, &MachineType
, &SubSystem
) != STATUS_SUCCESS
) {
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
228 if (fseek (InFptr
, 0x3C, SEEK_SET
) != 0) {
229 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature in file", NULL
);
233 if (fread (&PESigOffset
, sizeof (PESigOffset
), 1, InFptr
) != 1) {
234 Error (NULL
, 0, 0, InFileName
, "failed to read PE signature offset from file");
238 if (fseek (InFptr
, PESigOffset
+ 4, SEEK_SET
) != 0) {
239 Error (NULL
, 0, 0, InFileName
, "failed to seek to PE signature");
243 // We should now be at the COFF file header. Read it in and verify it's
244 // of an image type we support.
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");
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
);
256 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+
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");
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");
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");
276 // Search for the ".data" section
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");
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");
290 Buffer
= (UINT8
*) malloc (SectionHeader
.Misc
.VirtualSize
);
291 if (Buffer
== NULL
) {
292 Status
= EFI_OUT_OF_RESOURCES
;
295 if (fread (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, InFptr
) != 1) {
296 Error (NULL
, 0, 0, InFileName
, "failed to .data section");
300 // Now open our output file
302 if ((OutFptr
= fopen (OutFileName
, "wb")) == NULL
) {
303 Error (NULL
, 0, 0, OutFileName
, "failed to open output file for writing");
307 if (fwrite (Buffer
, SectionHeader
.Misc
.VirtualSize
, 1, OutFptr
) != 1) {
308 Error (NULL
, 0, 0, OutFileName
, "failed to write .data section");
312 Status
= STATUS_SUCCESS
;
317 Status
= STATUS_ERROR
;
320 if (InFptr
!= NULL
) {
324 // Close the output file. If there was an error, delete the output file so
325 // that a subsequent build will rebuild it.
327 if (OutFptr
!= NULL
) {
329 if (GetUtilityStatus () == STATUS_ERROR
) {
330 remove (OutFileName
);
335 // Free up our buffer
337 if (Buffer
!= NULL
) {
356 GC_TODO: Add function description
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
367 GC_TODO: add return values
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.
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.
390 EFI_IMAGE_DOS_HEADER DosHeader
;
391 EFI_IMAGE_FILE_HEADER FileHdr
;
392 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
396 Status
= STATUS_ERROR
;
398 // Position to the start of the file
400 fseek (Fptr
, 0, SEEK_SET
);
402 // Read the DOS header
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");
409 // Check the magic number (0x5A4D)
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)");
416 // Position into the file and check the PE signature
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");
424 // Check the PE signature in the header "PE\0\0"
426 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
427 Error (NULL
, 0, 0, FileName
, "file does not appear to be a PE32 image (signature)");
431 // Read the file header
433 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
434 Error (NULL
, 0, 0, FileName
, "failed to read PE file header from input file");
438 // Read the optional header so we can get the subsystem
440 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
441 Error (NULL
, 0, 0, FileName
, "failed to read COFF optional header from input file");
445 *SubSystem
= OptionalHdr
.Subsystem
;
449 Status
= STATUS_SUCCESS
;
451 fseek (Fptr
, 0, SEEK_SET
);
465 Given the Argc/Argv program arguments, and a pointer to an options structure,
466 parse the command-line options and check their validity.
471 Argc - standard C main() argument count
472 Argv - standard C main() argument list
476 STATUS_SUCCESS success
480 // GC_TODO: ] - add argument and description to function comment
483 // Clear out the options
485 memset ((char *) &mOptions
, 0, sizeof (mOptions
));
487 // Skip over the program name
497 strcpy (mOptions
.InFileName
, Argv
[0]);
504 strcpy (mOptions
.OutFileName
, Argv
[0]);
506 return STATUS_SUCCESS
;
518 Print usage information for this utility.
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",
536 " InFileName - name of the input PE32 file",
537 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION
,
541 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
542 fprintf (stdout
, "%s\n", Msg
[Index
]);