3 Copyright (c) 1999 - 2013, Intel Corporation. All rights reserved.<BR>
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 Utility program to create an EFI option ROM image from binary and
23 #include "EfiUtilityMsgs.h"
27 UINT64 DebugLevel
= 0;
38 Given an EFI image filename, create a ROM-able image by creating an option
39 ROM header and PCI data structure, filling them in, and then writing the
40 option ROM header + PCI data structure + EFI image out to the output file.
44 Argc - standard C main() argument count
46 Argv - standard C main() argument list
63 SetUtilityName(UTILITY_NAME
);
65 Status
= STATUS_SUCCESS
;
69 // Parse the command line arguments
71 if (ParseCommandLine (Argc
, Argv
, &mOptions
)) {
77 } else if (mOptions
.Verbose
) {
79 } else if (mOptions
.Debug
) {
80 SetPrintLevel(DebugLevel
);
83 if (mOptions
.Verbose
) {
84 VerboseMsg("%s tool start.\n", UTILITY_NAME
);
88 // If dumping an image, then do that and quit
90 if (mOptions
.DumpOption
== 1) {
91 if (mOptions
.FileList
!= NULL
) {
92 if ((Ptr0
= strstr ((CONST CHAR8
*) mOptions
.FileList
->FileName
, DEFAULT_OUTPUT_EXTENSION
)) != NULL
) {
93 DumpImage (mOptions
.FileList
);
96 Error (NULL
, 0, 1002, "No PciRom input file", "No *.rom input file");
102 // Determine the output filename. Either what they specified on
103 // the command line, or the first input filename with a different extension.
105 if (!mOptions
.OutFileName
[0]) {
106 strcpy (mOptions
.OutFileName
, mOptions
.FileList
->FileName
);
108 // Find the last . on the line and replace the filename extension with
111 for (Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
) - 1;
112 (Ext
>= mOptions
.OutFileName
) && (*Ext
!= '.') && (*Ext
!= '\\');
117 // If dot here, then insert extension here, otherwise append
120 Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
);
123 strcpy (Ext
, DEFAULT_OUTPUT_EXTENSION
);
126 // Make sure we don't have the same filename for input and output files
128 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
129 if (stricmp (mOptions
.OutFileName
, FList
->FileName
) == 0) {
130 Status
= STATUS_ERROR
;
131 Error (NULL
, 0, 1002, "Invalid input paramter", "Input and output file names must be different - %s = %s.", FList
->FileName
, mOptions
.OutFileName
);
136 // Now open our output file
138 if ((FptrOut
= fopen (mOptions
.OutFileName
, "wb")) == NULL
) {
139 Error (NULL
, 0, 0001, "Error opening file", "Error opening file %s", mOptions
.OutFileName
);
143 // Process all our files
146 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
148 if ((FList
->FileFlags
& FILE_FLAG_EFI
) != 0) {
149 if (mOptions
.Verbose
) {
150 VerboseMsg("Processing EFI file %s\n", FList
->FileName
);
153 Status
= ProcessEfiFile (FptrOut
, FList
, mOptions
.VendId
, mOptions
.DevId
, &Size
);
154 } else if ((FList
->FileFlags
& FILE_FLAG_BINARY
) !=0 ) {
155 if (mOptions
.Verbose
) {
156 VerboseMsg("Processing binary file %s\n", FList
->FileName
);
159 Status
= ProcessBinFile (FptrOut
, FList
, &Size
);
161 Error (NULL
, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList
->FileName
);
162 Status
= STATUS_ERROR
;
165 if (mOptions
.Verbose
) {
166 VerboseMsg(" Output size = 0x%X\n", (unsigned) Size
);
169 if (Status
!= STATUS_SUCCESS
) {
178 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
179 Error (NULL
, 0, 2000, "Invalid paramter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE
);
180 Status
= STATUS_ERROR
;
184 if (Status
== STATUS_SUCCESS
) {
185 if (FptrOut
!= NULL
) {
189 // Clean up our file list
191 while (mOptions
.FileList
!= NULL
) {
192 FList
= mOptions
.FileList
->Next
;
193 free (mOptions
.FileList
);
194 mOptions
.FileList
= FList
;
198 if (mOptions
.Verbose
) {
199 VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME
, GetUtilityStatus ());
202 return GetUtilityStatus ();
216 Process a binary input file.
220 OutFptr - file pointer to output binary ROM image file we're creating
221 InFile - structure contains information on the binary file to process
222 Size - pointer to where to return the size added to the output file
235 PCI_EXPANSION_ROM_HEADER
*RomHdr
;
236 PCI_DATA_STRUCTURE
*PciDs23
;
237 PCI_3_0_DATA_STRUCTURE
*PciDs30
;
244 Status
= STATUS_SUCCESS
;
247 // Try to open the input file
249 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
250 Error (NULL
, 0, 0001, "Error opening file", InFile
->FileName
);
254 // Seek to the end of the input file and get the file size. Then allocate
255 // a buffer to read it in to.
257 fseek (InFptr
, 0, SEEK_END
);
258 FileSize
= ftell (InFptr
);
259 if (mOptions
.Verbose
) {
260 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize
);
263 fseek (InFptr
, 0, SEEK_SET
);
264 Buffer
= (UINT8
*) malloc (FileSize
);
265 if (Buffer
== NULL
) {
266 Error (NULL
, 0, 4003, "Resource", "memory cannot be allocated!");
267 Status
= STATUS_ERROR
;
271 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
272 Error (NULL
, 0, 2000, "Invalid", "Failed to read all bytes from input file.");
273 Status
= STATUS_ERROR
;
277 // Total size must be an even multiple of 512 bytes, and can't exceed
278 // the option ROM image size.
280 TotalSize
= FileSize
;
281 if (TotalSize
& 0x1FF) {
282 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
285 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
286 Error (NULL
, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile
->FileName
, MAX_OPTION_ROM_SIZE
);
287 Status
= STATUS_ERROR
;
291 // Return the size to the caller so they can keep track of the running total.
296 // Crude check to make sure it's a legitimate ROM image
298 RomHdr
= (PCI_EXPANSION_ROM_HEADER
*) Buffer
;
299 if (RomHdr
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
300 Error (NULL
, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");
301 Status
= STATUS_ERROR
;
305 // Make sure the pointer to the PCI data structure is within the size of the image.
306 // Then check it for valid signature.
308 if ((RomHdr
->PcirOffset
> FileSize
) || (RomHdr
->PcirOffset
== 0)) {
309 Error (NULL
, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");
310 Status
= STATUS_ERROR
;
315 // Check the header is conform to PCI2.3 or PCI3.0
317 if (mOptions
.Pci23
== 1) {
318 PciDs23
= (PCI_DATA_STRUCTURE
*) (Buffer
+ RomHdr
->PcirOffset
);
319 if (PciDs23
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
320 Error (NULL
, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
321 Status
= STATUS_ERROR
;
326 // Default setting is PCI3.0 header
328 PciDs30
= (PCI_3_0_DATA_STRUCTURE
*)(Buffer
+ RomHdr
->PcirOffset
);
329 if (PciDs30
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
330 Error (NULL
, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
331 Status
= STATUS_ERROR
;
337 // ReSet Option Rom size
339 if (mOptions
.Pci23
== 1) {
340 PciDs23
->ImageLength
= (UINT16
) (TotalSize
/ 512);
341 CodeType
= PciDs23
->CodeType
;
343 PciDs30
->ImageLength
= (UINT16
) (TotalSize
/ 512);
344 CodeType
= PciDs30
->CodeType
;
348 // If this is the last image, then set the LAST bit unless requested not
349 // to via the command-line -n argument. Otherwise, make sure you clear it.
351 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
352 if (mOptions
.Pci23
== 1) {
353 PciDs23
->Indicator
= INDICATOR_LAST
;
355 PciDs30
->Indicator
= INDICATOR_LAST
;
358 if (mOptions
.Pci23
== 1) {
359 PciDs23
->Indicator
= 0;
361 PciDs30
->Indicator
= 0;
365 if (CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
367 for (Index
= 0; Index
< FileSize
- 1; Index
++) {
368 ByteCheckSum
= (UINT8
) (ByteCheckSum
+ Buffer
[Index
]);
371 Buffer
[FileSize
- 1] = (UINT8
) ((~ByteCheckSum
) + 1);
372 if (mOptions
.Verbose
) {
373 VerboseMsg(" Checksum = %02x\n\n", Buffer
[FileSize
- 1]);
378 // Now copy the input file contents out to the output file
380 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
381 Error (NULL
, 0, 0005, "Failed to write all file bytes to output file.", NULL
);
382 Status
= STATUS_ERROR
;
386 TotalSize
-= FileSize
;
388 // Pad the rest of the image to make it a multiple of 512 bytes
390 while (TotalSize
> 0) {
396 if (InFptr
!= NULL
) {
400 if (Buffer
!= NULL
) {
404 // Print the file name if errors occurred
406 if (Status
!= STATUS_SUCCESS
) {
407 Error (NULL
, 0, 0003, "Error", "Error parsing file: %s", InFile
->FileName
);
426 Process a PE32 EFI file.
430 OutFptr - file pointer to output binary ROM image file we're creating
431 InFile - structure contains information on the PE32 file to process
432 VendId - vendor ID as required in the option ROM header
433 DevId - device ID as required in the option ROM header
434 Size - pointer to where to return the size added to the output file
444 EFI_PCI_EXPANSION_ROM_HEADER RomHdr
;
445 PCI_DATA_STRUCTURE PciDs23
;
446 PCI_3_0_DATA_STRUCTURE PciDs30
;
448 UINT32 CompressedFileSize
;
450 UINT8
*CompressedBuffer
;
451 UINT8
*TempBufferPtr
;
456 UINT32 HeaderPadBytes
;
457 UINT32 PadBytesBeforeImage
;
458 UINT32 PadBytesAfterImage
;
461 // Try to open the input file
463 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
464 Error (NULL
, 0, 0001, "Open file error", "Error opening file: %s", InFile
->FileName
);
468 // Initialize our buffer pointers to null.
471 CompressedBuffer
= NULL
;
474 // Double-check the file to make sure it's what we expect it to be
476 Status
= CheckPE32File (InFptr
, &MachineType
, &SubSystem
);
477 if (Status
!= STATUS_SUCCESS
) {
481 // Seek to the end of the input file and get the file size
483 fseek (InFptr
, 0, SEEK_END
);
484 FileSize
= ftell (InFptr
);
487 // Get the size of the headers we're going to put in front of the image. The
488 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
490 if (sizeof (RomHdr
) & 0x03) {
491 HeaderPadBytes
= 4 - (sizeof (RomHdr
) & 0x03);
497 // For Pci3.0 to use the different data structure.
499 if (mOptions
.Pci23
== 1) {
500 HeaderSize
= sizeof (PCI_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
502 HeaderSize
= sizeof (PCI_3_0_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
505 if (mOptions
.Verbose
) {
506 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize
);
509 // Allocate memory for the entire file (in case we have to compress), then
510 // seek back to the beginning of the file and read it into our buffer.
512 Buffer
= (UINT8
*) malloc (FileSize
);
513 if (Buffer
== NULL
) {
514 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
515 Status
= STATUS_ERROR
;
519 fseek (InFptr
, 0, SEEK_SET
);
520 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
521 Error (NULL
, 0, 0004, "Error reading file", "File %s", InFile
->FileName
);
522 Status
= STATUS_ERROR
;
526 // Now determine the size of the final output file. It's either the header size
527 // plus the file's size, or the header size plus the compressed file size.
529 if ((InFile
->FileFlags
& FILE_FLAG_COMPRESS
) != 0) {
531 // Allocate a buffer into which we can compress the image, compress it,
532 // and use that size as the new size.
534 CompressedBuffer
= (UINT8
*) malloc (FileSize
);
535 if (CompressedBuffer
== NULL
) {
536 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
537 Status
= STATUS_ERROR
;
541 CompressedFileSize
= FileSize
;
542 Status
= EfiCompress (Buffer
, FileSize
, CompressedBuffer
, &CompressedFileSize
);
543 if (Status
!= STATUS_SUCCESS
) {
544 Error (NULL
, 0, 0007, "Error compressing file!", NULL
);
548 // Now compute the size, then swap buffer pointers.
550 if (mOptions
.Verbose
) {
551 VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize
);
554 TotalSize
= CompressedFileSize
+ HeaderSize
;
555 FileSize
= CompressedFileSize
;
556 TempBufferPtr
= Buffer
;
557 Buffer
= CompressedBuffer
;
558 CompressedBuffer
= TempBufferPtr
;
560 TotalSize
= FileSize
+ HeaderSize
;
563 // Total size must be an even multiple of 512 bytes
565 if (TotalSize
& 0x1FF) {
566 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
570 // If compressed, put the pad bytes after the image,
571 // else put the pad bytes before the image.
573 if ((InFile
->FileFlags
& FILE_FLAG_COMPRESS
) != 0) {
574 PadBytesBeforeImage
= 0;
575 PadBytesAfterImage
= TotalSize
- (FileSize
+ HeaderSize
);
577 PadBytesBeforeImage
= TotalSize
- (FileSize
+ HeaderSize
);
578 PadBytesAfterImage
= 0;
583 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
584 Error (NULL
, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile
->FileName
, MAX_OPTION_ROM_SIZE
);
585 Status
= STATUS_ERROR
;
589 // Return the size to the caller so they can keep track of the running total.
594 // Now fill in the ROM header. These values come from chapter 18 of the
595 // EFI 1.02 specification.
597 memset (&RomHdr
, 0, sizeof (RomHdr
));
598 RomHdr
.Signature
= PCI_EXPANSION_ROM_HEADER_SIGNATURE
;
599 RomHdr
.InitializationSize
= (UINT16
) (TotalSize
/ 512);
600 RomHdr
.EfiSignature
= EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
;
601 RomHdr
.EfiSubsystem
= SubSystem
;
602 RomHdr
.EfiMachineType
= MachineType
;
603 RomHdr
.EfiImageHeaderOffset
= (UINT16
) (HeaderSize
+ PadBytesBeforeImage
);
604 RomHdr
.PcirOffset
= (UINT16
) (sizeof (RomHdr
) + HeaderPadBytes
);
606 // Set image as compressed or not
608 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
609 RomHdr
.CompressionType
= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
;
612 // Fill in the PCI data structure
614 if (mOptions
.Pci23
== 1) {
615 memset (&PciDs23
, 0, sizeof (PCI_DATA_STRUCTURE
));
617 memset (&PciDs30
, 0, sizeof (PCI_3_0_DATA_STRUCTURE
));
620 if (mOptions
.Pci23
== 1) {
621 PciDs23
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
622 PciDs23
.VendorId
= VendId
;
623 PciDs23
.DeviceId
= DevId
;
624 PciDs23
.Length
= (UINT16
) sizeof (PCI_DATA_STRUCTURE
);
625 PciDs23
.Revision
= 0;
627 // Class code and code revision from the command line (optional)
629 PciDs23
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
630 PciDs23
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
631 PciDs23
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
632 PciDs23
.ImageLength
= RomHdr
.InitializationSize
;
633 PciDs23
.CodeRevision
= InFile
->CodeRevision
;
634 PciDs23
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
636 PciDs30
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
637 PciDs30
.VendorId
= VendId
;
638 PciDs30
.DeviceId
= DevId
;
639 PciDs30
.DeviceListOffset
= 0; // to be fixed
640 PciDs30
.Length
= (UINT16
) sizeof (PCI_3_0_DATA_STRUCTURE
);
641 PciDs30
.Revision
= 0x3;
643 // Class code and code revision from the command line (optional)
645 PciDs30
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
646 PciDs30
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
647 PciDs30
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
648 PciDs30
.ImageLength
= RomHdr
.InitializationSize
;
649 PciDs30
.CodeRevision
= InFile
->CodeRevision
;
650 PciDs30
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
651 PciDs30
.MaxRuntimeImageLength
= 0; // to be fixed
652 PciDs30
.ConfigUtilityCodeHeaderOffset
= 0; // to be fixed
653 PciDs30
.DMTFCLPEntryPointOffset
= 0; // to be fixed
656 // If this is the last image, then set the LAST bit unless requested not
657 // to via the command-line -n argument.
659 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
660 if (mOptions
.Pci23
== 1) {
661 PciDs23
.Indicator
= INDICATOR_LAST
;
663 PciDs30
.Indicator
= INDICATOR_LAST
;}
665 if (mOptions
.Pci23
== 1) {
666 PciDs23
.Indicator
= 0;
668 PciDs30
.Indicator
= 0;
672 // Write the ROM header to the output file
674 if (fwrite (&RomHdr
, sizeof (RomHdr
), 1, OutFptr
) != 1) {
675 Error (NULL
, 0, 0002, "Failed to write ROM header to output file!", NULL
);
676 Status
= STATUS_ERROR
;
681 // Write pad bytes to align the PciDs
683 while (HeaderPadBytes
> 0) {
684 if (putc (0, OutFptr
) == EOF
) {
685 Error (NULL
, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL
);
686 Status
= STATUS_ERROR
;
693 // Write the PCI data structure header to the output file
695 if (mOptions
.Pci23
== 1) {
696 if (fwrite (&PciDs23
, sizeof (PciDs23
), 1, OutFptr
) != 1) {
697 Error (NULL
, 0, 0002, "Failed to write PCI ROM header to output file!", NULL
);
698 Status
= STATUS_ERROR
;
702 if (fwrite (&PciDs30
, sizeof (PciDs30
), 1, OutFptr
) != 1) {
703 Error (NULL
, 0, 0002, "Failed to write PCI ROM header to output file!", NULL
);
704 Status
= STATUS_ERROR
;
710 // Pad head to make it a multiple of 512 bytes
712 while (PadBytesBeforeImage
> 0) {
713 if (putc (~0, OutFptr
) == EOF
) {
714 Error (NULL
, 0, 2000, "Failed to write trailing pad bytes output file!", NULL
);
715 Status
= STATUS_ERROR
;
718 PadBytesBeforeImage
--;
721 // Now dump the input file's contents to the output file
723 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
724 Error (NULL
, 0, 0002, "Failed to write all file bytes to output file!", NULL
);
725 Status
= STATUS_ERROR
;
730 // Pad the rest of the image to make it a multiple of 512 bytes
732 while (PadBytesAfterImage
> 0) {
733 if (putc (~0, OutFptr
) == EOF
) {
734 Error (NULL
, 0, 2000, "Failed to write trailing pad bytes output file!", NULL
);
735 Status
= STATUS_ERROR
;
739 PadBytesAfterImage
--;
743 if (InFptr
!= NULL
) {
747 // Free up our buffers
749 if (Buffer
!= NULL
) {
753 if (CompressedBuffer
!= NULL
) {
754 free (CompressedBuffer
);
757 // Print the file name if errors occurred
759 if (Status
!= STATUS_SUCCESS
) {
760 Error (NULL
, 0, 0003, "Error parsing", "Error parsing file: %s", InFile
->FileName
);
777 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
778 PE32 image file, and then return the machine type in the supplied pointer.
782 Fptr File pointer to the already-opened PE32 file
783 MachineType Location to stuff the machine type of the PE32 file. This is needed
784 because the image may be Itanium-based, IA32, or EBC.
793 EFI_IMAGE_DOS_HEADER DosHeader
;
794 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
797 // Position to the start of the file
799 fseek (Fptr
, 0, SEEK_SET
);
802 // Read the DOS header
804 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
805 Error (NULL
, 0, 0004, "Failed to read the DOS stub from the input file!", NULL
);
809 // Check the magic number (0x5A4D)
811 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
812 Error (NULL
, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");
816 // Position into the file and check the PE signature
818 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
823 if (fread (&PeHdr
, sizeof (PeHdr
), 1, Fptr
) != 1) {
824 Error (NULL
, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL
);
830 // Check the PE signature in the header "PE\0\0"
832 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
833 Error (NULL
, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");
837 memcpy ((char *) MachineType
, &PeHdr
.Pe32
.FileHeader
.Machine
, 2);
839 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
840 *SubSystem
= PeHdr
.Pe32
.OptionalHeader
.Subsystem
;
841 } else if (PeHdr
.Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
842 *SubSystem
= PeHdr
.Pe32Plus
.OptionalHeader
.Subsystem
;
844 Error (NULL
, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");
848 if (mOptions
.Verbose
) {
849 VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem
);
853 // File was successfully identified as a PE32
855 return STATUS_SUCCESS
;
869 Given the Argc/Argv program arguments, and a pointer to an options structure,
870 parse the command-line options and check their validity.
875 Argc - standard C main() argument count
876 Argv[] - standard C main() argument list
877 Options - pointer to a structure to store the options in
881 STATUS_SUCCESS success
887 FILE_LIST
*PrevFileList
;
899 // Clear out the options
901 memset ((char *) Options
, 0, sizeof (OPTIONS
));
904 // To avoid compile warnings
906 FileList
= PrevFileList
= NULL
;
911 // Skip over the program name
917 // If no arguments, assume they want usage info
924 if ((stricmp(Argv
[0], "-h") == 0) || (stricmp(Argv
[0], "--help") == 0)) {
929 if ((stricmp(Argv
[0], "--version") == 0)) {
935 // Process until no more arguments
938 if (Argv
[0][0] == '-') {
940 // Vendor ID specified with -f
942 if (stricmp (Argv
[0], "-f") == 0) {
944 // Make sure there's another parameter
946 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
947 if (EFI_ERROR (Status
)) {
948 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
951 if (TempValue
>= 0x10000) {
952 Error (NULL
, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv
[1]);
955 Options
->VendId
= (UINT16
) TempValue
;
956 Options
->VendIdValid
= 1;
960 } else if (stricmp (Argv
[0], "-i") == 0) {
962 // Device ID specified with -i
963 // Make sure there's another parameter
965 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
966 if (EFI_ERROR (Status
)) {
967 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]);
974 Options
->DevId
= (UINT16
) TempValue
;
975 Options
->DevIdValid
= 1;
979 } else if ((stricmp (Argv
[0], "-o") == 0) || (stricmp (Argv
[0], "--output") == 0)) {
981 // Output filename specified with -o
982 // Make sure there's another parameter
984 if (Argv
[1] == NULL
|| Argv
[1][0] == '-') {
985 Error (NULL
, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv
[0]);
988 strcpy (Options
->OutFileName
, Argv
[1]);
992 } else if ((stricmp (Argv
[0], "-h") == 0) || (stricmp (Argv
[0], "--help") == 0)) {
998 } else if (stricmp (Argv
[0], "-b") == 0) {
1000 // Specify binary files with -b
1002 FileFlags
= FILE_FLAG_BINARY
;
1003 } else if ((stricmp (Argv
[0], "-e") == 0) || (stricmp (Argv
[0], "-ec") == 0)) {
1005 // Specify EFI files with -e. Specify EFI-compressed with -c.
1007 FileFlags
= FILE_FLAG_EFI
;
1008 if ((Argv
[0][2] == 'c') || (Argv
[0][2] == 'C')) {
1009 FileFlags
|= FILE_FLAG_COMPRESS
;
1012 // Specify not to set the LAST bit in the last file with -n
1014 } else if (stricmp (Argv
[0], "-n") == 0) {
1015 Options
->NoLast
= 1;
1016 } else if (((stricmp (Argv
[0], "-v") == 0)) || ((stricmp (Argv
[0], "--verbose") == 0))) {
1020 Options
->Verbose
= 1;
1021 } else if (stricmp (Argv
[0], "--debug") == 0) {
1022 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &DebugLevel
);
1023 if (EFI_ERROR (Status
)) {
1024 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1027 if (DebugLevel
> 9) {
1028 Error (NULL
, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv
[1]);
1031 if (DebugLevel
>=5 && DebugLevel
<=9) {
1032 Options
->Debug
= TRUE
;
1034 Options
->Debug
= FALSE
;
1038 } else if ((stricmp (Argv
[0], "--quiet") == 0) || (stricmp (Argv
[0], "-q") == 0)) {
1039 Options
->Quiet
= TRUE
;
1040 } else if ((stricmp (Argv
[0], "--dump") == 0) || (stricmp (Argv
[0], "-d") == 0)) {
1042 // -dump for dumping a ROM image. In this case, say that the device id
1043 // and vendor id are valid so we don't have to specify bogus ones on the
1046 Options
->DumpOption
= 1;
1048 Options
->VendIdValid
= 1;
1049 Options
->DevIdValid
= 1;
1050 FileFlags
= FILE_FLAG_BINARY
;
1051 } else if ((stricmp (Argv
[0], "-l") == 0) || (stricmp (Argv
[0], "--class-code") == 0)) {
1053 // Class code value for the next file in the list.
1054 // Make sure there's another parameter
1056 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
1057 if (EFI_ERROR (Status
)) {
1058 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1061 ClassCode
= (UINT32
) TempValue
;
1062 if (ClassCode
& 0xFF000000) {
1063 Error (NULL
, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv
[1]);
1064 return STATUS_ERROR
;
1066 if (FileList
!= NULL
&& FileList
->ClassCode
== 0) {
1067 FileList
->ClassCode
= ClassCode
;
1071 } else if ((stricmp (Argv
[0], "-r") == 0) || (stricmp (Argv
[0], "--Revision") == 0)) {
1073 // Code revision in the PCI data structure. The value is for the next
1074 // file in the list.
1075 // Make sure there's another parameter
1077 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
1078 if (EFI_ERROR (Status
)) {
1079 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1082 CodeRevision
= (UINT32
) TempValue
;
1083 if (CodeRevision
& 0xFFFF0000) {
1084 Error (NULL
, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv
[1]);
1085 return STATUS_ERROR
;
1087 if (FileList
!= NULL
&& FileList
->CodeRevision
== 0) {
1088 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1092 } else if ((stricmp (Argv
[0], "-p") == 0) || (stricmp (Argv
[0], "--pci23") == 0)) {
1094 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
1098 Error (NULL
, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv
[0]);
1099 return STATUS_ERROR
;
1103 // Not a slash-option argument. Must be a file name. Make sure they've specified
1104 // -e or -b already.
1106 if ((FileFlags
& (FILE_FLAG_BINARY
| FILE_FLAG_EFI
)) == 0) {
1107 Error (NULL
, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv
[0]);
1108 return STATUS_ERROR
;
1111 // Check Efi Option RomImage
1113 if ((FileFlags
& FILE_FLAG_EFI
) == FILE_FLAG_EFI
) {
1117 // Create a new file structure
1119 FileList
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
1120 if (FileList
== NULL
) {
1121 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!", NULL
);
1122 return STATUS_ERROR
;
1126 // set flag and class code for this image.
1128 memset ((char *) FileList
, 0, sizeof (FILE_LIST
));
1129 FileList
->FileName
= Argv
[0];
1130 FileList
->FileFlags
= FileFlags
;
1131 FileList
->ClassCode
= ClassCode
;
1132 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1136 if (Options
->FileList
== NULL
) {
1137 Options
->FileList
= FileList
;
1139 if (PrevFileList
== NULL
) {
1140 PrevFileList
= FileList
;
1142 PrevFileList
->Next
= FileList
;
1146 PrevFileList
= FileList
;
1156 // Must have specified some files
1158 if (Options
->FileList
== NULL
) {
1159 Error (NULL
, 0, 2000, "Invalid parameter", "Missing input file name!");
1160 return STATUS_ERROR
;
1164 // For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.
1167 if (!Options
->VendIdValid
) {
1168 Error (NULL
, 0, 2000, "Missing Vendor ID in command line", NULL
);
1169 return STATUS_ERROR
;
1172 if (!Options
->DevIdValid
) {
1173 Error (NULL
, 0, 2000, "Missing Device ID in command line", NULL
);
1174 return STATUS_ERROR
;
1188 Routine Description:
1190 Print version information for this utility.
1201 fprintf (stdout
, "%s Version %d.%d %s \n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
, __BUILD_VERSION
);
1211 Routine Description:
1213 Print usage information for this utility.
1228 fprintf (stdout
, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME
);
1231 // Copyright declaration
1233 fprintf (stdout
, "Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.\n\n");
1238 fprintf (stdout
, "Options:\n");
1239 fprintf (stdout
, " -o FileName, --output FileName\n\
1240 File will be created to store the output content.\n");
1241 fprintf (stdout
, " -e EfiFileName\n\
1242 EFI PE32 image files.\n");
1243 fprintf (stdout
, " -ec EfiFileName\n\
1244 EFI PE32 image files and will be compressed.\n");
1245 fprintf (stdout
, " -b BinFileName\n\
1246 Legacy binary files.\n");
1247 fprintf (stdout
, " -l ClassCode\n\
1248 Hex ClassCode in the PCI data structure header.\n");
1249 fprintf (stdout
, " -r Rev Hex Revision in the PCI data structure header.\n");
1250 fprintf (stdout
, " -n Not to automatically set the LAST bit in the last file.\n");
1251 fprintf (stdout
, " -f VendorId\n\
1252 Hex PCI Vendor ID for the device OpROM, must be specified\n");
1253 fprintf (stdout
, " -i DeviceId\n\
1254 Hex PCI Device ID for the device OpROM, must be specified\n");
1255 fprintf (stdout
, " -p, --pci23\n\
1256 Default layout meets PCI 3.0 specifications\n\
1257 specifying this flag will for a PCI 2.3 layout.\n");
1258 fprintf (stdout
, " -d, --dump\n\
1259 Dump the headers of an existing option ROM image.\n");
1260 fprintf (stdout
, " -v, --verbose\n\
1261 Turn on verbose output with informational messages.\n");
1262 fprintf (stdout
, " --version Show program's version number and exit.\n");
1263 fprintf (stdout
, " -h, --help\n\
1264 Show this help message and exit.\n");
1265 fprintf (stdout
, " -q, --quiet\n\
1266 Disable all messages except FATAL ERRORS.\n");
1267 fprintf (stdout
, " --debug [#,0-9]\n\
1268 Enable debug messages at level #.\n");
1278 Routine Description:
1280 Dump the headers of an existing option ROM image
1284 InFile - the file name of an existing option ROM image
1292 PCI_EXPANSION_ROM_HEADER PciRomHdr
;
1296 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr
;
1297 PCI_DATA_STRUCTURE PciDs23
;
1298 PCI_3_0_DATA_STRUCTURE PciDs30
;
1301 // Open the input file
1303 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
1304 Error (NULL
, 0, 0001, "Error opening file", InFile
->FileName
);
1308 // Go through the image and dump the header stuff for each
1313 // Save our postition in the file, since offsets in the headers
1314 // are relative to the particular image.
1316 ImageStart
= ftell (InFptr
);
1320 // Read the option ROM header. Have to assume a raw binary image for now.
1322 if (fread (&PciRomHdr
, sizeof (PciRomHdr
), 1, InFptr
) != 1) {
1323 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");
1328 // Dump the contents of the header
1330 fprintf (stdout
, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount
, (unsigned) ImageStart
);
1331 fprintf (stdout
, " ROM header contents\n");
1332 fprintf (stdout
, " Signature 0x%04X\n", PciRomHdr
.Signature
);
1333 fprintf (stdout
, " PCIR offset 0x%04X\n", PciRomHdr
.PcirOffset
);
1335 // Find PCI data structure
1337 if (fseek (InFptr
, ImageStart
+ PciRomHdr
.PcirOffset
, SEEK_SET
)) {
1338 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");
1342 // Read and dump the PCI data structure
1344 memset (&PciDs23
, 0, sizeof (PciDs23
));
1345 memset (&PciDs30
, 0, sizeof (PciDs30
));
1346 if (mOptions
.Pci23
== 1) {
1347 if (fread (&PciDs23
, sizeof (PciDs23
), 1, InFptr
) != 1) {
1348 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile
->FileName
);
1352 if (fread (&PciDs30
, sizeof (PciDs30
), 1, InFptr
) != 1) {
1353 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile
->FileName
);
1357 if (mOptions
.Verbose
) {
1358 VerboseMsg("Read PCI data structure from file %s", InFile
->FileName
);
1361 //fprintf (stdout, " PCI Data Structure\n");
1362 if (mOptions
.Pci23
== 1) {
1365 " Signature %c%c%c%c\n",
1366 (char) PciDs23
.Signature
,
1367 (char) (PciDs23
.Signature
>> 8),
1368 (char) (PciDs23
.Signature
>> 16),
1369 (char) (PciDs23
.Signature
>> 24)
1371 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs23
.VendorId
);
1372 fprintf (stdout
, " Device ID 0x%04X\n", PciDs23
.DeviceId
);
1373 fprintf (stdout
, " Length 0x%04X\n", PciDs23
.Length
);
1374 fprintf (stdout
, " Revision 0x%04X\n", PciDs23
.Revision
);
1377 " Class Code 0x%06X\n",
1378 (unsigned) (PciDs23
.ClassCode
[0] | (PciDs23
.ClassCode
[1] << 8) | (PciDs23
.ClassCode
[2] << 16))
1380 fprintf (stdout
, " Image size 0x%X\n", (unsigned) PciDs23
.ImageLength
* 512);
1381 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs23
.CodeRevision
);
1382 fprintf (stdout
, " Indicator 0x%02X", PciDs23
.Indicator
);
1386 " Signature %c%c%c%c\n",
1387 (char) PciDs30
.Signature
,
1388 (char) (PciDs30
.Signature
>> 8),
1389 (char) (PciDs30
.Signature
>> 16),
1390 (char) (PciDs30
.Signature
>> 24)
1392 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs30
.VendorId
);
1393 fprintf (stdout
, " Device ID 0x%04X\n", PciDs30
.DeviceId
);
1394 fprintf (stdout
, " Length 0x%04X\n", PciDs30
.Length
);
1395 fprintf (stdout
, " Revision 0x%04X\n", PciDs30
.Revision
);
1396 fprintf (stdout
, " DeviceListOffset 0x%02X\n", PciDs30
.DeviceListOffset
);
1399 " Class Code 0x%06X\n",
1400 (unsigned) (PciDs30
.ClassCode
[0] | (PciDs30
.ClassCode
[1] << 8) | (PciDs30
.ClassCode
[2] << 16))
1402 fprintf (stdout
, " Image size 0x%X\n", (unsigned) PciDs30
.ImageLength
* 512);
1403 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs30
.CodeRevision
);
1404 fprintf (stdout
, " MaxRuntimeImageLength 0x%02X\n", PciDs30
.MaxRuntimeImageLength
);
1405 fprintf (stdout
, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30
.ConfigUtilityCodeHeaderOffset
);
1406 fprintf (stdout
, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30
.DMTFCLPEntryPointOffset
);
1407 fprintf (stdout
, " Indicator 0x%02X", PciDs30
.Indicator
);
1410 // Print the indicator, used to flag the last image
1412 if (PciDs23
.Indicator
== INDICATOR_LAST
|| PciDs30
.Indicator
== INDICATOR_LAST
) {
1413 fprintf (stdout
, " (last image)\n");
1415 fprintf (stdout
, "\n");
1418 // Print the code type. If EFI code, then we can provide more info.
1420 if (mOptions
.Pci23
== 1) {
1421 fprintf (stdout
, " Code type 0x%02X", PciDs23
.CodeType
);
1423 fprintf (stdout
, " Code type 0x%02X", PciDs30
.CodeType
);
1425 if (PciDs23
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
|| PciDs30
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
1426 fprintf (stdout
, " (EFI image)\n");
1428 // Re-read the header as an EFI ROM header, then dump more info
1430 fprintf (stdout
, " EFI ROM header contents\n");
1431 if (fseek (InFptr
, ImageStart
, SEEK_SET
)) {
1432 Error (NULL
, 0, 5001, "Failed to re-seek to ROM header structure!", NULL
);
1436 if (fread (&EfiRomHdr
, sizeof (EfiRomHdr
), 1, InFptr
) != 1) {
1437 Error (NULL
, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL
);
1441 // Now dump more info
1443 fprintf (stdout
, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr
.EfiSignature
);
1446 " Compression Type 0x%04X ",
1447 EfiRomHdr
.CompressionType
1449 if (EfiRomHdr
.CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
1450 fprintf (stdout
, "(compressed)\n");
1452 fprintf (stdout
, "(not compressed)\n");
1457 " Machine type 0x%04X (%s)\n",
1458 EfiRomHdr
.EfiMachineType
,
1459 GetMachineTypeStr (EfiRomHdr
.EfiMachineType
)
1463 " Subsystem 0x%04X (%s)\n",
1464 EfiRomHdr
.EfiSubsystem
,
1465 GetSubsystemTypeStr (EfiRomHdr
.EfiSubsystem
)
1469 " EFI image offset 0x%04X (@0x%X)\n",
1470 EfiRomHdr
.EfiImageHeaderOffset
,
1471 EfiRomHdr
.EfiImageHeaderOffset
+ (unsigned) ImageStart
1478 fprintf (stdout
, "\n");
1481 // If code type is EFI image, then dump it as well?
1483 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
1486 // If last image, then we're done
1488 if (PciDs23
.Indicator
== INDICATOR_LAST
|| PciDs30
.Indicator
== INDICATOR_LAST
) {
1492 // Seek to the start of the next image
1494 if (mOptions
.Pci23
== 1) {
1495 if (fseek (InFptr
, ImageStart
+ (PciDs23
.ImageLength
* 512), SEEK_SET
)) {
1496 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to next image!");
1500 if (fseek (InFptr
, ImageStart
+ (PciDs30
.ImageLength
* 512), SEEK_SET
)) {
1501 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to next image!");
1517 Routine Description:
1519 GC_TODO: Add function description
1523 MachineType - GC_TODO: add argument description
1527 GC_TODO: add return values
1533 for (Index
= 0; mMachineTypes
[Index
].Name
!= NULL
; Index
++) {
1534 if (mMachineTypes
[Index
].Value
== MachineType
) {
1535 return mMachineTypes
[Index
].Name
;
1544 GetSubsystemTypeStr (
1545 UINT16 SubsystemType
1549 Routine Description:
1551 GC_TODO: Add function description
1555 SubsystemType - GC_TODO: add argument description
1559 GC_TODO: add return values
1565 for (Index
= 0; mSubsystemTypes
[Index
].Name
!= NULL
; Index
++) {
1566 if (mSubsystemTypes
[Index
].Value
== SubsystemType
) {
1567 return mSubsystemTypes
[Index
].Name
;