2 Utility program to create an EFI option ROM image from binary and EFI PE32 files.
4 Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "EfiUtilityMsgs.h"
19 UINT64 DebugLevel
= 0;
30 Given an EFI image filename, create a ROM-able image by creating an option
31 ROM header and PCI data structure, filling them in, and then writing the
32 option ROM header + PCI data structure + EFI image out to the output file.
36 Argc - standard C main() argument count
38 Argv - standard C main() argument list
55 SetUtilityName(UTILITY_NAME
);
57 Status
= STATUS_SUCCESS
;
61 // Parse the command line arguments
63 if (ParseCommandLine (Argc
, Argv
, &mOptions
)) {
69 } else if (mOptions
.Verbose
) {
71 } else if (mOptions
.Debug
) {
72 SetPrintLevel(DebugLevel
);
75 if (mOptions
.Verbose
) {
76 VerboseMsg("%s tool start.\n", UTILITY_NAME
);
80 // If dumping an image, then do that and quit
82 if (mOptions
.DumpOption
== 1) {
83 if (mOptions
.FileList
!= NULL
) {
84 if ((Ptr0
= strstr ((CONST CHAR8
*) mOptions
.FileList
->FileName
, DEFAULT_OUTPUT_EXTENSION
)) != NULL
) {
85 DumpImage (mOptions
.FileList
);
88 Error (NULL
, 0, 1002, "No PciRom input file", "No *.rom input file");
94 // Determine the output filename. Either what they specified on
95 // the command line, or the first input filename with a different extension.
97 if (!mOptions
.OutFileName
[0]) {
98 if (mOptions
.FileList
!= NULL
) {
99 strcpy (mOptions
.OutFileName
, mOptions
.FileList
->FileName
);
101 // Find the last . on the line and replace the filename extension with
104 for (Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
) - 1;
105 (Ext
>= mOptions
.OutFileName
) && (*Ext
!= '.') && (*Ext
!= '\\');
110 // If dot here, then insert extension here, otherwise append
113 Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
);
116 strcpy (Ext
, DEFAULT_OUTPUT_EXTENSION
);
120 // Make sure we don't have the same filename for input and output files
122 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
123 if (stricmp (mOptions
.OutFileName
, FList
->FileName
) == 0) {
124 Status
= STATUS_ERROR
;
125 Error (NULL
, 0, 1002, "Invalid input parameter", "Input and output file names must be different - %s = %s.", FList
->FileName
, mOptions
.OutFileName
);
130 // Now open our output file
132 if ((FptrOut
= fopen (LongFilePath (mOptions
.OutFileName
), "wb")) == NULL
) {
133 Error (NULL
, 0, 0001, "Error opening file", "Error opening file %s", mOptions
.OutFileName
);
137 // Process all our files
140 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
142 if ((FList
->FileFlags
& FILE_FLAG_EFI
) != 0) {
143 if (mOptions
.Verbose
) {
144 VerboseMsg("Processing EFI file %s\n", FList
->FileName
);
147 Status
= ProcessEfiFile (FptrOut
, FList
, mOptions
.VendId
, mOptions
.DevId
, &Size
);
148 } else if ((FList
->FileFlags
& FILE_FLAG_BINARY
) !=0 ) {
149 if (mOptions
.Verbose
) {
150 VerboseMsg("Processing binary file %s\n", FList
->FileName
);
153 Status
= ProcessBinFile (FptrOut
, FList
, &Size
);
155 Error (NULL
, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList
->FileName
);
156 Status
= STATUS_ERROR
;
159 if (mOptions
.Verbose
) {
160 VerboseMsg(" Output size = 0x%X\n", (unsigned) Size
);
163 if (Status
!= STATUS_SUCCESS
) {
172 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
173 Error (NULL
, 0, 2000, "Invalid parameter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE
);
174 Status
= STATUS_ERROR
;
178 if (Status
== STATUS_SUCCESS
) {
180 // Clean up our file list
182 while (mOptions
.FileList
!= NULL
) {
183 FList
= mOptions
.FileList
->Next
;
184 free (mOptions
.FileList
);
185 mOptions
.FileList
= FList
;
189 if (FptrOut
!= NULL
) {
193 if (mOptions
.Verbose
) {
194 VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME
, GetUtilityStatus ());
197 return GetUtilityStatus ();
211 Process a binary input file.
215 OutFptr - file pointer to output binary ROM image file we're creating
216 InFile - structure contains information on the binary file to process
217 Size - pointer to where to return the size added to the output file
230 PCI_EXPANSION_ROM_HEADER
*RomHdr
;
231 PCI_DATA_STRUCTURE
*PciDs23
;
232 PCI_3_0_DATA_STRUCTURE
*PciDs30
;
239 Status
= STATUS_SUCCESS
;
242 // Try to open the input file
244 if ((InFptr
= fopen (LongFilePath (InFile
->FileName
), "rb")) == NULL
) {
245 Error (NULL
, 0, 0001, "Error opening file", InFile
->FileName
);
249 // Seek to the end of the input file and get the file size. Then allocate
250 // a buffer to read it in to.
252 fseek (InFptr
, 0, SEEK_END
);
253 FileSize
= ftell (InFptr
);
254 if (mOptions
.Verbose
) {
255 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize
);
258 fseek (InFptr
, 0, SEEK_SET
);
259 Buffer
= (UINT8
*) malloc (FileSize
);
260 if (Buffer
== NULL
) {
261 Error (NULL
, 0, 4003, "Resource", "memory cannot be allocated!");
262 Status
= STATUS_ERROR
;
266 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
267 Error (NULL
, 0, 2000, "Invalid", "Failed to read all bytes from input file.");
268 Status
= STATUS_ERROR
;
272 // Total size must be an even multiple of 512 bytes, and can't exceed
273 // the option ROM image size.
275 TotalSize
= FileSize
;
276 if (TotalSize
& 0x1FF) {
277 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
280 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
281 Error (NULL
, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile
->FileName
, MAX_OPTION_ROM_SIZE
);
282 Status
= STATUS_ERROR
;
286 // Return the size to the caller so they can keep track of the running total.
291 // Crude check to make sure it's a legitimate ROM image
293 RomHdr
= (PCI_EXPANSION_ROM_HEADER
*) Buffer
;
294 if (RomHdr
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
295 Error (NULL
, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");
296 Status
= STATUS_ERROR
;
300 // Make sure the pointer to the PCI data structure is within the size of the image.
301 // Then check it for valid signature.
303 if ((RomHdr
->PcirOffset
> FileSize
) || (RomHdr
->PcirOffset
== 0)) {
304 Error (NULL
, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");
305 Status
= STATUS_ERROR
;
310 // Check the header is conform to PCI2.3 or PCI3.0
312 if (mOptions
.Pci23
== 1) {
313 PciDs23
= (PCI_DATA_STRUCTURE
*) (Buffer
+ RomHdr
->PcirOffset
);
314 if (PciDs23
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
315 Error (NULL
, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
316 Status
= STATUS_ERROR
;
321 // Default setting is PCI3.0 header
323 PciDs30
= (PCI_3_0_DATA_STRUCTURE
*)(Buffer
+ RomHdr
->PcirOffset
);
324 if (PciDs30
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
325 Error (NULL
, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
326 Status
= STATUS_ERROR
;
332 // ReSet Option Rom size
334 if (mOptions
.Pci23
== 1) {
335 PciDs23
->ImageLength
= (UINT16
) (TotalSize
/ 512);
336 CodeType
= PciDs23
->CodeType
;
338 PciDs30
->ImageLength
= (UINT16
) (TotalSize
/ 512);
339 CodeType
= PciDs30
->CodeType
;
343 // If this is the last image, then set the LAST bit unless requested not
344 // to via the command-line -n argument. Otherwise, make sure you clear it.
346 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
347 if (mOptions
.Pci23
== 1) {
348 PciDs23
->Indicator
= INDICATOR_LAST
;
350 PciDs30
->Indicator
= INDICATOR_LAST
;
353 if (mOptions
.Pci23
== 1) {
354 PciDs23
->Indicator
= 0;
356 PciDs30
->Indicator
= 0;
360 if (CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
362 for (Index
= 0; Index
< FileSize
- 1; Index
++) {
363 ByteCheckSum
= (UINT8
) (ByteCheckSum
+ Buffer
[Index
]);
366 Buffer
[FileSize
- 1] = (UINT8
) ((~ByteCheckSum
) + 1);
367 if (mOptions
.Verbose
) {
368 VerboseMsg(" Checksum = %02x\n\n", Buffer
[FileSize
- 1]);
373 // Now copy the input file contents out to the output file
375 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
376 Error (NULL
, 0, 0005, "Failed to write all file bytes to output file.", NULL
);
377 Status
= STATUS_ERROR
;
381 TotalSize
-= FileSize
;
383 // Pad the rest of the image to make it a multiple of 512 bytes
385 while (TotalSize
> 0) {
391 if (InFptr
!= NULL
) {
395 if (Buffer
!= NULL
) {
399 // Print the file name if errors occurred
401 if (Status
!= STATUS_SUCCESS
) {
402 Error (NULL
, 0, 0003, "Error", "Error parsing file: %s", InFile
->FileName
);
421 Process a PE32 EFI file.
425 OutFptr - file pointer to output binary ROM image file we're creating
426 InFile - structure contains information on the PE32 file to process
427 VendId - vendor ID as required in the option ROM header
428 DevId - device ID as required in the option ROM header
429 Size - pointer to where to return the size added to the output file
439 EFI_PCI_EXPANSION_ROM_HEADER RomHdr
;
440 PCI_DATA_STRUCTURE PciDs23
;
441 PCI_3_0_DATA_STRUCTURE PciDs30
;
443 UINT32 CompressedFileSize
;
445 UINT8
*CompressedBuffer
;
446 UINT8
*TempBufferPtr
;
451 UINT32 HeaderPadBytes
;
452 UINT32 PadBytesBeforeImage
;
453 UINT32 PadBytesAfterImage
;
456 // Try to open the input file
458 if ((InFptr
= fopen (LongFilePath (InFile
->FileName
), "rb")) == NULL
) {
459 Error (NULL
, 0, 0001, "Open file error", "Error opening file: %s", InFile
->FileName
);
463 // Initialize our buffer pointers to null.
466 CompressedBuffer
= NULL
;
469 // Double-check the file to make sure it's what we expect it to be
471 Status
= CheckPE32File (InFptr
, &MachineType
, &SubSystem
);
472 if (Status
!= STATUS_SUCCESS
) {
476 // Seek to the end of the input file and get the file size
478 fseek (InFptr
, 0, SEEK_END
);
479 FileSize
= ftell (InFptr
);
482 // Get the size of the headers we're going to put in front of the image. The
483 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
485 if (sizeof (RomHdr
) & 0x03) {
486 HeaderPadBytes
= 4 - (sizeof (RomHdr
) & 0x03);
492 // For Pci3.0 to use the different data structure.
494 if (mOptions
.Pci23
== 1) {
495 HeaderSize
= sizeof (PCI_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
497 HeaderSize
= sizeof (PCI_3_0_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
500 if (mOptions
.Verbose
) {
501 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize
);
504 // Allocate memory for the entire file (in case we have to compress), then
505 // seek back to the beginning of the file and read it into our buffer.
507 Buffer
= (UINT8
*) malloc (FileSize
);
508 if (Buffer
== NULL
) {
509 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
510 Status
= STATUS_ERROR
;
514 fseek (InFptr
, 0, SEEK_SET
);
515 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
516 Error (NULL
, 0, 0004, "Error reading file", "File %s", InFile
->FileName
);
517 Status
= STATUS_ERROR
;
521 // Now determine the size of the final output file. It's either the header size
522 // plus the file's size, or the header size plus the compressed file size.
524 if ((InFile
->FileFlags
& FILE_FLAG_COMPRESS
) != 0) {
526 // Allocate a buffer into which we can compress the image, compress it,
527 // and use that size as the new size.
529 CompressedBuffer
= (UINT8
*) malloc (FileSize
);
530 if (CompressedBuffer
== NULL
) {
531 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
532 Status
= STATUS_ERROR
;
536 CompressedFileSize
= FileSize
;
537 Status
= EfiCompress (Buffer
, FileSize
, CompressedBuffer
, &CompressedFileSize
);
538 if (Status
!= STATUS_SUCCESS
) {
539 Error (NULL
, 0, 0007, "Error compressing file!", NULL
);
543 // Now compute the size, then swap buffer pointers.
545 if (mOptions
.Verbose
) {
546 VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize
);
549 TotalSize
= CompressedFileSize
+ HeaderSize
;
550 FileSize
= CompressedFileSize
;
551 TempBufferPtr
= Buffer
;
552 Buffer
= CompressedBuffer
;
553 CompressedBuffer
= TempBufferPtr
;
555 TotalSize
= FileSize
+ HeaderSize
;
558 // Total size must be an even multiple of 512 bytes
560 if (TotalSize
& 0x1FF) {
561 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
565 // If compressed, put the pad bytes after the image,
566 // else put the pad bytes before the image.
568 if ((InFile
->FileFlags
& FILE_FLAG_COMPRESS
) != 0) {
569 PadBytesBeforeImage
= 0;
570 PadBytesAfterImage
= TotalSize
- (FileSize
+ HeaderSize
);
572 PadBytesBeforeImage
= TotalSize
- (FileSize
+ HeaderSize
);
573 PadBytesAfterImage
= 0;
578 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
579 Error (NULL
, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile
->FileName
, MAX_OPTION_ROM_SIZE
);
580 Status
= STATUS_ERROR
;
584 // Return the size to the caller so they can keep track of the running total.
589 // Now fill in the ROM header. These values come from chapter 18 of the
590 // EFI 1.02 specification.
592 memset (&RomHdr
, 0, sizeof (RomHdr
));
593 RomHdr
.Signature
= PCI_EXPANSION_ROM_HEADER_SIGNATURE
;
594 RomHdr
.InitializationSize
= (UINT16
) (TotalSize
/ 512);
595 RomHdr
.EfiSignature
= EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
;
596 RomHdr
.EfiSubsystem
= SubSystem
;
597 RomHdr
.EfiMachineType
= MachineType
;
598 RomHdr
.EfiImageHeaderOffset
= (UINT16
) (HeaderSize
+ PadBytesBeforeImage
);
599 RomHdr
.PcirOffset
= (UINT16
) (sizeof (RomHdr
) + HeaderPadBytes
);
601 // Set image as compressed or not
603 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
604 RomHdr
.CompressionType
= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
;
607 // Fill in the PCI data structure
609 if (mOptions
.Pci23
== 1) {
610 memset (&PciDs23
, 0, sizeof (PCI_DATA_STRUCTURE
));
612 memset (&PciDs30
, 0, sizeof (PCI_3_0_DATA_STRUCTURE
));
615 if (mOptions
.Pci23
== 1) {
616 PciDs23
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
617 PciDs23
.VendorId
= VendId
;
618 PciDs23
.DeviceId
= DevId
;
619 PciDs23
.Length
= (UINT16
) sizeof (PCI_DATA_STRUCTURE
);
620 PciDs23
.Revision
= 0;
622 // Class code and code revision from the command line (optional)
624 PciDs23
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
625 PciDs23
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
626 PciDs23
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
627 PciDs23
.ImageLength
= RomHdr
.InitializationSize
;
628 PciDs23
.CodeRevision
= InFile
->CodeRevision
;
629 PciDs23
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
631 PciDs30
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
632 PciDs30
.VendorId
= VendId
;
633 PciDs30
.DeviceId
= DevId
;
634 PciDs30
.DeviceListOffset
= 0; // to be fixed
635 PciDs30
.Length
= (UINT16
) sizeof (PCI_3_0_DATA_STRUCTURE
);
636 PciDs30
.Revision
= 0x3;
638 // Class code and code revision from the command line (optional)
640 PciDs30
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
641 PciDs30
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
642 PciDs30
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
643 PciDs30
.ImageLength
= RomHdr
.InitializationSize
;
644 PciDs30
.CodeRevision
= InFile
->CodeRevision
;
645 PciDs30
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
646 PciDs30
.MaxRuntimeImageLength
= 0; // to be fixed
647 PciDs30
.ConfigUtilityCodeHeaderOffset
= 0; // to be fixed
648 PciDs30
.DMTFCLPEntryPointOffset
= 0; // to be fixed
651 // If this is the last image, then set the LAST bit unless requested not
652 // to via the command-line -n argument.
654 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
655 if (mOptions
.Pci23
== 1) {
656 PciDs23
.Indicator
= INDICATOR_LAST
;
658 PciDs30
.Indicator
= INDICATOR_LAST
;}
660 if (mOptions
.Pci23
== 1) {
661 PciDs23
.Indicator
= 0;
663 PciDs30
.Indicator
= 0;
667 // Write the ROM header to the output file
669 if (fwrite (&RomHdr
, sizeof (RomHdr
), 1, OutFptr
) != 1) {
670 Error (NULL
, 0, 0002, "Failed to write ROM header to output file!", NULL
);
671 Status
= STATUS_ERROR
;
676 // Write pad bytes to align the PciDs
678 while (HeaderPadBytes
> 0) {
679 if (putc (0, OutFptr
) == EOF
) {
680 Error (NULL
, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL
);
681 Status
= STATUS_ERROR
;
688 // Write the PCI data structure header to the output file
690 if (mOptions
.Pci23
== 1) {
691 if (fwrite (&PciDs23
, sizeof (PciDs23
), 1, OutFptr
) != 1) {
692 Error (NULL
, 0, 0002, "Failed to write PCI ROM header to output file!", NULL
);
693 Status
= STATUS_ERROR
;
697 if (fwrite (&PciDs30
, sizeof (PciDs30
), 1, OutFptr
) != 1) {
698 Error (NULL
, 0, 0002, "Failed to write PCI ROM header to output file!", NULL
);
699 Status
= STATUS_ERROR
;
705 // Pad head to make it a multiple of 512 bytes
707 while (PadBytesBeforeImage
> 0) {
708 if (putc (~0, OutFptr
) == EOF
) {
709 Error (NULL
, 0, 2000, "Failed to write trailing pad bytes output file!", NULL
);
710 Status
= STATUS_ERROR
;
713 PadBytesBeforeImage
--;
716 // Now dump the input file's contents to the output file
718 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
719 Error (NULL
, 0, 0002, "Failed to write all file bytes to output file!", NULL
);
720 Status
= STATUS_ERROR
;
725 // Pad the rest of the image to make it a multiple of 512 bytes
727 while (PadBytesAfterImage
> 0) {
728 if (putc (~0, OutFptr
) == EOF
) {
729 Error (NULL
, 0, 2000, "Failed to write trailing pad bytes output file!", NULL
);
730 Status
= STATUS_ERROR
;
734 PadBytesAfterImage
--;
738 if (InFptr
!= NULL
) {
742 // Free up our buffers
744 if (Buffer
!= NULL
) {
748 if (CompressedBuffer
!= NULL
) {
749 free (CompressedBuffer
);
752 // Print the file name if errors occurred
754 if (Status
!= STATUS_SUCCESS
) {
755 Error (NULL
, 0, 0003, "Error parsing", "Error parsing file: %s", InFile
->FileName
);
772 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
773 PE32 image file, and then return the machine type in the supplied pointer.
777 Fptr File pointer to the already-opened PE32 file
778 MachineType Location to stuff the machine type of the PE32 file. This is needed
779 because the image may be Itanium-based, IA32, or EBC.
788 EFI_IMAGE_DOS_HEADER DosHeader
;
789 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
792 // Position to the start of the file
794 fseek (Fptr
, 0, SEEK_SET
);
797 // Read the DOS header
799 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
800 Error (NULL
, 0, 0004, "Failed to read the DOS stub from the input file!", NULL
);
804 // Check the magic number (0x5A4D)
806 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
807 Error (NULL
, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");
811 // Position into the file and check the PE signature
813 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
818 if (fread (&PeHdr
, sizeof (PeHdr
), 1, Fptr
) != 1) {
819 Error (NULL
, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL
);
825 // Check the PE signature in the header "PE\0\0"
827 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
828 Error (NULL
, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");
832 memcpy ((char *) MachineType
, &PeHdr
.Pe32
.FileHeader
.Machine
, 2);
834 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
835 *SubSystem
= PeHdr
.Pe32
.OptionalHeader
.Subsystem
;
836 } else if (PeHdr
.Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
837 *SubSystem
= PeHdr
.Pe32Plus
.OptionalHeader
.Subsystem
;
839 Error (NULL
, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");
843 if (mOptions
.Verbose
) {
844 VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem
);
848 // File was successfully identified as a PE32
850 return STATUS_SUCCESS
;
864 Given the Argc/Argv program arguments, and a pointer to an options structure,
865 parse the command-line options and check their validity.
870 Argc - standard C main() argument count
871 Argv[] - standard C main() argument list
872 Options - pointer to a structure to store the options in
876 STATUS_SUCCESS success
882 FILE_LIST
*PrevFileList
;
896 // Clear out the options
898 memset ((char *) Options
, 0, sizeof (OPTIONS
));
901 // To avoid compile warnings
903 FileList
= PrevFileList
= NULL
;
908 // Skip over the program name
914 // If no arguments, assume they want usage info
921 if ((stricmp(Argv
[0], "-h") == 0) || (stricmp(Argv
[0], "--help") == 0)) {
926 if ((stricmp(Argv
[0], "--version") == 0)) {
932 // Process until no more arguments
935 if (Argv
[0][0] == '-') {
937 // Vendor ID specified with -f
939 if (stricmp (Argv
[0], "-f") == 0) {
941 // Make sure there's another parameter
943 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
944 if (EFI_ERROR (Status
)) {
945 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
949 if (TempValue
>= 0x10000) {
950 Error (NULL
, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv
[1]);
954 Options
->VendId
= (UINT16
) TempValue
;
955 Options
->VendIdValid
= 1;
959 } else if (stricmp (Argv
[0], "-i") == 0) {
961 // Device ID specified with -i
962 // Make sure there's another parameter
964 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
965 if (EFI_ERROR (Status
)) {
966 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
970 if (TempValue
>= 0x10000) {
971 Error (NULL
, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv
[1]);
975 Options
->DevId
= (UINT16
) TempValue
;
976 Options
->DevIdValid
= 1;
980 } else if ((stricmp (Argv
[0], "-o") == 0) || (stricmp (Argv
[0], "--output") == 0)) {
982 // Output filename specified with -o
983 // Make sure there's another parameter
985 if (Argv
[1] == NULL
|| Argv
[1][0] == '-') {
986 Error (NULL
, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv
[0]);
987 ReturnStatus
= STATUS_ERROR
;
990 if (strlen (Argv
[1]) > MAX_PATH
- 1) {
991 Error (NULL
, 0, 2000, "Invalid parameter", "Output file name %s is too long!", Argv
[1]);
992 ReturnStatus
= STATUS_ERROR
;
995 strncpy (Options
->OutFileName
, Argv
[1], MAX_PATH
- 1);
996 Options
->OutFileName
[MAX_PATH
- 1] = 0;
1000 } else if ((stricmp (Argv
[0], "-h") == 0) || (stricmp (Argv
[0], "--help") == 0)) {
1005 ReturnStatus
= STATUS_ERROR
;
1007 } else if (stricmp (Argv
[0], "-b") == 0) {
1009 // Specify binary files with -b
1011 FileFlags
= FILE_FLAG_BINARY
;
1012 } else if ((stricmp (Argv
[0], "-e") == 0) || (stricmp (Argv
[0], "-ec") == 0)) {
1014 // Specify EFI files with -e. Specify EFI-compressed with -c.
1016 FileFlags
= FILE_FLAG_EFI
;
1017 if ((Argv
[0][2] == 'c') || (Argv
[0][2] == 'C')) {
1018 FileFlags
|= FILE_FLAG_COMPRESS
;
1021 // Specify not to set the LAST bit in the last file with -n
1023 } else if (stricmp (Argv
[0], "-n") == 0) {
1024 Options
->NoLast
= 1;
1025 } else if (((stricmp (Argv
[0], "-v") == 0)) || ((stricmp (Argv
[0], "--verbose") == 0))) {
1029 Options
->Verbose
= 1;
1030 } else if (stricmp (Argv
[0], "--debug") == 0) {
1031 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &DebugLevel
);
1032 if (EFI_ERROR (Status
)) {
1033 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1037 if (DebugLevel
> 9) {
1038 Error (NULL
, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv
[1]);
1042 if (DebugLevel
>=5 && DebugLevel
<=9) {
1043 Options
->Debug
= TRUE
;
1045 Options
->Debug
= FALSE
;
1049 } else if ((stricmp (Argv
[0], "--quiet") == 0) || (stricmp (Argv
[0], "-q") == 0)) {
1050 Options
->Quiet
= TRUE
;
1051 } else if ((stricmp (Argv
[0], "--dump") == 0) || (stricmp (Argv
[0], "-d") == 0)) {
1053 // -dump for dumping a ROM image. In this case, say that the device id
1054 // and vendor id are valid so we don't have to specify bogus ones on the
1057 Options
->DumpOption
= 1;
1059 Options
->VendIdValid
= 1;
1060 Options
->DevIdValid
= 1;
1061 FileFlags
= FILE_FLAG_BINARY
;
1062 } else if ((stricmp (Argv
[0], "-l") == 0) || (stricmp (Argv
[0], "--class-code") == 0)) {
1064 // Class code value for the next file in the list.
1065 // Make sure there's another parameter
1067 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
1068 if (EFI_ERROR (Status
)) {
1069 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1073 ClassCode
= (UINT32
) TempValue
;
1074 if (ClassCode
& 0xFF000000) {
1075 Error (NULL
, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv
[1]);
1076 ReturnStatus
= STATUS_ERROR
;
1079 if (FileList
!= NULL
&& FileList
->ClassCode
== 0) {
1080 FileList
->ClassCode
= ClassCode
;
1084 } else if ((stricmp (Argv
[0], "-r") == 0) || (stricmp (Argv
[0], "--Revision") == 0)) {
1086 // Code revision in the PCI data structure. The value is for the next
1087 // file in the list.
1088 // Make sure there's another parameter
1090 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
1091 if (EFI_ERROR (Status
)) {
1092 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1096 CodeRevision
= (UINT32
) TempValue
;
1097 if (CodeRevision
& 0xFFFF0000) {
1098 Error (NULL
, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv
[1]);
1099 ReturnStatus
= STATUS_ERROR
;
1102 if (FileList
!= NULL
&& FileList
->CodeRevision
== 0) {
1103 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1107 } else if ((stricmp (Argv
[0], "-p") == 0) || (stricmp (Argv
[0], "--pci23") == 0)) {
1109 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
1113 Error (NULL
, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv
[0]);
1114 ReturnStatus
= STATUS_ERROR
;
1119 // Not a slash-option argument. Must be a file name. Make sure they've specified
1120 // -e or -b already.
1122 if ((FileFlags
& (FILE_FLAG_BINARY
| FILE_FLAG_EFI
)) == 0) {
1123 Error (NULL
, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv
[0]);
1124 ReturnStatus
= STATUS_ERROR
;
1128 // Check Efi Option RomImage
1130 if ((FileFlags
& FILE_FLAG_EFI
) == FILE_FLAG_EFI
) {
1134 // Create a new file structure
1136 FileList
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
1137 if (FileList
== NULL
) {
1138 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!", NULL
);
1139 ReturnStatus
= STATUS_ERROR
;
1144 // set flag and class code for this image.
1146 memset ((char *) FileList
, 0, sizeof (FILE_LIST
));
1147 FileList
->FileName
= Argv
[0];
1148 FileList
->FileFlags
= FileFlags
;
1149 FileList
->ClassCode
= ClassCode
;
1150 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1154 if (Options
->FileList
== NULL
) {
1155 Options
->FileList
= FileList
;
1157 if (PrevFileList
== NULL
) {
1158 PrevFileList
= FileList
;
1160 PrevFileList
->Next
= FileList
;
1164 PrevFileList
= FileList
;
1174 // Must have specified some files
1176 if (Options
->FileList
== NULL
) {
1177 Error (NULL
, 0, 2000, "Invalid parameter", "Missing input file name!");
1179 // No memory allocation, return directly.
1181 return STATUS_ERROR
;
1185 // For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.
1188 if (!Options
->VendIdValid
) {
1189 Error (NULL
, 0, 2000, "Missing Vendor ID in command line", NULL
);
1190 ReturnStatus
= STATUS_ERROR
;
1194 if (!Options
->DevIdValid
) {
1195 Error (NULL
, 0, 2000, "Missing Device ID in command line", NULL
);
1196 ReturnStatus
= STATUS_ERROR
;
1202 if (ReturnStatus
!= 0) {
1203 while (Options
->FileList
!= NULL
) {
1204 FileList
= Options
->FileList
->Next
;
1205 free (Options
->FileList
);
1206 Options
->FileList
= FileList
;
1210 return ReturnStatus
;
1220 Routine Description:
1222 Print version information for this utility.
1233 fprintf (stdout
, "%s Version %d.%d %s \n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
, __BUILD_VERSION
);
1243 Routine Description:
1245 Print usage information for this utility.
1260 fprintf (stdout
, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME
);
1263 // Copyright declaration
1265 fprintf (stdout
, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");
1270 fprintf (stdout
, "Options:\n");
1271 fprintf (stdout
, " -o FileName, --output FileName\n\
1272 File will be created to store the output content.\n");
1273 fprintf (stdout
, " -e EfiFileName\n\
1274 EFI PE32 image files.\n");
1275 fprintf (stdout
, " -ec EfiFileName\n\
1276 EFI PE32 image files and will be compressed.\n");
1277 fprintf (stdout
, " -b BinFileName\n\
1278 Legacy binary files.\n");
1279 fprintf (stdout
, " -l ClassCode\n\
1280 Hex ClassCode in the PCI data structure header.\n");
1281 fprintf (stdout
, " -r Rev Hex Revision in the PCI data structure header.\n");
1282 fprintf (stdout
, " -n Not to automatically set the LAST bit in the last file.\n");
1283 fprintf (stdout
, " -f VendorId\n\
1284 Hex PCI Vendor ID for the device OpROM, must be specified\n");
1285 fprintf (stdout
, " -i DeviceId\n\
1286 Hex PCI Device ID for the device OpROM, must be specified\n");
1287 fprintf (stdout
, " -p, --pci23\n\
1288 Default layout meets PCI 3.0 specifications\n\
1289 specifying this flag will for a PCI 2.3 layout.\n");
1290 fprintf (stdout
, " -d, --dump\n\
1291 Dump the headers of an existing option ROM image.\n");
1292 fprintf (stdout
, " -v, --verbose\n\
1293 Turn on verbose output with informational messages.\n");
1294 fprintf (stdout
, " --version Show program's version number and exit.\n");
1295 fprintf (stdout
, " -h, --help\n\
1296 Show this help message and exit.\n");
1297 fprintf (stdout
, " -q, --quiet\n\
1298 Disable all messages except FATAL ERRORS.\n");
1299 fprintf (stdout
, " --debug [#,0-9]\n\
1300 Enable debug messages at level #.\n");
1310 Routine Description:
1312 Dump the headers of an existing option ROM image
1316 InFile - the file name of an existing option ROM image
1324 PCI_EXPANSION_ROM_HEADER PciRomHdr
;
1328 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr
;
1329 PCI_DATA_STRUCTURE PciDs23
;
1330 PCI_3_0_DATA_STRUCTURE PciDs30
;
1333 // Open the input file
1335 if ((InFptr
= fopen (LongFilePath (InFile
->FileName
), "rb")) == NULL
) {
1336 Error (NULL
, 0, 0001, "Error opening file", InFile
->FileName
);
1340 // Go through the image and dump the header stuff for each
1345 // Save our postition in the file, since offsets in the headers
1346 // are relative to the particular image.
1348 ImageStart
= ftell (InFptr
);
1352 // Read the option ROM header. Have to assume a raw binary image for now.
1354 if (fread (&PciRomHdr
, sizeof (PciRomHdr
), 1, InFptr
) != 1) {
1355 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");
1360 // Dump the contents of the header
1362 fprintf (stdout
, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount
, (unsigned) ImageStart
);
1363 fprintf (stdout
, " ROM header contents\n");
1364 fprintf (stdout
, " Signature 0x%04X\n", PciRomHdr
.Signature
);
1365 fprintf (stdout
, " PCIR offset 0x%04X\n", PciRomHdr
.PcirOffset
);
1367 // Find PCI data structure
1369 if (fseek (InFptr
, ImageStart
+ PciRomHdr
.PcirOffset
, SEEK_SET
)) {
1370 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");
1374 // Read and dump the PCI data structure
1376 memset (&PciDs23
, 0, sizeof (PciDs23
));
1377 memset (&PciDs30
, 0, sizeof (PciDs30
));
1378 if (mOptions
.Pci23
== 1) {
1379 if (fread (&PciDs23
, sizeof (PciDs23
), 1, InFptr
) != 1) {
1380 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile
->FileName
);
1384 if (fread (&PciDs30
, sizeof (PciDs30
), 1, InFptr
) != 1) {
1385 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile
->FileName
);
1389 if (mOptions
.Verbose
) {
1390 VerboseMsg("Read PCI data structure from file %s", InFile
->FileName
);
1393 //fprintf (stdout, " PCI Data Structure\n");
1394 if (mOptions
.Pci23
== 1) {
1397 " Signature %c%c%c%c\n",
1398 (char) PciDs23
.Signature
,
1399 (char) (PciDs23
.Signature
>> 8),
1400 (char) (PciDs23
.Signature
>> 16),
1401 (char) (PciDs23
.Signature
>> 24)
1403 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs23
.VendorId
);
1404 fprintf (stdout
, " Device ID 0x%04X\n", PciDs23
.DeviceId
);
1405 fprintf (stdout
, " Length 0x%04X\n", PciDs23
.Length
);
1406 fprintf (stdout
, " Revision 0x%04X\n", PciDs23
.Revision
);
1409 " Class Code 0x%06X\n",
1410 (unsigned) (PciDs23
.ClassCode
[0] | (PciDs23
.ClassCode
[1] << 8) | (PciDs23
.ClassCode
[2] << 16))
1412 fprintf (stdout
, " Image size 0x%X\n", (unsigned) PciDs23
.ImageLength
* 512);
1413 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs23
.CodeRevision
);
1414 fprintf (stdout
, " Indicator 0x%02X", PciDs23
.Indicator
);
1418 " Signature %c%c%c%c\n",
1419 (char) PciDs30
.Signature
,
1420 (char) (PciDs30
.Signature
>> 8),
1421 (char) (PciDs30
.Signature
>> 16),
1422 (char) (PciDs30
.Signature
>> 24)
1424 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs30
.VendorId
);
1425 fprintf (stdout
, " Device ID 0x%04X\n", PciDs30
.DeviceId
);
1426 fprintf (stdout
, " Length 0x%04X\n", PciDs30
.Length
);
1427 fprintf (stdout
, " Revision 0x%04X\n", PciDs30
.Revision
);
1428 fprintf (stdout
, " DeviceListOffset 0x%02X\n", PciDs30
.DeviceListOffset
);
1431 " Class Code 0x%06X\n",
1432 (unsigned) (PciDs30
.ClassCode
[0] | (PciDs30
.ClassCode
[1] << 8) | (PciDs30
.ClassCode
[2] << 16))
1434 fprintf (stdout
, " Image size 0x%X\n", (unsigned) PciDs30
.ImageLength
* 512);
1435 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs30
.CodeRevision
);
1436 fprintf (stdout
, " MaxRuntimeImageLength 0x%02X\n", PciDs30
.MaxRuntimeImageLength
);
1437 fprintf (stdout
, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30
.ConfigUtilityCodeHeaderOffset
);
1438 fprintf (stdout
, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30
.DMTFCLPEntryPointOffset
);
1439 fprintf (stdout
, " Indicator 0x%02X", PciDs30
.Indicator
);
1442 // Print the indicator, used to flag the last image
1444 if (PciDs23
.Indicator
== INDICATOR_LAST
|| PciDs30
.Indicator
== INDICATOR_LAST
) {
1445 fprintf (stdout
, " (last image)\n");
1447 fprintf (stdout
, "\n");
1450 // Print the code type. If EFI code, then we can provide more info.
1452 if (mOptions
.Pci23
== 1) {
1453 fprintf (stdout
, " Code type 0x%02X", PciDs23
.CodeType
);
1455 fprintf (stdout
, " Code type 0x%02X", PciDs30
.CodeType
);
1457 if (PciDs23
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
|| PciDs30
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
1458 fprintf (stdout
, " (EFI image)\n");
1460 // Re-read the header as an EFI ROM header, then dump more info
1462 fprintf (stdout
, " EFI ROM header contents\n");
1463 if (fseek (InFptr
, ImageStart
, SEEK_SET
)) {
1464 Error (NULL
, 0, 5001, "Failed to re-seek to ROM header structure!", NULL
);
1468 if (fread (&EfiRomHdr
, sizeof (EfiRomHdr
), 1, InFptr
) != 1) {
1469 Error (NULL
, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL
);
1473 // Now dump more info
1475 fprintf (stdout
, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr
.EfiSignature
);
1478 " Compression Type 0x%04X ",
1479 EfiRomHdr
.CompressionType
1481 if (EfiRomHdr
.CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
1482 fprintf (stdout
, "(compressed)\n");
1484 fprintf (stdout
, "(not compressed)\n");
1489 " Machine type 0x%04X (%s)\n",
1490 EfiRomHdr
.EfiMachineType
,
1491 GetMachineTypeStr (EfiRomHdr
.EfiMachineType
)
1495 " Subsystem 0x%04X (%s)\n",
1496 EfiRomHdr
.EfiSubsystem
,
1497 GetSubsystemTypeStr (EfiRomHdr
.EfiSubsystem
)
1501 " EFI image offset 0x%04X (@0x%X)\n",
1502 EfiRomHdr
.EfiImageHeaderOffset
,
1503 EfiRomHdr
.EfiImageHeaderOffset
+ (unsigned) ImageStart
1510 fprintf (stdout
, "\n");
1513 // If code type is EFI image, then dump it as well?
1515 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
1518 // If last image, then we're done
1520 if (PciDs23
.Indicator
== INDICATOR_LAST
|| PciDs30
.Indicator
== INDICATOR_LAST
) {
1524 // Seek to the start of the next image
1526 if (mOptions
.Pci23
== 1) {
1527 if (fseek (InFptr
, ImageStart
+ (PciDs23
.ImageLength
* 512), SEEK_SET
)) {
1528 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to next image!");
1532 if (fseek (InFptr
, ImageStart
+ (PciDs30
.ImageLength
* 512), SEEK_SET
)) {
1533 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to next image!");
1549 Routine Description:
1551 GC_TODO: Add function description
1555 MachineType - GC_TODO: add argument description
1559 GC_TODO: add return values
1565 for (Index
= 0; mMachineTypes
[Index
].Name
!= NULL
; Index
++) {
1566 if (mMachineTypes
[Index
].Value
== MachineType
) {
1567 return mMachineTypes
[Index
].Name
;
1576 GetSubsystemTypeStr (
1577 UINT16 SubsystemType
1581 Routine Description:
1583 GC_TODO: Add function description
1587 SubsystemType - GC_TODO: add argument description
1591 GC_TODO: add return values
1597 for (Index
= 0; mSubsystemTypes
[Index
].Name
!= NULL
; Index
++) {
1598 if (mSubsystemTypes
[Index
].Value
== SubsystemType
) {
1599 return mSubsystemTypes
[Index
].Name
;