3 Copyright (c) 1999-2006 Intel Corporation. All rights reserved
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Utility program to create an EFI option ROM image from binary and
28 #include <Common/UefiBaseTypes.h>
29 #include <Common/EfiImage.h> // for PE32 structure definitions
30 #include <Common/MultiPhase.h>
32 #include <IndustryStandard/pci22.h> // for option ROM header structures
35 #include "CommonLib.h"
38 // Version of this utility
40 #define UTILITY_NAME "EfiRom"
41 #define UTILITY_MAJOR_VERSION 2
42 #define UTILITY_MINOR_VERSION 5
45 // Define some status return values
47 #define STATUS_SUCCESS 0
48 #define STATUS_WARNING 1
49 #define STATUS_ERROR 2
52 // Define the max length of a filename
56 #define DEFAULT_OUTPUT_EXTENSION ".rom"
59 // Max size for an option ROM image
61 #define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB
63 // Values for the indicator field in the PCI data structure
65 #define INDICATOR_LAST 0x80 // last file in series of files
67 // Masks for the FILE_LIST.FileFlags field
69 #define FILE_FLAG_BINARY 0x01
70 #define FILE_FLAG_EFI 0x02
71 #define FILE_FLAG_COMPRESS 0x04
74 // Use this linked list structure to keep track of all the filenames
75 // specified on the command line.
77 typedef struct _FILE_LIST
{
78 struct _FILE_LIST
*Next
;
86 // Use this to track our command-line options
89 INT8 OutFileName
[MAX_PATH
];
101 // Make a global structure to keep track of command-line options
103 static OPTIONS mOptions
;
106 // Use these to convert from machine type value to a named type
113 static STRING_LOOKUP mMachineTypes
[] = {
114 EFI_IMAGE_MACHINE_IA32
,
116 EFI_IMAGE_MACHINE_IA64
,
118 EFI_IMAGE_MACHINE_EBC
,
124 static STRING_LOOKUP mSubsystemTypes
[] = {
125 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
127 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
128 "EFI boot service driver",
129 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
130 "EFI runtime driver",
135 // Function prototypes
196 GetSubsystemTypeStr (
208 Given an EFI image filename, create a ROM-able image by creating an option
209 ROM header and PCI data structure, filling them in, and then writing the
210 option ROM header + PCI data structure + EFI image out to the output file.
214 Argc - standard C main() argument count
216 Argv - standard C main() argument list
224 // GC_TODO: ] - add argument and description to function comment
233 Status
= STATUS_SUCCESS
;
237 // Parse the command line arguments
239 if (ParseCommandLine (Argc
, Argv
, &mOptions
)) {
243 // If dumping an image, then do that and quit
245 if (mOptions
.DumpOption
) {
246 DumpImage (mOptions
.FileList
);
250 // Determine the output filename. Either what they specified on
251 // the command line, or the first input filename with a different extension.
253 if (!mOptions
.OutFileName
[0]) {
254 strcpy (mOptions
.OutFileName
, mOptions
.FileList
->FileName
);
256 // Find the last . on the line and replace the filename extension with
259 for (Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
) - 1;
260 (Ext
>= mOptions
.OutFileName
) && (*Ext
!= '.') && (*Ext
!= '\\');
265 // If dot here, then insert extension here, otherwise append
268 Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
);
271 strcpy (Ext
, DEFAULT_OUTPUT_EXTENSION
);
274 // Make sure we don't have the same filename for input and output files
276 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
277 if (stricmp (mOptions
.OutFileName
, FList
->FileName
) == 0) {
278 Status
= STATUS_ERROR
;
281 "ERROR: Input and output file names must be different - %s = %s\n",
289 // Now open our output file
291 if ((FptrOut
= fopen (mOptions
.OutFileName
, "w+b")) == NULL
) {
292 fprintf (stdout
, "ERROR: Failed to open output file %s\n", mOptions
.OutFileName
);
296 // Process all our files
299 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
301 if (FList
->FileFlags
& FILE_FLAG_EFI
) {
302 if (mOptions
.Verbose
) {
303 fprintf (stdout
, "Processing EFI file %s\n", FList
->FileName
);
306 Status
= ProcessEfiFile (FptrOut
, FList
, mOptions
.VendId
, mOptions
.DevId
, &Size
);
307 } else if (FList
->FileFlags
& FILE_FLAG_BINARY
) {
308 if (mOptions
.Verbose
) {
309 fprintf (stdout
, "Processing binary file %s\n", FList
->FileName
);
312 Status
= ProcessBinFile (FptrOut
, FList
, &Size
);
314 fprintf (stdout
, "ERROR: File not specified as EFI or binary: %s\n", FList
->FileName
);
315 Status
= STATUS_ERROR
;
318 if (mOptions
.Verbose
) {
319 fprintf (stdout
, " Output size = 0x%X\n", Size
);
322 if (Status
!= STATUS_SUCCESS
) {
331 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
334 "ERROR: Option ROM image size exceeds limit 0x%X bytes\n",
337 Status
= STATUS_ERROR
;
341 if (FptrOut
!= NULL
) {
345 // Clean up our file list
347 while (mOptions
.FileList
!= NULL
) {
348 FList
= mOptions
.FileList
->Next
;
349 free (mOptions
.FileList
);
350 mOptions
.FileList
= FList
;
367 Process a binary input file.
371 OutFptr - file pointer to output binary ROM image file we're creating
372 InFile - structure contains information on the binary file to process
373 Size - pointer to where to return the size added to the output file
386 PCI_EXPANSION_ROM_HEADER
*RomHdr
;
387 PCI_DATA_STRUCTURE
*PciDs
;
391 Status
= STATUS_SUCCESS
;
394 // Try to open the input file
396 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
397 fprintf (stdout
, "ERROR: Failed to open input file %s\n", InFile
->FileName
);
401 // Seek to the end of the input file and get the file size. Then allocate
402 // a buffer to read it in to.
404 fseek (InFptr
, 0, SEEK_END
);
405 FileSize
= ftell (InFptr
);
406 if (mOptions
.Verbose
) {
407 fprintf (stdout
, " File size = 0x%X\n", FileSize
);
410 fseek (InFptr
, 0, SEEK_SET
);
411 Buffer
= (INT8
*) malloc (FileSize
);
412 if (Buffer
== NULL
) {
413 fprintf (stdout
, "ERROR: Memory allocation failed\n");
414 Status
= STATUS_ERROR
;
418 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
419 fprintf (stdout
, "ERROR: Failed to read all bytes from input file\n");
420 Status
= STATUS_ERROR
;
424 // Total size must be an even multiple of 512 bytes, and can't exceed
425 // the option ROM image size.
427 TotalSize
= FileSize
;
428 if (TotalSize
& 0x1FF) {
429 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
432 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
435 "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
439 Status
= STATUS_ERROR
;
443 // Return the size to the caller so they can keep track of the running total.
448 // Crude check to make sure it's a legitimate ROM image
450 RomHdr
= (PCI_EXPANSION_ROM_HEADER
*) Buffer
;
451 if (RomHdr
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
452 fprintf (stdout
, "ERROR: ROM image file has invalid ROM signature\n");
453 Status
= STATUS_ERROR
;
457 // Make sure the pointer to the PCI data structure is within the size of the image.
458 // Then check it for valid signature.
460 if ((RomHdr
->PcirOffset
> FileSize
) || (RomHdr
->PcirOffset
== 0)) {
461 fprintf (stdout
, "ERROR: Invalid PCI data structure offset\n");
462 Status
= STATUS_ERROR
;
466 PciDs
= (PCI_DATA_STRUCTURE
*) (Buffer
+ RomHdr
->PcirOffset
);
467 if (PciDs
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
468 fprintf (stdout
, "ERROR: PCI data structure has invalid signature\n");
469 Status
= STATUS_ERROR
;
473 // If this is the last image, then set the LAST bit unless requested not
474 // to via the command-line -l argument. Otherwise, make sure you clear it.
476 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
477 PciDs
->Indicator
= INDICATOR_LAST
;
479 PciDs
->Indicator
= 0;
483 for (Index
= 0; Index
< FileSize
- 1; Index
++) {
484 ByteCheckSum
= (UINT8
) (ByteCheckSum
+ Buffer
[Index
]);
487 Buffer
[FileSize
- 1] = (UINT8
) ((~ByteCheckSum
) + 1);
488 fprintf (stdout
, "CheckSUm = %02x\n", (UINT32
) Buffer
[FileSize
- 1]);
491 // Now copy the input file contents out to the output file
493 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
494 fprintf (stdout
, "ERROR: Failed to write all file bytes to output file\n");
495 Status
= STATUS_ERROR
;
499 TotalSize
-= FileSize
;
501 // Pad the rest of the image to make it a multiple of 512 bytes
503 while (TotalSize
> 0) {
509 if (InFptr
!= NULL
) {
513 if (Buffer
!= NULL
) {
517 // Print the file name if errors occurred
519 if (Status
!= STATUS_SUCCESS
) {
520 fprintf (stdout
, "Error processing binary file %s\n", InFile
->FileName
);
539 Process a PE32 EFI file.
543 OutFptr - file pointer to output binary ROM image file we're creating
544 InFile - structure contains information on the PE32 file to process
545 VendId - vendor ID as required in the option ROM header
546 DevId - device ID as required in the option ROM header
547 Size - pointer to where to return the size added to the output file
557 EFI_PCI_EXPANSION_ROM_HEADER RomHdr
;
558 PCI_DATA_STRUCTURE PciDs
;
560 UINT32 CompressedFileSize
;
562 UINT8
*CompressedBuffer
;
563 UINT8
*TempBufferPtr
;
568 UINT32 HeaderPadBytes
;
571 // Try to open the input file
573 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
574 fprintf (stdout
, "ERROR: Failed to open input file %s\n", InFile
->FileName
);
578 // Initialize our buffer pointers to null.
581 CompressedBuffer
= NULL
;
584 // Double-check the file to make sure it's what we expect it to be
586 Status
= CheckPE32File (InFptr
, &MachineType
, &SubSystem
);
587 if (Status
!= STATUS_SUCCESS
) {
591 // Seek to the end of the input file and get the file size
593 fseek (InFptr
, 0, SEEK_END
);
594 FileSize
= ftell (InFptr
);
597 // Get the size of the headers we're going to put in front of the image. The
598 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
600 if (sizeof (RomHdr
) & 0x03) {
601 HeaderPadBytes
= 4 - (sizeof (RomHdr
) & 0x03);
606 HeaderSize
= sizeof (PCI_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
607 if (mOptions
.Verbose
) {
608 fprintf (stdout
, " File size = 0x%X\n", FileSize
);
611 // Allocate memory for the entire file (in case we have to compress), then
612 // seek back to the beginning of the file and read it into our buffer.
614 Buffer
= (INT8
*) malloc (FileSize
);
615 if (Buffer
== NULL
) {
616 fprintf (stdout
, "ERROR: Memory allocation failed\n");
617 Status
= STATUS_ERROR
;
621 fseek (InFptr
, 0, SEEK_SET
);
622 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
623 fprintf (stdout
, "ERROR: Failed to read all bytes from input file\n");
624 Status
= STATUS_ERROR
;
628 // Now determine the size of the final output file. It's either the header size
629 // plus the file's size, or the header size plus the compressed file size.
631 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
633 // Allocate a buffer into which we can compress the image, compress it,
634 // and use that size as the new size.
636 CompressedBuffer
= (INT8
*) malloc (FileSize
);
637 if (CompressedBuffer
== NULL
) {
638 fprintf (stdout
, "ERROR: Memory allocation failed\n");
639 Status
= STATUS_ERROR
;
643 CompressedFileSize
= FileSize
;
644 Status
= EfiCompress (Buffer
, FileSize
, CompressedBuffer
, &CompressedFileSize
);
645 if (Status
!= STATUS_SUCCESS
) {
646 fprintf (stdout
, "ERROR: Compression failed\n");
650 // Now compute the size, then swap buffer pointers.
652 if (mOptions
.Verbose
) {
653 fprintf (stdout
, " Comp size = 0x%X\n", CompressedFileSize
);
656 TotalSize
= CompressedFileSize
+ HeaderSize
;
657 FileSize
= CompressedFileSize
;
658 TempBufferPtr
= Buffer
;
659 Buffer
= CompressedBuffer
;
660 CompressedBuffer
= TempBufferPtr
;
662 TotalSize
= FileSize
+ HeaderSize
;
665 // Total size must be an even multiple of 512 bytes
667 if (TotalSize
& 0x1FF) {
668 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
673 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
676 "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
680 Status
= STATUS_ERROR
;
684 // Return the size to the caller so they can keep track of the running total.
689 // Now fill in the ROM header. These values come from chapter 18 of the
690 // EFI 1.02 specification.
692 memset (&RomHdr
, 0, sizeof (RomHdr
));
693 RomHdr
.Signature
= PCI_EXPANSION_ROM_HEADER_SIGNATURE
;
694 RomHdr
.InitializationSize
= (UINT16
) (TotalSize
/ 512);
695 RomHdr
.EfiSignature
= EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
;
696 RomHdr
.EfiSubsystem
= SubSystem
;
697 RomHdr
.EfiMachineType
= MachineType
;
698 RomHdr
.EfiImageHeaderOffset
= (UINT16
) HeaderSize
;
699 RomHdr
.PcirOffset
= (UINT16
) (sizeof (RomHdr
) + HeaderPadBytes
);
701 // Set image as compressed or not
703 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
704 RomHdr
.CompressionType
= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
;
707 // Fill in the PCI data structure
709 memset (&PciDs
, 0, sizeof (PCI_DATA_STRUCTURE
));
711 PciDs
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
712 PciDs
.VendorId
= VendId
;
713 PciDs
.DeviceId
= DevId
;
714 PciDs
.Length
= (UINT16
) sizeof (PCI_DATA_STRUCTURE
);
717 // Class code and code revision from the command line (optional)
719 PciDs
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
720 PciDs
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
721 PciDs
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
722 PciDs
.ImageLength
= RomHdr
.InitializationSize
;
723 PciDs
.CodeRevision
= InFile
->CodeRevision
;
724 PciDs
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
727 // If this is the last image, then set the LAST bit unless requested not
728 // to via the command-line -l argument.
730 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
731 PciDs
.Indicator
= INDICATOR_LAST
;
734 // Write the ROM header to the output file
736 if (fwrite (&RomHdr
, sizeof (RomHdr
), 1, OutFptr
) != 1) {
737 fprintf (stdout
, "ERROR: Failed to write ROM header to output file\n");
738 Status
= STATUS_ERROR
;
743 // Write pad bytes to align the PciDs
745 while (HeaderPadBytes
> 0) {
746 if (putc (0, OutFptr
) == EOF
) {
747 fprintf (stdout
, "ERROR: Failed to write ROM header pad bytes to output file\n");
748 Status
= STATUS_ERROR
;
755 // Write the PCI data structure header to the output file
757 if (fwrite (&PciDs
, sizeof (PciDs
), 1, OutFptr
) != 1) {
758 fprintf (stdout
, "ERROR: Failed to write PCI ROM header to output file\n");
759 Status
= STATUS_ERROR
;
763 // Keep track of how many bytes left to write
765 TotalSize
-= HeaderSize
;
768 // Now dump the input file's contents to the output file
770 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
771 fprintf (stdout
, "ERROR: Failed to write all file bytes to output file\n");
772 Status
= STATUS_ERROR
;
776 TotalSize
-= FileSize
;
778 // Pad the rest of the image to make it a multiple of 512 bytes
780 while (TotalSize
> 0) {
781 if (putc (~0, OutFptr
) == EOF
) {
782 fprintf (stdout
, "ERROR: Failed to write trailing pad bytes output file\n");
783 Status
= STATUS_ERROR
;
791 if (InFptr
!= NULL
) {
796 // Free up our buffers
798 if (Buffer
!= NULL
) {
802 if (CompressedBuffer
!= NULL
) {
803 free (CompressedBuffer
);
806 // Print the file name if errors occurred
808 if (Status
!= STATUS_SUCCESS
) {
809 fprintf (stdout
, "Error processing EFI file %s\n", InFile
->FileName
);
826 GC_TODO: Add function description
830 Fptr - GC_TODO: add argument description
831 MachineType - GC_TODO: add argument description
832 SubSystem - GC_TODO: add argument description
836 GC_TODO: add return values
844 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
845 PE32 image file, and then return the machine type in the supplied pointer.
849 Fptr File pointer to the already-opened PE32 file
850 MachineType Location to stuff the machine type of the PE32 file. This is needed
851 because the image may be Itanium-based, IA32, or EBC.
859 EFI_IMAGE_DOS_HEADER DosHeader
;
860 EFI_IMAGE_FILE_HEADER FileHdr
;
861 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
865 // Position to the start of the file
867 fseek (Fptr
, 0, SEEK_SET
);
870 // Read the DOS header
872 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
873 fprintf (stdout
, "ERROR: Failed to read the DOS stub from the input file\n");
877 // Check the magic number (0x5A4D)
879 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
880 fprintf (stdout
, "ERROR: Input file does not appear to be a PE32 image (magic number)\n");
884 // Position into the file and check the PE signature
886 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
887 if (fread (&PESig
, sizeof (PESig
), 1, Fptr
) != 1) {
888 fprintf (stdout
, "ERROR: Failed to read PE signature bytes from input file\n");
892 // Check the PE signature in the header "PE\0\0"
894 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
895 fprintf (stdout
, "ERROR: Input file does not appear to be a PE32 image (signature)\n");
899 // Read the file header and stuff their MachineType
901 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
902 fprintf (stdout
, "ERROR: Failed to read PE file header from input file\n");
906 memcpy ((char *) MachineType
, &FileHdr
.Machine
, 2);
909 // Read the optional header so we can get the subsystem
911 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
912 fprintf (stdout
, "ERROR: Failed to read COFF optional header from input file\n");
916 *SubSystem
= OptionalHdr
.Subsystem
;
917 if (mOptions
.Verbose
) {
918 fprintf (stdout
, " Got subsystem = 0x%X from image\n", (int) *SubSystem
);
923 return STATUS_SUCCESS
;
937 Given the Argc/Argv program arguments, and a pointer to an options structure,
938 parse the command-line options and check their validity.
943 Argc - standard C main() argument count
944 Argv[] - standard C main() argument list
945 Options - pointer to a structure to store the options in
949 STATUS_SUCCESS success
957 FILE_LIST
*PrevFileList
;
965 // Clear out the options
967 memset ((char *) Options
, 0, sizeof (OPTIONS
));
970 // To avoid compile warnings
972 FileList
= PrevFileList
= NULL
;
977 // Skip over the program name
983 // If no arguments, assume they want usage info
990 if ((strcmp(Argv
[0], "-h") == 0) || (strcmp(Argv
[0], "--help") == 0) ||
991 (strcmp(Argv
[0], "-?") == 0) || (strcmp(Argv
[0], "/?") == 0)) {
996 if ((strcmp(Argv
[0], "-V") == 0) || (strcmp(Argv
[0], "--version") == 0)) {
1002 // Process until no more arguments
1005 if ((Argv
[0][0] == '-') || (Argv
[0][0] == '/')) {
1007 // To simplify string comparisons, replace slashes with dashes
1012 // Vendor ID specified with -v
1014 if (stricmp (Argv
[0], "-v") == 0) {
1016 // Make sure there's another parameter
1019 Options
->VendId
= (UINT16
) strtol (Argv
[1], NULL
, 16);
1020 Options
->VendIdValid
= 1;
1024 "ERROR: Missing Vendor ID with %s\n\n",
1028 return STATUS_ERROR
;
1033 } else if (stricmp (Argv
[0], "-d") == 0) {
1035 // Device ID specified with -d
1036 // Make sure there's another parameter
1039 Options
->DevId
= (UINT16
) strtol (Argv
[1], NULL
, 16);
1040 Options
->DevIdValid
= 1;
1044 "ERROR: Missing Device ID with %s\n\n",
1048 return STATUS_ERROR
;
1053 } else if (stricmp (Argv
[0], "-o") == 0) {
1055 // Output filename specified with -o
1056 // Make sure there's another parameter
1059 strcpy (Options
->OutFileName
, Argv
[1]);
1063 "ERROR: Missing output file name with %s\n\n",
1067 return STATUS_ERROR
;
1072 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1077 return STATUS_ERROR
;
1078 } else if (stricmp (Argv
[0], "-b") == 0) {
1080 // Specify binary files with -b
1082 FileFlags
= (FileFlags
&~FILE_FLAG_EFI
) | FILE_FLAG_BINARY
;
1083 } else if ((stricmp (Argv
[0], "-e") == 0) || (stricmp (Argv
[0], "-ec") == 0)) {
1085 // Specify EFI files with -e. Specify EFI-compressed with -ec.
1087 FileFlags
= (FileFlags
&~FILE_FLAG_BINARY
) | FILE_FLAG_EFI
;
1088 if ((Argv
[0][2] == 'c') || (Argv
[0][2] == 'C')) {
1089 FileFlags
|= FILE_FLAG_COMPRESS
;
1092 // Specify not to set the LAST bit in the last file with -l
1094 } else if (stricmp (Argv
[0], "-l") == 0) {
1095 Options
->NoLast
= 1;
1096 } else if (stricmp (Argv
[0], "-p") == 0) {
1098 // -v for verbose would have been nicer, but it's already used. Let's use
1099 // -p for prolix (wordy) output
1101 Options
->Verbose
= 1;
1102 } else if (stricmp (Argv
[0], "-dump") == 0) {
1104 // -dump for dumping a ROM image. In this case, say that the device id
1105 // and vendor id are valid so we don't have to specify bogus ones on the
1108 Options
->DumpOption
= 1;
1110 Options
->VendIdValid
= 1;
1111 Options
->DevIdValid
= 1;
1112 FileFlags
= FILE_FLAG_BINARY
;
1113 } else if (stricmp (Argv
[0], "-cc") == 0) {
1115 // Class code value for the next file in the list.
1116 // Make sure there's another parameter
1120 // No error checking on the return value. Could check for LONG_MAX,
1121 // LONG_MIN, or 0 class code value if desired. Check range (3 bytes)
1124 ClassCode
= (UINT32
) strtol (Argv
[1], NULL
, 16);
1125 if (ClassCode
& 0xFF000000) {
1126 fprintf (stdout
, "ERROR: Class code %s out of range\n", Argv
[1]);
1127 return STATUS_ERROR
;
1132 "ERROR: Missing class code value with %s\n\n",
1136 return STATUS_ERROR
;
1141 } else if (stricmp (Argv
[0], "-rev") == 0) {
1143 // Code revision in the PCI data structure. The value is for the next
1144 // file in the list.
1145 // Make sure there's another parameter
1149 // No error checking on the return value. Could check for LONG_MAX,
1150 // LONG_MIN, or 0 value if desired. Check range (2 bytes)
1153 CodeRevision
= (UINT32
) strtol (Argv
[1], NULL
, 16);
1154 if (CodeRevision
& 0xFFFF0000) {
1155 fprintf (stdout
, "ERROR: Code revision %s out of range\n", Argv
[1]);
1156 return STATUS_ERROR
;
1161 "ERROR: Missing code revision value with %s\n\n",
1165 return STATUS_ERROR
;
1171 fprintf (stdout
, "ERROR: Invalid option specified: %s\n\n", Argv
[0]);
1173 return STATUS_ERROR
;
1177 // Not a slash-option argument. Must be a file name. Make sure they've specified
1178 // -e or -b already.
1180 if ((FileFlags
& (FILE_FLAG_BINARY
| FILE_FLAG_EFI
)) == 0) {
1181 fprintf (stdout
, "ERROR: Missing -e or -b with input file %s\n", Argv
[0]);
1182 return STATUS_ERROR
;
1185 // Create a new file structure
1187 FileList
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
1188 if (FileList
== NULL
) {
1189 fprintf (stdout
, "ERROR: Memory allocation failure\n");
1190 return STATUS_ERROR
;
1193 memset ((char *) FileList
, 0, sizeof (FILE_LIST
));
1194 FileList
->FileName
= Argv
[0];
1195 FileList
->FileFlags
= FileFlags
;
1196 if (Options
->FileList
== NULL
) {
1197 Options
->FileList
= FileList
;
1199 if (PrevFileList
== NULL
) {
1200 PrevFileList
= FileList
;
1202 PrevFileList
->Next
= FileList
;
1206 PrevFileList
= FileList
;
1208 // Set the class code and code revision for this file, then reset the values.
1210 FileList
->ClassCode
= ClassCode
;
1211 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1222 // Make sure they specified a device ID and vendor ID
1224 if (!Options
->VendIdValid
) {
1225 fprintf (stdout
, "ERROR: Missing Vendor ID on command line\n\n");
1227 return STATUS_ERROR
;
1230 if (!Options
->DevIdValid
) {
1231 fprintf (stdout
, "ERROR: Missing Device ID on command line\n\n");
1233 return STATUS_ERROR
;
1236 // Must have specified some files
1238 if (Options
->FileList
== NULL
) {
1239 fprintf (stdout
, "ERROR: Missing input file name\n");
1241 return STATUS_ERROR
;
1254 Routine Description:
1256 Print version information for this utility.
1267 printf ("%s v%d.%d -EDK utility to create an option ROM image from a list of input files\n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
);
1268 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
1278 Routine Description:
1280 Print usage information for this utility.
1293 static const char *Msg
[] = {
1294 "\nUsage: efirom {-p} [-v VendorId] [-d DeviceId] {-o OutFileName} ",
1295 " [-e|-b] [FileName(s)]",
1297 " VendorId - required hex PCI Vendor ID for the device",
1298 " DeviceId - required hex PCI Device ID for the device",
1299 " OutFileName - optional output file name. Default is the first input",
1300 " file name with a "DEFAULT_OUTPUT_EXTENSION
" file extension",
1301 " FileNames - input PE32 or binary file name(s)",
1302 " BinFileName - input binary file name(s)",
1303 " -p - for verbose output",
1304 " -l - to not automatically set the LAST bit on the last file",
1305 " -b - following FileNames are binary files",
1306 " -e - following FileNames are EFI PE32 image files",
1307 " -ec - following FileNames are EFI PE32 image files, and should",
1308 " be compressed by this utility",
1309 " -cc ClassCode - to use hex ClassCode in the PCI data structure header for",
1310 " the following FileName",
1311 " -rev Revision - to use hex Revision in the PCI data structure header for",
1312 " the following FileName",
1313 " -dump - to dump the headers of an existing option ROM image",
1314 " -h,--help,-?,/? - to display help messages",
1315 " -V,--version - to display version information",
1317 "Example usage: EfiRom -v 0xABCD -d 0x1234 -b File1.bin File2.bin -e File1.efi File2.efi ",
1323 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
1324 fprintf (stdout
, "%s\n", Msg
[Index
]);
1335 Routine Description:
1337 GC_TODO: Add function description
1341 InFile - GC_TODO: add argument description
1345 GC_TODO: add return values
1349 PCI_EXPANSION_ROM_HEADER PciRomHdr
;
1353 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr
;
1354 PCI_DATA_STRUCTURE PciDs
;
1357 // Open the input file
1359 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
1362 "ERROR: Could not open input file %s\n",
1368 // Go through the image and dump the header stuff for each
1373 // Save our postition in the file, since offsets in the headers
1374 // are relative to the particular image.
1376 ImageStart
= ftell (InFptr
);
1380 // Read the option ROM header. Have to assume a raw binary image for now.
1382 if (fread (&PciRomHdr
, sizeof (PciRomHdr
), 1, InFptr
) != 1) {
1383 fprintf (stdout
, "ERROR: Failed to read PCI ROM header from file\n");
1388 // Dump the contents of the header
1390 fprintf (stdout
, "Image %d -- Offset 0x%X\n", ImageCount
, ImageStart
);
1391 fprintf (stdout
, " ROM header contents\n");
1392 fprintf (stdout
, " Signature 0x%04X\n", (UINT32
) PciRomHdr
.Signature
);
1393 fprintf (stdout
, " PCIR offset 0x%04X\n", (UINT32
) PciRomHdr
.PcirOffset
);
1395 // Find PCI data structure
1397 if (fseek (InFptr
, ImageStart
+ PciRomHdr
.PcirOffset
, SEEK_SET
)) {
1398 fprintf (stdout
, "ERROR: Failed to seek to PCI data structure\n");
1402 // Read and dump the PCI data structure
1404 if (fread (&PciDs
, sizeof (PciDs
), 1, InFptr
) != 1) {
1405 fprintf (stdout
, "ERROR: Failed to read PCI data structure from file\n");
1409 fprintf (stdout
, " PCI Data Structure\n");
1412 " Signature %c%c%c%c\n",
1413 (char) PciDs
.Signature
,
1414 (char) (PciDs
.Signature
>> 8),
1415 (char) (PciDs
.Signature
>> 16),
1416 (char) (PciDs
.Signature
>> 24)
1418 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs
.VendorId
);
1419 fprintf (stdout
, " Device ID 0x%04X\n", PciDs
.DeviceId
);
1422 " Class Code 0x%06X\n",
1423 (UINT32
) (PciDs
.ClassCode
[0] | (PciDs
.ClassCode
[1] << 8) | (PciDs
.ClassCode
[2] << 16))
1425 fprintf (stdout
, " Image size 0x%X\n", PciDs
.ImageLength
* 512);
1426 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs
.CodeRevision
);
1427 fprintf (stdout
, " Indicator 0x%02X", (UINT32
) PciDs
.Indicator
);
1429 // Print the indicator, used to flag the last image
1431 if (PciDs
.Indicator
== INDICATOR_LAST
) {
1432 fprintf (stdout
, " (last image)\n");
1434 fprintf (stdout
, "\n");
1437 // Print the code type. If EFI code, then we can provide more info.
1439 fprintf (stdout
, " Code type 0x%02X", (UINT32
) PciDs
.CodeType
);
1440 if (PciDs
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
1441 fprintf (stdout
, " (EFI image)\n");
1443 // Re-read the header as an EFI ROM header, then dump more info
1445 fprintf (stdout
, " EFI ROM header contents\n");
1446 if (fseek (InFptr
, ImageStart
, SEEK_SET
)) {
1447 fprintf (stdout
, "ERROR: Failed to re-seek to ROM header structure\n");
1451 if (fread (&EfiRomHdr
, sizeof (EfiRomHdr
), 1, InFptr
) != 1) {
1452 fprintf (stdout
, "ERROR: Failed to read EFI PCI ROM header from file\n");
1456 // Now dump more info
1458 fprintf (stdout
, " EFI Signature 0x%04X\n", EfiRomHdr
.EfiSignature
);
1461 " Compression Type 0x%04X ",
1462 (UINT32
) EfiRomHdr
.CompressionType
1464 if (EfiRomHdr
.CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
1465 fprintf (stdout
, "(compressed)\n");
1467 fprintf (stdout
, "(not compressed)\n");
1472 " Machine type 0x%04X (%s)\n",
1473 EfiRomHdr
.EfiMachineType
,
1474 GetMachineTypeStr (EfiRomHdr
.EfiMachineType
)
1478 " Subsystem 0x%04X (%s)\n",
1479 EfiRomHdr
.EfiSubsystem
,
1480 GetSubsystemTypeStr (EfiRomHdr
.EfiSubsystem
)
1484 " EFI image offset 0x%04X (@0x%X)\n",
1485 (UINT32
) EfiRomHdr
.EfiImageHeaderOffset
,
1486 (UINT32
) (EfiRomHdr
.EfiImageHeaderOffset
+ ImageStart
)
1493 fprintf (stdout
, "\n");
1496 // If code type is EFI image, then dump it as well?
1498 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
1501 // If last image, then we're done
1503 if (PciDs
.Indicator
== INDICATOR_LAST
) {
1507 // Seek to the start of the next image
1509 if (fseek (InFptr
, ImageStart
+ (PciDs
.ImageLength
* 512), SEEK_SET
)) {
1510 fprintf (stdout
, "ERROR: Failed to seek to next image\n");
1525 Routine Description:
1527 GC_TODO: Add function description
1531 MachineType - GC_TODO: add argument description
1535 GC_TODO: add return values
1541 for (Index
= 0; mMachineTypes
[Index
].Name
!= NULL
; Index
++) {
1542 if (mMachineTypes
[Index
].Value
== MachineType
) {
1543 return mMachineTypes
[Index
].Name
;
1552 GetSubsystemTypeStr (
1553 UINT16 SubsystemType
1557 Routine Description:
1559 GC_TODO: Add function description
1563 SubsystemType - GC_TODO: add argument description
1567 GC_TODO: add return values
1573 for (Index
= 0; mSubsystemTypes
[Index
].Name
!= NULL
; Index
++) {
1574 if (mSubsystemTypes
[Index
].Value
== SubsystemType
) {
1575 return mSubsystemTypes
[Index
].Name
;