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
34 #include "EfiCompress.h"
35 #include "CommonLib.h"
38 // Version of this utility
40 #define UTILITY_VERSION "v2.5"
43 // Define some status return values
45 #define STATUS_SUCCESS 0
46 #define STATUS_WARNING 1
47 #define STATUS_ERROR 2
50 // Define the max length of a filename
54 #define DEFAULT_OUTPUT_EXTENSION ".rom"
57 // Max size for an option ROM image
59 #define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB
61 // Values for the indicator field in the PCI data structure
63 #define INDICATOR_LAST 0x80 // last file in series of files
65 // Masks for the FILE_LIST.FileFlags field
67 #define FILE_FLAG_BINARY 0x01
68 #define FILE_FLAG_EFI 0x02
69 #define FILE_FLAG_COMPRESS 0x04
72 // Use this linked list structure to keep track of all the filenames
73 // specified on the command line.
75 typedef struct _FILE_LIST
{
76 struct _FILE_LIST
*Next
;
84 // Use this to track our command-line options
87 INT8 OutFileName
[MAX_PATH
];
99 // Make a global structure to keep track of command-line options
101 static OPTIONS mOptions
;
104 // Use these to convert from machine type value to a named type
111 static STRING_LOOKUP mMachineTypes
[] = {
112 EFI_IMAGE_MACHINE_IA32
,
114 EFI_IMAGE_MACHINE_IA64
,
116 EFI_IMAGE_MACHINE_EBC
,
122 static STRING_LOOKUP mSubsystemTypes
[] = {
123 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
125 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
126 "EFI boot service driver",
127 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
128 "EFI runtime driver",
133 // Function prototypes
188 GetSubsystemTypeStr (
200 Given an EFI image filename, create a ROM-able image by creating an option
201 ROM header and PCI data structure, filling them in, and then writing the
202 option ROM header + PCI data structure + EFI image out to the output file.
206 Argc - standard C main() argument count
208 Argv - standard C main() argument list
216 // GC_TODO: ] - add argument and description to function comment
225 Status
= STATUS_SUCCESS
;
229 // Parse the command line arguments
231 if (ParseCommandLine (Argc
, Argv
, &mOptions
)) {
235 // If dumping an image, then do that and quit
237 if (mOptions
.DumpOption
) {
238 DumpImage (mOptions
.FileList
);
242 // Determine the output filename. Either what they specified on
243 // the command line, or the first input filename with a different extension.
245 if (!mOptions
.OutFileName
[0]) {
246 strcpy (mOptions
.OutFileName
, mOptions
.FileList
->FileName
);
248 // Find the last . on the line and replace the filename extension with
251 for (Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
) - 1;
252 (Ext
>= mOptions
.OutFileName
) && (*Ext
!= '.') && (*Ext
!= '\\');
257 // If dot here, then insert extension here, otherwise append
260 Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
);
263 strcpy (Ext
, DEFAULT_OUTPUT_EXTENSION
);
266 // Make sure we don't have the same filename for input and output files
268 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
269 if (stricmp (mOptions
.OutFileName
, FList
->FileName
) == 0) {
270 Status
= STATUS_ERROR
;
273 "ERROR: Input and output file names must be different - %s = %s\n",
281 // Now open our output file
283 if ((FptrOut
= fopen (mOptions
.OutFileName
, "w+b")) == NULL
) {
284 fprintf (stdout
, "ERROR: Failed to open output file %s\n", mOptions
.OutFileName
);
288 // Process all our files
291 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
293 if (FList
->FileFlags
& FILE_FLAG_EFI
) {
294 if (mOptions
.Verbose
) {
295 fprintf (stdout
, "Processing EFI file %s\n", FList
->FileName
);
298 Status
= ProcessEfiFile (FptrOut
, FList
, mOptions
.VendId
, mOptions
.DevId
, &Size
);
299 } else if (FList
->FileFlags
& FILE_FLAG_BINARY
) {
300 if (mOptions
.Verbose
) {
301 fprintf (stdout
, "Processing binary file %s\n", FList
->FileName
);
304 Status
= ProcessBinFile (FptrOut
, FList
, &Size
);
306 fprintf (stdout
, "ERROR: File not specified as EFI or binary: %s\n", FList
->FileName
);
307 Status
= STATUS_ERROR
;
310 if (mOptions
.Verbose
) {
311 fprintf (stdout
, " Output size = 0x%X\n", Size
);
314 if (Status
!= STATUS_SUCCESS
) {
323 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
326 "ERROR: Option ROM image size exceeds limit 0x%X bytes\n",
329 Status
= STATUS_ERROR
;
333 if (FptrOut
!= NULL
) {
337 // Clean up our file list
339 while (mOptions
.FileList
!= NULL
) {
340 FList
= mOptions
.FileList
->Next
;
341 free (mOptions
.FileList
);
342 mOptions
.FileList
= FList
;
359 Process a binary input file.
363 OutFptr - file pointer to output binary ROM image file we're creating
364 InFile - structure contains information on the binary file to process
365 Size - pointer to where to return the size added to the output file
378 PCI_EXPANSION_ROM_HEADER
*RomHdr
;
379 PCI_DATA_STRUCTURE
*PciDs
;
383 Status
= STATUS_SUCCESS
;
386 // Try to open the input file
388 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
389 fprintf (stdout
, "ERROR: Failed to open input file %s\n", InFile
->FileName
);
393 // Seek to the end of the input file and get the file size. Then allocate
394 // a buffer to read it in to.
396 fseek (InFptr
, 0, SEEK_END
);
397 FileSize
= ftell (InFptr
);
398 if (mOptions
.Verbose
) {
399 fprintf (stdout
, " File size = 0x%X\n", FileSize
);
402 fseek (InFptr
, 0, SEEK_SET
);
403 Buffer
= (INT8
*) malloc (FileSize
);
404 if (Buffer
== NULL
) {
405 fprintf (stdout
, "ERROR: Memory allocation failed\n");
406 Status
= STATUS_ERROR
;
410 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
411 fprintf (stdout
, "ERROR: Failed to read all bytes from input file\n");
412 Status
= STATUS_ERROR
;
416 // Total size must be an even multiple of 512 bytes, and can't exceed
417 // the option ROM image size.
419 TotalSize
= FileSize
;
420 if (TotalSize
& 0x1FF) {
421 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
424 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
427 "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
431 Status
= STATUS_ERROR
;
435 // Return the size to the caller so they can keep track of the running total.
440 // Crude check to make sure it's a legitimate ROM image
442 RomHdr
= (PCI_EXPANSION_ROM_HEADER
*) Buffer
;
443 if (RomHdr
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
444 fprintf (stdout
, "ERROR: ROM image file has invalid ROM signature\n");
445 Status
= STATUS_ERROR
;
449 // Make sure the pointer to the PCI data structure is within the size of the image.
450 // Then check it for valid signature.
452 if ((RomHdr
->PcirOffset
> FileSize
) || (RomHdr
->PcirOffset
== 0)) {
453 fprintf (stdout
, "ERROR: Invalid PCI data structure offset\n");
454 Status
= STATUS_ERROR
;
458 PciDs
= (PCI_DATA_STRUCTURE
*) (Buffer
+ RomHdr
->PcirOffset
);
459 if (PciDs
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
460 fprintf (stdout
, "ERROR: PCI data structure has invalid signature\n");
461 Status
= STATUS_ERROR
;
465 // If this is the last image, then set the LAST bit unless requested not
466 // to via the command-line -l argument. Otherwise, make sure you clear it.
468 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
469 PciDs
->Indicator
= INDICATOR_LAST
;
471 PciDs
->Indicator
= 0;
475 for (Index
= 0; Index
< FileSize
- 1; Index
++) {
476 ByteCheckSum
= (UINT8
) (ByteCheckSum
+ Buffer
[Index
]);
479 Buffer
[FileSize
- 1] = (UINT8
) ((~ByteCheckSum
) + 1);
480 fprintf (stdout
, "CheckSUm = %02x\n", (UINT32
) Buffer
[FileSize
- 1]);
483 // Now copy the input file contents out to the output file
485 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
486 fprintf (stdout
, "ERROR: Failed to write all file bytes to output file\n");
487 Status
= STATUS_ERROR
;
491 TotalSize
-= FileSize
;
493 // Pad the rest of the image to make it a multiple of 512 bytes
495 while (TotalSize
> 0) {
501 if (InFptr
!= NULL
) {
505 if (Buffer
!= NULL
) {
509 // Print the file name if errors occurred
511 if (Status
!= STATUS_SUCCESS
) {
512 fprintf (stdout
, "Error processing binary file %s\n", InFile
->FileName
);
531 Process a PE32 EFI file.
535 OutFptr - file pointer to output binary ROM image file we're creating
536 InFile - structure contains information on the PE32 file to process
537 VendId - vendor ID as required in the option ROM header
538 DevId - device ID as required in the option ROM header
539 Size - pointer to where to return the size added to the output file
549 EFI_PCI_EXPANSION_ROM_HEADER RomHdr
;
550 PCI_DATA_STRUCTURE PciDs
;
552 UINT32 CompressedFileSize
;
554 UINT8
*CompressedBuffer
;
555 UINT8
*TempBufferPtr
;
560 UINT32 HeaderPadBytes
;
563 // Try to open the input file
565 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
566 fprintf (stdout
, "ERROR: Failed to open input file %s\n", InFile
->FileName
);
570 // Initialize our buffer pointers to null.
573 CompressedBuffer
= NULL
;
576 // Double-check the file to make sure it's what we expect it to be
578 Status
= CheckPE32File (InFptr
, &MachineType
, &SubSystem
);
579 if (Status
!= STATUS_SUCCESS
) {
583 // Seek to the end of the input file and get the file size
585 fseek (InFptr
, 0, SEEK_END
);
586 FileSize
= ftell (InFptr
);
589 // Get the size of the headers we're going to put in front of the image. The
590 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
592 if (sizeof (RomHdr
) & 0x03) {
593 HeaderPadBytes
= 4 - (sizeof (RomHdr
) & 0x03);
598 HeaderSize
= sizeof (PCI_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
599 if (mOptions
.Verbose
) {
600 fprintf (stdout
, " File size = 0x%X\n", FileSize
);
603 // Allocate memory for the entire file (in case we have to compress), then
604 // seek back to the beginning of the file and read it into our buffer.
606 Buffer
= (INT8
*) malloc (FileSize
);
607 if (Buffer
== NULL
) {
608 fprintf (stdout
, "ERROR: Memory allocation failed\n");
609 Status
= STATUS_ERROR
;
613 fseek (InFptr
, 0, SEEK_SET
);
614 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
615 fprintf (stdout
, "ERROR: Failed to read all bytes from input file\n");
616 Status
= STATUS_ERROR
;
620 // Now determine the size of the final output file. It's either the header size
621 // plus the file's size, or the header size plus the compressed file size.
623 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
625 // Allocate a buffer into which we can compress the image, compress it,
626 // and use that size as the new size.
628 CompressedBuffer
= (INT8
*) malloc (FileSize
);
629 if (CompressedBuffer
== NULL
) {
630 fprintf (stdout
, "ERROR: Memory allocation failed\n");
631 Status
= STATUS_ERROR
;
635 CompressedFileSize
= FileSize
;
636 Status
= Compress (Buffer
, FileSize
, CompressedBuffer
, &CompressedFileSize
);
637 if (Status
!= STATUS_SUCCESS
) {
638 fprintf (stdout
, "ERROR: Compression failed\n");
642 // Now compute the size, then swap buffer pointers.
644 if (mOptions
.Verbose
) {
645 fprintf (stdout
, " Comp size = 0x%X\n", CompressedFileSize
);
648 TotalSize
= CompressedFileSize
+ HeaderSize
;
649 FileSize
= CompressedFileSize
;
650 TempBufferPtr
= Buffer
;
651 Buffer
= CompressedBuffer
;
652 CompressedBuffer
= TempBufferPtr
;
654 TotalSize
= FileSize
+ HeaderSize
;
657 // Total size must be an even multiple of 512 bytes
659 if (TotalSize
& 0x1FF) {
660 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
665 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
668 "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
672 Status
= STATUS_ERROR
;
676 // Return the size to the caller so they can keep track of the running total.
681 // Now fill in the ROM header. These values come from chapter 18 of the
682 // EFI 1.02 specification.
684 memset (&RomHdr
, 0, sizeof (RomHdr
));
685 RomHdr
.Signature
= PCI_EXPANSION_ROM_HEADER_SIGNATURE
;
686 RomHdr
.InitializationSize
= (UINT16
) (TotalSize
/ 512);
687 RomHdr
.EfiSignature
= EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
;
688 RomHdr
.EfiSubsystem
= SubSystem
;
689 RomHdr
.EfiMachineType
= MachineType
;
690 RomHdr
.EfiImageHeaderOffset
= (UINT16
) HeaderSize
;
691 RomHdr
.PcirOffset
= (UINT16
) (sizeof (RomHdr
) + HeaderPadBytes
);
693 // Set image as compressed or not
695 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
696 RomHdr
.CompressionType
= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
;
699 // Fill in the PCI data structure
701 memset (&PciDs
, 0, sizeof (PCI_DATA_STRUCTURE
));
703 PciDs
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
704 PciDs
.VendorId
= VendId
;
705 PciDs
.DeviceId
= DevId
;
706 PciDs
.Length
= (UINT16
) sizeof (PCI_DATA_STRUCTURE
);
709 // Class code and code revision from the command line (optional)
711 PciDs
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
712 PciDs
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
713 PciDs
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
714 PciDs
.ImageLength
= RomHdr
.InitializationSize
;
715 PciDs
.CodeRevision
= InFile
->CodeRevision
;
716 PciDs
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
719 // If this is the last image, then set the LAST bit unless requested not
720 // to via the command-line -l argument.
722 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
723 PciDs
.Indicator
= INDICATOR_LAST
;
726 // Write the ROM header to the output file
728 if (fwrite (&RomHdr
, sizeof (RomHdr
), 1, OutFptr
) != 1) {
729 fprintf (stdout
, "ERROR: Failed to write ROM header to output file\n");
730 Status
= STATUS_ERROR
;
735 // Write pad bytes to align the PciDs
737 while (HeaderPadBytes
> 0) {
738 if (putc (0, OutFptr
) == EOF
) {
739 fprintf (stdout
, "ERROR: Failed to write ROM header pad bytes to output file\n");
740 Status
= STATUS_ERROR
;
747 // Write the PCI data structure header to the output file
749 if (fwrite (&PciDs
, sizeof (PciDs
), 1, OutFptr
) != 1) {
750 fprintf (stdout
, "ERROR: Failed to write PCI ROM header to output file\n");
751 Status
= STATUS_ERROR
;
755 // Keep track of how many bytes left to write
757 TotalSize
-= HeaderSize
;
760 // Now dump the input file's contents to the output file
762 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
763 fprintf (stdout
, "ERROR: Failed to write all file bytes to output file\n");
764 Status
= STATUS_ERROR
;
768 TotalSize
-= FileSize
;
770 // Pad the rest of the image to make it a multiple of 512 bytes
772 while (TotalSize
> 0) {
773 if (putc (~0, OutFptr
) == EOF
) {
774 fprintf (stdout
, "ERROR: Failed to write trailing pad bytes output file\n");
775 Status
= STATUS_ERROR
;
783 if (InFptr
!= NULL
) {
788 // Free up our buffers
790 if (Buffer
!= NULL
) {
794 if (CompressedBuffer
!= NULL
) {
795 free (CompressedBuffer
);
798 // Print the file name if errors occurred
800 if (Status
!= STATUS_SUCCESS
) {
801 fprintf (stdout
, "Error processing EFI file %s\n", InFile
->FileName
);
818 GC_TODO: Add function description
822 Fptr - GC_TODO: add argument description
823 MachineType - GC_TODO: add argument description
824 SubSystem - GC_TODO: add argument description
828 GC_TODO: add return values
836 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
837 PE32 image file, and then return the machine type in the supplied pointer.
841 Fptr File pointer to the already-opened PE32 file
842 MachineType Location to stuff the machine type of the PE32 file. This is needed
843 because the image may be Itanium-based, IA32, or EBC.
851 EFI_IMAGE_DOS_HEADER DosHeader
;
852 EFI_IMAGE_FILE_HEADER FileHdr
;
853 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
857 // Position to the start of the file
859 fseek (Fptr
, 0, SEEK_SET
);
862 // Read the DOS header
864 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
865 fprintf (stdout
, "ERROR: Failed to read the DOS stub from the input file\n");
869 // Check the magic number (0x5A4D)
871 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
872 fprintf (stdout
, "ERROR: Input file does not appear to be a PE32 image (magic number)\n");
876 // Position into the file and check the PE signature
878 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
879 if (fread (&PESig
, sizeof (PESig
), 1, Fptr
) != 1) {
880 fprintf (stdout
, "ERROR: Failed to read PE signature bytes from input file\n");
884 // Check the PE signature in the header "PE\0\0"
886 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
887 fprintf (stdout
, "ERROR: Input file does not appear to be a PE32 image (signature)\n");
891 // Read the file header and stuff their MachineType
893 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
894 fprintf (stdout
, "ERROR: Failed to read PE file header from input file\n");
898 memcpy ((char *) MachineType
, &FileHdr
.Machine
, 2);
901 // Read the optional header so we can get the subsystem
903 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
904 fprintf (stdout
, "ERROR: Failed to read COFF optional header from input file\n");
908 *SubSystem
= OptionalHdr
.Subsystem
;
909 if (mOptions
.Verbose
) {
910 fprintf (stdout
, " Got subsystem = 0x%X from image\n", (int) *SubSystem
);
915 return STATUS_SUCCESS
;
929 Given the Argc/Argv program arguments, and a pointer to an options structure,
930 parse the command-line options and check their validity.
935 Argc - standard C main() argument count
936 Argv[] - standard C main() argument list
937 Options - pointer to a structure to store the options in
941 STATUS_SUCCESS success
949 FILE_LIST
*PrevFileList
;
957 // Clear out the options
959 memset ((char *) Options
, 0, sizeof (OPTIONS
));
962 // To avoid compile warnings
964 FileList
= PrevFileList
= NULL
;
969 // Skip over the program name
975 // If no arguments, assume they want usage info
982 // Process until no more arguments
985 if ((Argv
[0][0] == '-') || (Argv
[0][0] == '/')) {
987 // To simplify string comparisons, replace slashes with dashes
992 // Vendor ID specified with -v
994 if (stricmp (Argv
[0], "-v") == 0) {
996 // Make sure there's another parameter
999 Options
->VendId
= (UINT16
) strtol (Argv
[1], NULL
, 16);
1000 Options
->VendIdValid
= 1;
1004 "ERROR: Missing Vendor ID with %s\n\n",
1008 return STATUS_ERROR
;
1013 } else if (stricmp (Argv
[0], "-d") == 0) {
1015 // Device ID specified with -d
1016 // Make sure there's another parameter
1019 Options
->DevId
= (UINT16
) strtol (Argv
[1], NULL
, 16);
1020 Options
->DevIdValid
= 1;
1024 "ERROR: Missing Device ID with %s\n\n",
1028 return STATUS_ERROR
;
1033 } else if (stricmp (Argv
[0], "-o") == 0) {
1035 // Output filename specified with -o
1036 // Make sure there's another parameter
1039 strcpy (Options
->OutFileName
, Argv
[1]);
1043 "ERROR: Missing output file name with %s\n\n",
1047 return STATUS_ERROR
;
1052 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1057 return STATUS_ERROR
;
1058 } else if (stricmp (Argv
[0], "-b") == 0) {
1060 // Specify binary files with -b
1062 FileFlags
= (FileFlags
&~FILE_FLAG_EFI
) | FILE_FLAG_BINARY
;
1063 } else if ((stricmp (Argv
[0], "-e") == 0) || (stricmp (Argv
[0], "-ec") == 0)) {
1065 // Specify EFI files with -e. Specify EFI-compressed with -ec.
1067 FileFlags
= (FileFlags
&~FILE_FLAG_BINARY
) | FILE_FLAG_EFI
;
1068 if ((Argv
[0][2] == 'c') || (Argv
[0][2] == 'C')) {
1069 FileFlags
|= FILE_FLAG_COMPRESS
;
1072 // Specify not to set the LAST bit in the last file with -l
1074 } else if (stricmp (Argv
[0], "-l") == 0) {
1075 Options
->NoLast
= 1;
1076 } else if (stricmp (Argv
[0], "-p") == 0) {
1078 // -v for verbose would have been nicer, but it's already used. Let's use
1079 // -p for prolix (wordy) output
1081 Options
->Verbose
= 1;
1082 } else if (stricmp (Argv
[0], "-dump") == 0) {
1084 // -dump for dumping a ROM image. In this case, say that the device id
1085 // and vendor id are valid so we don't have to specify bogus ones on the
1088 Options
->DumpOption
= 1;
1090 Options
->VendIdValid
= 1;
1091 Options
->DevIdValid
= 1;
1092 FileFlags
= FILE_FLAG_BINARY
;
1093 } else if (stricmp (Argv
[0], "-cc") == 0) {
1095 // Class code value for the next file in the list.
1096 // Make sure there's another parameter
1100 // No error checking on the return value. Could check for LONG_MAX,
1101 // LONG_MIN, or 0 class code value if desired. Check range (3 bytes)
1104 ClassCode
= (UINT32
) strtol (Argv
[1], NULL
, 16);
1105 if (ClassCode
& 0xFF000000) {
1106 fprintf (stdout
, "ERROR: Class code %s out of range\n", Argv
[1]);
1107 return STATUS_ERROR
;
1112 "ERROR: Missing class code value with %s\n\n",
1116 return STATUS_ERROR
;
1121 } else if (stricmp (Argv
[0], "-rev") == 0) {
1123 // Code revision in the PCI data structure. The value is for the next
1124 // file in the list.
1125 // Make sure there's another parameter
1129 // No error checking on the return value. Could check for LONG_MAX,
1130 // LONG_MIN, or 0 value if desired. Check range (2 bytes)
1133 CodeRevision
= (UINT32
) strtol (Argv
[1], NULL
, 16);
1134 if (CodeRevision
& 0xFFFF0000) {
1135 fprintf (stdout
, "ERROR: Code revision %s out of range\n", Argv
[1]);
1136 return STATUS_ERROR
;
1141 "ERROR: Missing code revision value with %s\n\n",
1145 return STATUS_ERROR
;
1151 fprintf (stdout
, "ERROR: Invalid option specified: %s\n\n", Argv
[0]);
1153 return STATUS_ERROR
;
1157 // Not a slash-option argument. Must be a file name. Make sure they've specified
1158 // -e or -b already.
1160 if ((FileFlags
& (FILE_FLAG_BINARY
| FILE_FLAG_EFI
)) == 0) {
1161 fprintf (stdout
, "ERROR: Missing -e or -b with input file %s\n", Argv
[0]);
1162 return STATUS_ERROR
;
1165 // Create a new file structure
1167 FileList
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
1168 if (FileList
== NULL
) {
1169 fprintf (stdout
, "ERROR: Memory allocation failure\n");
1170 return STATUS_ERROR
;
1173 memset ((char *) FileList
, 0, sizeof (FILE_LIST
));
1174 FileList
->FileName
= Argv
[0];
1175 FileList
->FileFlags
= FileFlags
;
1176 if (Options
->FileList
== NULL
) {
1177 Options
->FileList
= FileList
;
1179 if (PrevFileList
== NULL
) {
1180 PrevFileList
= FileList
;
1182 PrevFileList
->Next
= FileList
;
1186 PrevFileList
= FileList
;
1188 // Set the class code and code revision for this file, then reset the values.
1190 FileList
->ClassCode
= ClassCode
;
1191 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1202 // Make sure they specified a device ID and vendor ID
1204 if (!Options
->VendIdValid
) {
1205 fprintf (stdout
, "ERROR: Missing Vendor ID on command line\n\n");
1207 return STATUS_ERROR
;
1210 if (!Options
->DevIdValid
) {
1211 fprintf (stdout
, "ERROR: Missing Device ID on command line\n\n");
1213 return STATUS_ERROR
;
1216 // Must have specified some files
1218 if (Options
->FileList
== NULL
) {
1219 fprintf (stdout
, "ERROR: Missing input file name\n");
1221 return STATUS_ERROR
;
1234 Routine Description:
1236 Print usage information for this utility.
1249 static const char *Msg
[] = {
1250 "EfiRom "UTILITY_VERSION
" - Intel EFI Make Option ROM utility",
1251 " Copyright (C), 1999-2002 Intel Coproration\n",
1252 " Create an option ROM image from a list of input files",
1253 " Usage: efirom {-p} [-v VendorId] [-d DeviceId] {-o OutFileName} ",
1254 " [-e|-b] [FileName(s)]",
1256 " VendorId - required hex PCI Vendor ID for the device",
1257 " DeviceId - required hex PCI Device ID for the device",
1258 " OutFileName - optional output file name. Default is the first input",
1259 " file name with a "DEFAULT_OUTPUT_EXTENSION
" file extension",
1260 " FileNames - input PE32 or binary file name(s)",
1261 " BinFileName - input binary file name(s)",
1262 " -p - for verbose output",
1263 " -l - to not automatically set the LAST bit on the last file",
1264 " -b - following FileNames are binary files",
1265 " -e - following FileNames are EFI PE32 image files",
1266 " -ec - following FileNames are EFI PE32 image files, and should",
1267 " be compressed by this utility",
1268 " -cc ClassCode - to use hex ClassCode in the PCI data structure header for",
1269 " the following FileName",
1270 " -rev Revision - to use hex Revision in the PCI data structure header for",
1271 " the following FileName",
1272 " -dump - to dump the headers of an existing option ROM image",
1274 "Example usage: EfiRom -v 0xABCD -d 0x1234 -b File1.bin File2.bin -e File1.efi File2.efi ",
1279 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
1280 fprintf (stdout
, "%s\n", Msg
[Index
]);
1291 Routine Description:
1293 GC_TODO: Add function description
1297 InFile - GC_TODO: add argument description
1301 GC_TODO: add return values
1305 PCI_EXPANSION_ROM_HEADER PciRomHdr
;
1309 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr
;
1310 PCI_DATA_STRUCTURE PciDs
;
1313 // Open the input file
1315 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
1318 "ERROR: Could not open input file %s\n",
1324 // Go through the image and dump the header stuff for each
1329 // Save our postition in the file, since offsets in the headers
1330 // are relative to the particular image.
1332 ImageStart
= ftell (InFptr
);
1336 // Read the option ROM header. Have to assume a raw binary image for now.
1338 if (fread (&PciRomHdr
, sizeof (PciRomHdr
), 1, InFptr
) != 1) {
1339 fprintf (stdout
, "ERROR: Failed to read PCI ROM header from file\n");
1344 // Dump the contents of the header
1346 fprintf (stdout
, "Image %d -- Offset 0x%X\n", ImageCount
, ImageStart
);
1347 fprintf (stdout
, " ROM header contents\n");
1348 fprintf (stdout
, " Signature 0x%04X\n", (UINT32
) PciRomHdr
.Signature
);
1349 fprintf (stdout
, " PCIR offset 0x%04X\n", (UINT32
) PciRomHdr
.PcirOffset
);
1351 // Find PCI data structure
1353 if (fseek (InFptr
, ImageStart
+ PciRomHdr
.PcirOffset
, SEEK_SET
)) {
1354 fprintf (stdout
, "ERROR: Failed to seek to PCI data structure\n");
1358 // Read and dump the PCI data structure
1360 if (fread (&PciDs
, sizeof (PciDs
), 1, InFptr
) != 1) {
1361 fprintf (stdout
, "ERROR: Failed to read PCI data structure from file\n");
1365 fprintf (stdout
, " PCI Data Structure\n");
1368 " Signature %c%c%c%c\n",
1369 (char) PciDs
.Signature
,
1370 (char) (PciDs
.Signature
>> 8),
1371 (char) (PciDs
.Signature
>> 16),
1372 (char) (PciDs
.Signature
>> 24)
1374 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs
.VendorId
);
1375 fprintf (stdout
, " Device ID 0x%04X\n", PciDs
.DeviceId
);
1378 " Class Code 0x%06X\n",
1379 (UINT32
) (PciDs
.ClassCode
[0] | (PciDs
.ClassCode
[1] << 8) | (PciDs
.ClassCode
[2] << 16))
1381 fprintf (stdout
, " Image size 0x%X\n", PciDs
.ImageLength
* 512);
1382 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs
.CodeRevision
);
1383 fprintf (stdout
, " Indicator 0x%02X", (UINT32
) PciDs
.Indicator
);
1385 // Print the indicator, used to flag the last image
1387 if (PciDs
.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 fprintf (stdout
, " Code type 0x%02X", (UINT32
) PciDs
.CodeType
);
1396 if (PciDs
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
1397 fprintf (stdout
, " (EFI image)\n");
1399 // Re-read the header as an EFI ROM header, then dump more info
1401 fprintf (stdout
, " EFI ROM header contents\n");
1402 if (fseek (InFptr
, ImageStart
, SEEK_SET
)) {
1403 fprintf (stdout
, "ERROR: Failed to re-seek to ROM header structure\n");
1407 if (fread (&EfiRomHdr
, sizeof (EfiRomHdr
), 1, InFptr
) != 1) {
1408 fprintf (stdout
, "ERROR: Failed to read EFI PCI ROM header from file\n");
1412 // Now dump more info
1414 fprintf (stdout
, " EFI Signature 0x%04X\n", EfiRomHdr
.EfiSignature
);
1417 " Compression Type 0x%04X ",
1418 (UINT32
) EfiRomHdr
.CompressionType
1420 if (EfiRomHdr
.CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
1421 fprintf (stdout
, "(compressed)\n");
1423 fprintf (stdout
, "(not compressed)\n");
1428 " Machine type 0x%04X (%s)\n",
1429 EfiRomHdr
.EfiMachineType
,
1430 GetMachineTypeStr (EfiRomHdr
.EfiMachineType
)
1434 " Subsystem 0x%04X (%s)\n",
1435 EfiRomHdr
.EfiSubsystem
,
1436 GetSubsystemTypeStr (EfiRomHdr
.EfiSubsystem
)
1440 " EFI image offset 0x%04X (@0x%X)\n",
1441 (UINT32
) EfiRomHdr
.EfiImageHeaderOffset
,
1442 (UINT32
) (EfiRomHdr
.EfiImageHeaderOffset
+ ImageStart
)
1449 fprintf (stdout
, "\n");
1452 // If code type is EFI image, then dump it as well?
1454 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
1457 // If last image, then we're done
1459 if (PciDs
.Indicator
== INDICATOR_LAST
) {
1463 // Seek to the start of the next image
1465 if (fseek (InFptr
, ImageStart
+ (PciDs
.ImageLength
* 512), SEEK_SET
)) {
1466 fprintf (stdout
, "ERROR: Failed to seek to next image\n");
1481 Routine Description:
1483 GC_TODO: Add function description
1487 MachineType - GC_TODO: add argument description
1491 GC_TODO: add return values
1497 for (Index
= 0; mMachineTypes
[Index
].Name
!= NULL
; Index
++) {
1498 if (mMachineTypes
[Index
].Value
== MachineType
) {
1499 return mMachineTypes
[Index
].Name
;
1508 GetSubsystemTypeStr (
1509 UINT16 SubsystemType
1513 Routine Description:
1515 GC_TODO: Add function description
1519 SubsystemType - GC_TODO: add argument description
1523 GC_TODO: add return values
1529 for (Index
= 0; mSubsystemTypes
[Index
].Name
!= NULL
; Index
++) {
1530 if (mSubsystemTypes
[Index
].Value
== SubsystemType
) {
1531 return mSubsystemTypes
[Index
].Name
;