3 Copyright (c) 1999 - 2010, 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
;
243 Status
= STATUS_SUCCESS
;
246 // Try to open the input file
248 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
249 Error (NULL
, 0, 0001, "Error opening file", InFile
->FileName
);
253 // Seek to the end of the input file and get the file size. Then allocate
254 // a buffer to read it in to.
256 fseek (InFptr
, 0, SEEK_END
);
257 FileSize
= ftell (InFptr
);
258 if (mOptions
.Verbose
) {
259 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize
);
262 fseek (InFptr
, 0, SEEK_SET
);
263 Buffer
= (UINT8
*) malloc (FileSize
);
264 if (Buffer
== NULL
) {
265 Error (NULL
, 0, 4003, "Resource", "memory cannot be allocated!");
266 Status
= STATUS_ERROR
;
270 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
271 Error (NULL
, 0, 2000, "Invalid", "Failed to read all bytes from input file.");
272 Status
= STATUS_ERROR
;
276 // Total size must be an even multiple of 512 bytes, and can't exceed
277 // the option ROM image size.
279 TotalSize
= FileSize
;
280 if (TotalSize
& 0x1FF) {
281 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
284 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
285 Error (NULL
, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile
->FileName
, MAX_OPTION_ROM_SIZE
);
286 Status
= STATUS_ERROR
;
290 // Return the size to the caller so they can keep track of the running total.
295 // Crude check to make sure it's a legitimate ROM image
297 RomHdr
= (PCI_EXPANSION_ROM_HEADER
*) Buffer
;
298 if (RomHdr
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
299 Error (NULL
, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");
300 Status
= STATUS_ERROR
;
304 // Make sure the pointer to the PCI data structure is within the size of the image.
305 // Then check it for valid signature.
307 if ((RomHdr
->PcirOffset
> FileSize
) || (RomHdr
->PcirOffset
== 0)) {
308 Error (NULL
, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");
309 Status
= STATUS_ERROR
;
314 // Check the header is conform to PCI2.3 or PCI3.0
316 if (mOptions
.Pci23
== 1) {
317 PciDs23
= (PCI_DATA_STRUCTURE
*) (Buffer
+ RomHdr
->PcirOffset
);
318 if (PciDs23
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
319 Error (NULL
, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
320 Status
= STATUS_ERROR
;
325 // Default setting is PCI3.0 header
327 PciDs30
= (PCI_3_0_DATA_STRUCTURE
*)(Buffer
+ RomHdr
->PcirOffset
);
328 if (PciDs30
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
329 Error (NULL
, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
330 Status
= STATUS_ERROR
;
336 // ReSet Option Rom size
338 if (mOptions
.Pci23
== 1) {
339 PciDs23
->ImageLength
= (UINT16
) (TotalSize
/ 512);
341 PciDs30
->ImageLength
= (UINT16
) (TotalSize
/ 512);
345 // If this is the last image, then set the LAST bit unless requested not
346 // to via the command-line -n argument. Otherwise, make sure you clear it.
348 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
349 if (mOptions
.Pci23
== 1) {
350 PciDs23
->Indicator
= INDICATOR_LAST
;
352 PciDs30
->Indicator
= INDICATOR_LAST
;
355 if (mOptions
.Pci23
== 1) {
356 PciDs23
->Indicator
= 0;
358 PciDs30
->Indicator
= 0;
363 for (Index
= 0; Index
< FileSize
- 1; Index
++) {
364 ByteCheckSum
= (UINT8
) (ByteCheckSum
+ Buffer
[Index
]);
367 Buffer
[FileSize
- 1] = (UINT8
) ((~ByteCheckSum
) + 1);
368 if (mOptions
.Verbose
) {
369 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
;
454 // Try to open the input file
456 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
457 Error (NULL
, 0, 0001, "Open file error", "Error opening file: %s", InFile
->FileName
);
461 // Initialize our buffer pointers to null.
464 CompressedBuffer
= NULL
;
467 // Double-check the file to make sure it's what we expect it to be
469 Status
= CheckPE32File (InFptr
, &MachineType
, &SubSystem
);
470 if (Status
!= STATUS_SUCCESS
) {
474 // Seek to the end of the input file and get the file size
476 fseek (InFptr
, 0, SEEK_END
);
477 FileSize
= ftell (InFptr
);
480 // Get the size of the headers we're going to put in front of the image. The
481 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
483 if (sizeof (RomHdr
) & 0x03) {
484 HeaderPadBytes
= 4 - (sizeof (RomHdr
) & 0x03);
490 // For Pci3.0 to use the different data structure.
492 if (mOptions
.Pci23
== 1) {
493 HeaderSize
= sizeof (PCI_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
495 HeaderSize
= sizeof (PCI_3_0_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
498 if (mOptions
.Verbose
) {
499 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize
);
502 // Allocate memory for the entire file (in case we have to compress), then
503 // seek back to the beginning of the file and read it into our buffer.
505 Buffer
= (UINT8
*) malloc (FileSize
);
506 if (Buffer
== NULL
) {
507 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
508 Status
= STATUS_ERROR
;
512 fseek (InFptr
, 0, SEEK_SET
);
513 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
514 Error (NULL
, 0, 0004, "Error reading file", "File %s", InFile
->FileName
);
515 Status
= STATUS_ERROR
;
519 // Now determine the size of the final output file. It's either the header size
520 // plus the file's size, or the header size plus the compressed file size.
522 if ((InFile
->FileFlags
& FILE_FLAG_COMPRESS
) != 0) {
524 // Allocate a buffer into which we can compress the image, compress it,
525 // and use that size as the new size.
527 CompressedBuffer
= (UINT8
*) malloc (FileSize
);
528 if (CompressedBuffer
== NULL
) {
529 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
530 Status
= STATUS_ERROR
;
534 CompressedFileSize
= FileSize
;
535 Status
= EfiCompress (Buffer
, FileSize
, CompressedBuffer
, &CompressedFileSize
);
536 if (Status
!= STATUS_SUCCESS
) {
537 Error (NULL
, 0, 0007, "Error compressing file!", NULL
);
541 // Now compute the size, then swap buffer pointers.
543 if (mOptions
.Verbose
) {
544 VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize
);
547 TotalSize
= CompressedFileSize
+ HeaderSize
;
548 FileSize
= CompressedFileSize
;
549 TempBufferPtr
= Buffer
;
550 Buffer
= CompressedBuffer
;
551 CompressedBuffer
= TempBufferPtr
;
553 TotalSize
= FileSize
+ HeaderSize
;
556 // Total size must be an even multiple of 512 bytes
558 if (TotalSize
& 0x1FF) {
559 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
564 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
565 Error (NULL
, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile
->FileName
, MAX_OPTION_ROM_SIZE
);
566 Status
= STATUS_ERROR
;
570 // Return the size to the caller so they can keep track of the running total.
575 // Now fill in the ROM header. These values come from chapter 18 of the
576 // EFI 1.02 specification.
578 memset (&RomHdr
, 0, sizeof (RomHdr
));
579 RomHdr
.Signature
= PCI_EXPANSION_ROM_HEADER_SIGNATURE
;
580 RomHdr
.InitializationSize
= (UINT16
) (TotalSize
/ 512);
581 RomHdr
.EfiSignature
= EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
;
582 RomHdr
.EfiSubsystem
= SubSystem
;
583 RomHdr
.EfiMachineType
= MachineType
;
584 RomHdr
.EfiImageHeaderOffset
= (UINT16
) HeaderSize
;
585 RomHdr
.PcirOffset
= (UINT16
) (sizeof (RomHdr
) + HeaderPadBytes
);
587 // Set image as compressed or not
589 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
590 RomHdr
.CompressionType
= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
;
593 // Fill in the PCI data structure
595 if (mOptions
.Pci23
== 1) {
596 memset (&PciDs23
, 0, sizeof (PCI_DATA_STRUCTURE
));
598 memset (&PciDs30
, 0, sizeof (PCI_3_0_DATA_STRUCTURE
));
601 if (mOptions
.Pci23
== 1) {
602 PciDs23
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
603 PciDs23
.VendorId
= VendId
;
604 PciDs23
.DeviceId
= DevId
;
605 PciDs23
.Length
= (UINT16
) sizeof (PCI_DATA_STRUCTURE
);
606 PciDs23
.Revision
= 0;
608 // Class code and code revision from the command line (optional)
610 PciDs23
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
611 PciDs23
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
612 PciDs23
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
613 PciDs23
.ImageLength
= RomHdr
.InitializationSize
;
614 PciDs23
.CodeRevision
= InFile
->CodeRevision
;
615 PciDs23
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
617 PciDs30
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
618 PciDs30
.VendorId
= VendId
;
619 PciDs30
.DeviceId
= DevId
;
620 PciDs30
.DeviceListOffset
= 0; // to be fixed
621 PciDs30
.Length
= (UINT16
) sizeof (PCI_3_0_DATA_STRUCTURE
);
622 PciDs30
.Revision
= 0x3;
624 // Class code and code revision from the command line (optional)
626 PciDs30
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
627 PciDs30
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
628 PciDs30
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
629 PciDs30
.ImageLength
= RomHdr
.InitializationSize
;
630 PciDs30
.CodeRevision
= InFile
->CodeRevision
;
631 PciDs30
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
632 PciDs30
.MaxRuntimeImageLength
= 0; // to be fixed
633 PciDs30
.ConfigUtilityCodeHeaderOffset
= 0; // to be fixed
634 PciDs30
.DMTFCLPEntryPointOffset
= 0; // to be fixed
637 // If this is the last image, then set the LAST bit unless requested not
638 // to via the command-line -n argument.
640 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
641 if (mOptions
.Pci23
== 1) {
642 PciDs23
.Indicator
= INDICATOR_LAST
;
644 PciDs30
.Indicator
= INDICATOR_LAST
;}
646 if (mOptions
.Pci23
== 1) {
647 PciDs23
.Indicator
= 0;
649 PciDs30
.Indicator
= 0;
653 // Write the ROM header to the output file
655 if (fwrite (&RomHdr
, sizeof (RomHdr
), 1, OutFptr
) != 1) {
656 Error (NULL
, 0, 0002, "Failed to write ROM header to output file!", NULL
);
657 Status
= STATUS_ERROR
;
662 // Write pad bytes to align the PciDs
664 while (HeaderPadBytes
> 0) {
665 if (putc (0, OutFptr
) == EOF
) {
666 Error (NULL
, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL
);
667 Status
= STATUS_ERROR
;
674 // Write the PCI data structure header to the output file
676 if (mOptions
.Pci23
== 1) {
677 if (fwrite (&PciDs23
, sizeof (PciDs23
), 1, OutFptr
) != 1) {
678 Error (NULL
, 0, 0002, "Failed to write PCI ROM header to output file!", NULL
);
679 Status
= STATUS_ERROR
;
683 if (fwrite (&PciDs30
, sizeof (PciDs30
), 1, OutFptr
) != 1) {
684 Error (NULL
, 0, 0002, "Failed to write PCI ROM header to output file!", NULL
);
685 Status
= STATUS_ERROR
;
690 // Keep track of how many bytes left to write
692 TotalSize
-= HeaderSize
;
695 // Now dump the input file's contents to the output file
697 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
698 Error (NULL
, 0, 0002, "Failed to write all file bytes to output file!", NULL
);
699 Status
= STATUS_ERROR
;
703 TotalSize
-= FileSize
;
705 // Pad the rest of the image to make it a multiple of 512 bytes
707 while (TotalSize
> 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
;
718 if (InFptr
!= NULL
) {
722 // Free up our buffers
724 if (Buffer
!= NULL
) {
728 if (CompressedBuffer
!= NULL
) {
729 free (CompressedBuffer
);
732 // Print the file name if errors occurred
734 if (Status
!= STATUS_SUCCESS
) {
735 Error (NULL
, 0, 0003, "Error parsing", "Error parsing file: %s", InFile
->FileName
);
752 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
753 PE32 image file, and then return the machine type in the supplied pointer.
757 Fptr File pointer to the already-opened PE32 file
758 MachineType Location to stuff the machine type of the PE32 file. This is needed
759 because the image may be Itanium-based, IA32, or EBC.
768 EFI_IMAGE_DOS_HEADER DosHeader
;
769 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
772 // Position to the start of the file
774 fseek (Fptr
, 0, SEEK_SET
);
777 // Read the DOS header
779 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
780 Error (NULL
, 0, 0004, "Failed to read the DOS stub from the input file!", NULL
);
784 // Check the magic number (0x5A4D)
786 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
787 Error (NULL
, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");
791 // Position into the file and check the PE signature
793 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
798 if (fread (&PeHdr
, sizeof (PeHdr
), 1, Fptr
) != 1) {
799 Error (NULL
, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL
);
805 // Check the PE signature in the header "PE\0\0"
807 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
808 Error (NULL
, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");
812 memcpy ((char *) MachineType
, &PeHdr
.Pe32
.FileHeader
.Machine
, 2);
814 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
815 *SubSystem
= PeHdr
.Pe32
.OptionalHeader
.Subsystem
;
816 } else if (PeHdr
.Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
817 *SubSystem
= PeHdr
.Pe32Plus
.OptionalHeader
.Subsystem
;
819 Error (NULL
, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");
823 if (mOptions
.Verbose
) {
824 VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem
);
828 // File was successfully identified as a PE32
830 return STATUS_SUCCESS
;
844 Given the Argc/Argv program arguments, and a pointer to an options structure,
845 parse the command-line options and check their validity.
850 Argc - standard C main() argument count
851 Argv[] - standard C main() argument list
852 Options - pointer to a structure to store the options in
856 STATUS_SUCCESS success
862 FILE_LIST
*PrevFileList
;
874 // Clear out the options
876 memset ((char *) Options
, 0, sizeof (OPTIONS
));
879 // To avoid compile warnings
881 FileList
= PrevFileList
= NULL
;
886 // Skip over the program name
892 // If no arguments, assume they want usage info
899 if ((stricmp(Argv
[0], "-h") == 0) || (stricmp(Argv
[0], "--help") == 0)) {
904 if ((stricmp(Argv
[0], "--version") == 0)) {
910 // Process until no more arguments
913 if (Argv
[0][0] == '-') {
915 // Vendor ID specified with -f
917 if (stricmp (Argv
[0], "-f") == 0) {
919 // Make sure there's another parameter
921 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
922 if (EFI_ERROR (Status
)) {
923 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
926 if (TempValue
>= 0x10000) {
927 Error (NULL
, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv
[1]);
930 Options
->VendId
= (UINT16
) TempValue
;
931 Options
->VendIdValid
= 1;
935 } else if (stricmp (Argv
[0], "-i") == 0) {
937 // Device ID specified with -i
938 // Make sure there's another parameter
940 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
941 if (EFI_ERROR (Status
)) {
942 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
945 if (TempValue
>= 0x10000) {
946 Error (NULL
, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv
[1]);
949 Options
->DevId
= (UINT16
) TempValue
;
950 Options
->DevIdValid
= 1;
954 } else if ((stricmp (Argv
[0], "-o") == 0) || (stricmp (Argv
[0], "--output") == 0)) {
956 // Output filename specified with -o
957 // Make sure there's another parameter
959 if (Argv
[1] == NULL
|| Argv
[1][0] == '-') {
960 Error (NULL
, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv
[0]);
963 strcpy (Options
->OutFileName
, Argv
[1]);
967 } else if ((stricmp (Argv
[0], "-h") == 0) || (stricmp (Argv
[0], "--help") == 0)) {
973 } else if (stricmp (Argv
[0], "-b") == 0) {
975 // Specify binary files with -b
977 FileFlags
= FILE_FLAG_BINARY
;
978 } else if ((stricmp (Argv
[0], "-e") == 0) || (stricmp (Argv
[0], "-ec") == 0)) {
980 // Specify EFI files with -e. Specify EFI-compressed with -c.
982 FileFlags
= FILE_FLAG_EFI
;
983 if ((Argv
[0][2] == 'c') || (Argv
[0][2] == 'C')) {
984 FileFlags
|= FILE_FLAG_COMPRESS
;
987 // Specify not to set the LAST bit in the last file with -n
989 } else if (stricmp (Argv
[0], "-n") == 0) {
991 } else if (((stricmp (Argv
[0], "-v") == 0)) || ((stricmp (Argv
[0], "--verbose") == 0))) {
995 Options
->Verbose
= 1;
996 } else if (stricmp (Argv
[0], "--debug") == 0) {
997 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &DebugLevel
);
998 if (EFI_ERROR (Status
)) {
999 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1002 if (DebugLevel
> 9) {
1003 Error (NULL
, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv
[1]);
1006 if (DebugLevel
>=5 && DebugLevel
<=9) {
1007 Options
->Debug
= TRUE
;
1009 Options
->Debug
= FALSE
;
1013 } else if ((stricmp (Argv
[0], "--quiet") == 0) || (stricmp (Argv
[0], "-q") == 0)) {
1014 Options
->Quiet
= TRUE
;
1015 } else if ((stricmp (Argv
[0], "--dump") == 0) || (stricmp (Argv
[0], "-d") == 0)) {
1017 // -dump for dumping a ROM image. In this case, say that the device id
1018 // and vendor id are valid so we don't have to specify bogus ones on the
1021 Options
->DumpOption
= 1;
1023 Options
->VendIdValid
= 1;
1024 Options
->DevIdValid
= 1;
1025 FileFlags
= FILE_FLAG_BINARY
;
1026 } else if ((stricmp (Argv
[0], "-l") == 0) || (stricmp (Argv
[0], "--class-code") == 0)) {
1028 // Class code value for the next file in the list.
1029 // Make sure there's another parameter
1031 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
1032 if (EFI_ERROR (Status
)) {
1033 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1036 ClassCode
= (UINT32
) TempValue
;
1037 if (ClassCode
& 0xFF000000) {
1038 Error (NULL
, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv
[1]);
1039 return STATUS_ERROR
;
1041 if (FileList
!= NULL
&& FileList
->ClassCode
== 0) {
1042 FileList
->ClassCode
= ClassCode
;
1046 } else if ((stricmp (Argv
[0], "-r") == 0) || (stricmp (Argv
[0], "--Revision") == 0)) {
1048 // Code revision in the PCI data structure. The value is for the next
1049 // file in the list.
1050 // Make sure there's another parameter
1052 Status
= AsciiStringToUint64(Argv
[1], FALSE
, &TempValue
);
1053 if (EFI_ERROR (Status
)) {
1054 Error (NULL
, 0, 2000, "Invalid option value", "%s = %s", Argv
[0], Argv
[1]);
1057 CodeRevision
= (UINT32
) TempValue
;
1058 if (CodeRevision
& 0xFFFF0000) {
1059 Error (NULL
, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv
[1]);
1060 return STATUS_ERROR
;
1062 if (FileList
!= NULL
&& FileList
->CodeRevision
== 0) {
1063 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1067 } else if ((stricmp (Argv
[0], "-p") == 0) || (stricmp (Argv
[0], "--pci23") == 0)) {
1069 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
1073 Error (NULL
, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv
[0]);
1074 return STATUS_ERROR
;
1078 // Not a slash-option argument. Must be a file name. Make sure they've specified
1079 // -e or -b already.
1081 if ((FileFlags
& (FILE_FLAG_BINARY
| FILE_FLAG_EFI
)) == 0) {
1082 Error (NULL
, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv
[0]);
1083 return STATUS_ERROR
;
1086 // Check Efi Option RomImage
1088 if ((FileFlags
& FILE_FLAG_EFI
) == FILE_FLAG_EFI
) {
1092 // Create a new file structure
1094 FileList
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
1095 if (FileList
== NULL
) {
1096 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!", NULL
);
1097 return STATUS_ERROR
;
1101 // set flag and class code for this image.
1103 memset ((char *) FileList
, 0, sizeof (FILE_LIST
));
1104 FileList
->FileName
= Argv
[0];
1105 FileList
->FileFlags
= FileFlags
;
1106 FileList
->ClassCode
= ClassCode
;
1107 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1111 if (Options
->FileList
== NULL
) {
1112 Options
->FileList
= FileList
;
1114 if (PrevFileList
== NULL
) {
1115 PrevFileList
= FileList
;
1117 PrevFileList
->Next
= FileList
;
1121 PrevFileList
= FileList
;
1131 // Must have specified some files
1133 if (Options
->FileList
== NULL
) {
1134 Error (NULL
, 0, 2000, "Invalid parameter", "Missing input file name!");
1135 return STATUS_ERROR
;
1139 // For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.
1142 if (!Options
->VendIdValid
) {
1143 Error (NULL
, 0, 2000, "Missing Vendor ID in command line", NULL
);
1144 return STATUS_ERROR
;
1147 if (!Options
->DevIdValid
) {
1148 Error (NULL
, 0, 2000, "Missing Device ID in command line", NULL
);
1149 return STATUS_ERROR
;
1163 Routine Description:
1165 Print version information for this utility.
1176 fprintf (stdout
, "%s Version %d.%d %s \n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
, __BUILD_VERSION
);
1186 Routine Description:
1188 Print usage information for this utility.
1203 fprintf (stdout
, "Usage: %s [options] [file name<s>] \n\n", UTILITY_NAME
);
1206 // Copyright declaration
1208 fprintf (stdout
, "Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.\n\n");
1213 fprintf (stdout
, "Options:\n");
1214 fprintf (stdout
, " -o FileName, --output FileName\n\
1215 File will be created to store the ouput content.\n");
1216 fprintf (stdout
, " -e EfiFileName\n\
1217 EFI PE32 image files.\n");
1218 fprintf (stdout
, " -ec EfiFileName\n\
1219 EFI PE32 image files and will be compressed.\n");
1220 fprintf (stdout
, " -b BinFileName\n\
1221 Legacy binary files.\n");
1222 fprintf (stdout
, " -l ClassCode\n\
1223 Hex ClassCode in the PCI data structure header.\n");
1224 fprintf (stdout
, " -r Rev Hex Revision in the PCI data structure header.\n");
1225 fprintf (stdout
, " -n Not to automatically set the LAST bit in the last file.\n");
1226 fprintf (stdout
, " -f VendorId\n\
1227 Hex PCI Vendor ID for the device OpROM.\n");
1228 fprintf (stdout
, " -i DeviceId\n\
1229 Hex PCI Device ID for the device OpROM.\n");
1230 fprintf (stdout
, " -p, --pci23\n\
1231 Default layout meets PCI 3.0 specifications\n\
1232 specifying this flag will for a PCI 2.3 layout.\n");
1233 fprintf (stdout
, " -d, --dump\n\
1234 Dump the headers of an existing option ROM image.\n");
1235 fprintf (stdout
, " -v, --verbose\n\
1236 Turn on verbose output with informational messages.\n");
1237 fprintf (stdout
, " --version Show program's version number and exit.\n");
1238 fprintf (stdout
, " -h, --help\n\
1239 Show this help message and exit.\n");
1240 fprintf (stdout
, " -q, --quiet\n\
1241 Disable all messages except FATAL ERRORS.\n");
1242 fprintf (stdout
, " --debug [#,0-9]\n\
1243 Enable debug messages at level #.\n");
1253 Routine Description:
1255 Dump the headers of an existing option ROM image
1259 InFile - the file name of an existing option ROM image
1267 PCI_EXPANSION_ROM_HEADER PciRomHdr
;
1271 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr
;
1272 PCI_DATA_STRUCTURE PciDs23
;
1273 PCI_3_0_DATA_STRUCTURE PciDs30
;
1276 // Open the input file
1278 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
1279 Error (NULL
, 0, 0001, "Error opening file", InFile
->FileName
);
1283 // Go through the image and dump the header stuff for each
1288 // Save our postition in the file, since offsets in the headers
1289 // are relative to the particular image.
1291 ImageStart
= ftell (InFptr
);
1295 // Read the option ROM header. Have to assume a raw binary image for now.
1297 if (fread (&PciRomHdr
, sizeof (PciRomHdr
), 1, InFptr
) != 1) {
1298 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");
1303 // Dump the contents of the header
1305 fprintf (stdout
, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount
, (unsigned) ImageStart
);
1306 fprintf (stdout
, " ROM header contents\n");
1307 fprintf (stdout
, " Signature 0x%04X\n", PciRomHdr
.Signature
);
1308 fprintf (stdout
, " PCIR offset 0x%04X\n", PciRomHdr
.PcirOffset
);
1310 // Find PCI data structure
1312 if (fseek (InFptr
, ImageStart
+ PciRomHdr
.PcirOffset
, SEEK_SET
)) {
1313 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");
1317 // Read and dump the PCI data structure
1319 memset (&PciDs23
, 0, sizeof (PciDs23
));
1320 memset (&PciDs30
, 0, sizeof (PciDs30
));
1321 if (mOptions
.Pci23
== 1) {
1322 if (fread (&PciDs23
, sizeof (PciDs23
), 1, InFptr
) != 1) {
1323 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile
->FileName
);
1327 if (fread (&PciDs30
, sizeof (PciDs30
), 1, InFptr
) != 1) {
1328 Error (NULL
, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile
->FileName
);
1332 if (mOptions
.Verbose
) {
1333 VerboseMsg("Read PCI data structure from file %s", InFile
->FileName
);
1336 //fprintf (stdout, " PCI Data Structure\n");
1337 if (mOptions
.Pci23
== 1) {
1340 " Signature %c%c%c%c\n",
1341 (char) PciDs23
.Signature
,
1342 (char) (PciDs23
.Signature
>> 8),
1343 (char) (PciDs23
.Signature
>> 16),
1344 (char) (PciDs23
.Signature
>> 24)
1346 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs23
.VendorId
);
1347 fprintf (stdout
, " Device ID 0x%04X\n", PciDs23
.DeviceId
);
1348 fprintf (stdout
, " Length 0x%04X\n", PciDs23
.Length
);
1349 fprintf (stdout
, " Revision 0x%04X\n", PciDs23
.Revision
);
1352 " Class Code 0x%06X\n",
1353 (unsigned) (PciDs23
.ClassCode
[0] | (PciDs23
.ClassCode
[1] << 8) | (PciDs23
.ClassCode
[2] << 16))
1355 fprintf (stdout
, " Image size 0x%X\n", (unsigned) PciDs23
.ImageLength
* 512);
1356 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs23
.CodeRevision
);
1357 fprintf (stdout
, " Indicator 0x%02X", PciDs23
.Indicator
);
1361 " Signature %c%c%c%c\n",
1362 (char) PciDs30
.Signature
,
1363 (char) (PciDs30
.Signature
>> 8),
1364 (char) (PciDs30
.Signature
>> 16),
1365 (char) (PciDs30
.Signature
>> 24)
1367 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs30
.VendorId
);
1368 fprintf (stdout
, " Device ID 0x%04X\n", PciDs30
.DeviceId
);
1369 fprintf (stdout
, " Length 0x%04X\n", PciDs30
.Length
);
1370 fprintf (stdout
, " Revision 0x%04X\n", PciDs30
.Revision
);
1371 fprintf (stdout
, " DeviceListOffset 0x%02X\n", PciDs30
.DeviceListOffset
);
1374 " Class Code 0x%06X\n",
1375 (unsigned) (PciDs30
.ClassCode
[0] | (PciDs30
.ClassCode
[1] << 8) | (PciDs30
.ClassCode
[2] << 16))
1377 fprintf (stdout
, " Image size 0x%X\n", (unsigned) PciDs30
.ImageLength
* 512);
1378 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs30
.CodeRevision
);
1379 fprintf (stdout
, " MaxRuntimeImageLength 0x%02X\n", PciDs30
.MaxRuntimeImageLength
);
1380 fprintf (stdout
, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30
.ConfigUtilityCodeHeaderOffset
);
1381 fprintf (stdout
, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30
.DMTFCLPEntryPointOffset
);
1382 fprintf (stdout
, " Indicator 0x%02X", PciDs30
.Indicator
);
1385 // Print the indicator, used to flag the last image
1387 if (PciDs23
.Indicator
== INDICATOR_LAST
|| PciDs30
.Indicator
== INDICATOR_LAST
) {
1388 fprintf (stdout
, " (last image)\n");
1390 fprintf (stdout
, "\n");
1393 // Print the code type. If EFI code, then we can provide more info.
1395 if (mOptions
.Pci23
== 1) {
1396 fprintf (stdout
, " Code type 0x%02X", PciDs23
.CodeType
);
1398 fprintf (stdout
, " Code type 0x%02X", PciDs30
.CodeType
);
1400 if (PciDs23
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
|| PciDs30
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
1401 fprintf (stdout
, " (EFI image)\n");
1403 // Re-read the header as an EFI ROM header, then dump more info
1405 fprintf (stdout
, " EFI ROM header contents\n");
1406 if (fseek (InFptr
, ImageStart
, SEEK_SET
)) {
1407 Error (NULL
, 0, 5001, "Failed to re-seek to ROM header structure!", NULL
);
1411 if (fread (&EfiRomHdr
, sizeof (EfiRomHdr
), 1, InFptr
) != 1) {
1412 Error (NULL
, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL
);
1416 // Now dump more info
1418 fprintf (stdout
, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr
.EfiSignature
);
1421 " Compression Type 0x%04X ",
1422 EfiRomHdr
.CompressionType
1424 if (EfiRomHdr
.CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
1425 fprintf (stdout
, "(compressed)\n");
1427 fprintf (stdout
, "(not compressed)\n");
1432 " Machine type 0x%04X (%s)\n",
1433 EfiRomHdr
.EfiMachineType
,
1434 GetMachineTypeStr (EfiRomHdr
.EfiMachineType
)
1438 " Subsystem 0x%04X (%s)\n",
1439 EfiRomHdr
.EfiSubsystem
,
1440 GetSubsystemTypeStr (EfiRomHdr
.EfiSubsystem
)
1444 " EFI image offset 0x%04X (@0x%X)\n",
1445 EfiRomHdr
.EfiImageHeaderOffset
,
1446 EfiRomHdr
.EfiImageHeaderOffset
+ (unsigned) ImageStart
1453 fprintf (stdout
, "\n");
1456 // If code type is EFI image, then dump it as well?
1458 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
1461 // If last image, then we're done
1463 if (PciDs23
.Indicator
== INDICATOR_LAST
|| PciDs30
.Indicator
== INDICATOR_LAST
) {
1467 // Seek to the start of the next image
1469 if (mOptions
.Pci23
== 1) {
1470 if (fseek (InFptr
, ImageStart
+ (PciDs23
.ImageLength
* 512), SEEK_SET
)) {
1471 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to next image!");
1475 if (fseek (InFptr
, ImageStart
+ (PciDs30
.ImageLength
* 512), SEEK_SET
)) {
1476 Error (NULL
, 0, 3001, "Not supported", "Failed to seek to next image!");
1492 Routine Description:
1494 GC_TODO: Add function description
1498 MachineType - GC_TODO: add argument description
1502 GC_TODO: add return values
1508 for (Index
= 0; mMachineTypes
[Index
].Name
!= NULL
; Index
++) {
1509 if (mMachineTypes
[Index
].Value
== MachineType
) {
1510 return mMachineTypes
[Index
].Name
;
1519 GetSubsystemTypeStr (
1520 UINT16 SubsystemType
1524 Routine Description:
1526 GC_TODO: Add function description
1530 SubsystemType - GC_TODO: add argument description
1534 GC_TODO: add return values
1540 for (Index
= 0; mSubsystemTypes
[Index
].Name
!= NULL
; Index
++) {
1541 if (mSubsystemTypes
[Index
].Value
== SubsystemType
) {
1542 return mSubsystemTypes
[Index
].Name
;