3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this 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.
19 Utility program to create an EFI option ROM image from binary and
30 // Includes for EFI 1.1 build
32 // #include "Tiano.h" // required defines for Compress.h
33 // #include "EfiImage.h" // for PE32 structure definitions
34 // #include "Compress.h" // for compression function
35 // Includes for Tiano build
37 #include "TianoCommon.h"
38 #include "EfiImage.h" // for PE32 structure definitions
42 // END include differences
44 #include "Pci22.h" // for option ROM header structures
46 // Version of this utility
48 #define UTILITY_VERSION "v2.5"
51 // Define some status return values
53 #define STATUS_SUCCESS 0
54 #define STATUS_WARNING 1
55 #define STATUS_ERROR 2
58 // Define the max length of a filename
62 #define DEFAULT_OUTPUT_EXTENSION ".rom"
65 // Max size for an option ROM image
67 #define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB
69 // Values for the indicator field in the PCI data structure
71 #define INDICATOR_LAST 0x80 // last file in series of files
73 // Masks for the FILE_LIST.FileFlags field
75 #define FILE_FLAG_BINARY 0x01
76 #define FILE_FLAG_EFI 0x02
77 #define FILE_FLAG_COMPRESS 0x04
80 // Use this linked list structure to keep track of all the filenames
81 // specified on the command line.
83 typedef struct _FILE_LIST
{
84 struct _FILE_LIST
*Next
;
92 // Use this to track our command-line options
95 INT8 OutFileName
[MAX_PATH
];
107 // Make a global structure to keep track of command-line options
109 static OPTIONS mOptions
;
112 // Use these to convert from machine type value to a named type
119 static STRING_LOOKUP mMachineTypes
[] = {
120 EFI_IMAGE_MACHINE_IA32
,
122 EFI_IMAGE_MACHINE_IA64
,
124 EFI_IMAGE_MACHINE_EBC
,
130 static STRING_LOOKUP mSubsystemTypes
[] = {
131 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
133 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
134 "EFI boot service driver",
135 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
136 "EFI runtime driver",
141 // Function prototypes
196 GetSubsystemTypeStr (
209 Given an EFI image filename, create a ROM-able image by creating an option
210 ROM header and PCI data structure, filling them in, and then writing the
211 option ROM header + PCI data structure + EFI image out to the output file.
215 Argc - standard C main() argument count
217 Argv - standard C main() argument list
225 // GC_TODO: ] - add argument and description to function comment
234 Status
= STATUS_SUCCESS
;
238 // Parse the command line arguments
240 if (ParseCommandLine (Argc
, Argv
, &mOptions
)) {
244 // If dumping an image, then do that and quit
246 if (mOptions
.DumpOption
) {
247 DumpImage (mOptions
.FileList
);
251 // Determine the output filename. Either what they specified on
252 // the command line, or the first input filename with a different extension.
254 if (!mOptions
.OutFileName
[0]) {
255 strcpy (mOptions
.OutFileName
, mOptions
.FileList
->FileName
);
257 // Find the last . on the line and replace the filename extension with
260 for (Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
) - 1;
261 (Ext
>= mOptions
.OutFileName
) && (*Ext
!= '.') && (*Ext
!= '\\');
266 // If dot here, then insert extension here, otherwise append
269 Ext
= mOptions
.OutFileName
+ strlen (mOptions
.OutFileName
);
272 strcpy (Ext
, DEFAULT_OUTPUT_EXTENSION
);
275 // Make sure we don't have the same filename for input and output files
277 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
278 if (_stricmp (mOptions
.OutFileName
, FList
->FileName
) == 0) {
279 Status
= STATUS_ERROR
;
282 "ERROR: Input and output file names must be different - %s = %s\n",
290 // Now open our output file
292 if ((FptrOut
= fopen (mOptions
.OutFileName
, "w+b")) == NULL
) {
293 fprintf (stdout
, "ERROR: Failed to open output file %s\n", mOptions
.OutFileName
);
297 // Process all our files
300 for (FList
= mOptions
.FileList
; FList
!= NULL
; FList
= FList
->Next
) {
302 if (FList
->FileFlags
& FILE_FLAG_EFI
) {
303 if (mOptions
.Verbose
) {
304 fprintf (stdout
, "Processing EFI file %s\n", FList
->FileName
);
307 Status
= ProcessEfiFile (FptrOut
, FList
, mOptions
.VendId
, mOptions
.DevId
, &Size
);
308 } else if (FList
->FileFlags
& FILE_FLAG_BINARY
) {
309 if (mOptions
.Verbose
) {
310 fprintf (stdout
, "Processing binary file %s\n", FList
->FileName
);
313 Status
= ProcessBinFile (FptrOut
, FList
, &Size
);
315 fprintf (stdout
, "ERROR: File not specified as EFI or binary: %s\n", FList
->FileName
);
316 Status
= STATUS_ERROR
;
319 if (mOptions
.Verbose
) {
320 fprintf (stdout
, " Output size = 0x%X\n", Size
);
323 if (Status
!= STATUS_SUCCESS
) {
332 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
335 "ERROR: Option ROM image size exceeds limit 0x%X bytes\n",
338 Status
= STATUS_ERROR
;
342 if (FptrOut
!= NULL
) {
346 // Clean up our file list
348 while (mOptions
.FileList
!= NULL
) {
349 FList
= mOptions
.FileList
->Next
;
350 free (mOptions
.FileList
);
351 mOptions
.FileList
= FList
;
368 Process a binary input file.
372 OutFptr - file pointer to output binary ROM image file we're creating
373 InFile - structure contains information on the binary file to process
374 Size - pointer to where to return the size added to the output file
387 PCI_EXPANSION_ROM_HEADER
*RomHdr
;
388 PCI_DATA_STRUCTURE
*PciDs
;
392 Status
= STATUS_SUCCESS
;
395 // Try to open the input file
397 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
398 fprintf (stdout
, "ERROR: Failed to open input file %s\n", InFile
->FileName
);
402 // Seek to the end of the input file and get the file size. Then allocate
403 // a buffer to read it in to.
405 fseek (InFptr
, 0, SEEK_END
);
406 FileSize
= ftell (InFptr
);
407 if (mOptions
.Verbose
) {
408 fprintf (stdout
, " File size = 0x%X\n", FileSize
);
411 fseek (InFptr
, 0, SEEK_SET
);
412 Buffer
= (INT8
*) malloc (FileSize
);
413 if (Buffer
== NULL
) {
414 fprintf (stdout
, "ERROR: Memory allocation failed\n");
415 Status
= STATUS_ERROR
;
419 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
420 fprintf (stdout
, "ERROR: Failed to read all bytes from input file\n");
421 Status
= STATUS_ERROR
;
425 // Total size must be an even multiple of 512 bytes, and can't exceed
426 // the option ROM image size.
428 TotalSize
= FileSize
;
429 if (TotalSize
& 0x1FF) {
430 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
433 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
436 "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
440 Status
= STATUS_ERROR
;
444 // Return the size to the caller so they can keep track of the running total.
449 // Crude check to make sure it's a legitimate ROM image
451 RomHdr
= (PCI_EXPANSION_ROM_HEADER
*) Buffer
;
452 if (RomHdr
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
453 fprintf (stdout
, "ERROR: ROM image file has invalid ROM signature\n");
454 Status
= STATUS_ERROR
;
458 // Make sure the pointer to the PCI data structure is within the size of the image.
459 // Then check it for valid signature.
461 if ((RomHdr
->PcirOffset
> FileSize
) || (RomHdr
->PcirOffset
== 0)) {
462 fprintf (stdout
, "ERROR: Invalid PCI data structure offset\n");
463 Status
= STATUS_ERROR
;
467 PciDs
= (PCI_DATA_STRUCTURE
*) (Buffer
+ RomHdr
->PcirOffset
);
468 if (PciDs
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
469 fprintf (stdout
, "ERROR: PCI data structure has invalid signature\n");
470 Status
= STATUS_ERROR
;
474 // If this is the last image, then set the LAST bit unless requested not
475 // to via the command-line -l argument. Otherwise, make sure you clear it.
477 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
478 PciDs
->Indicator
= INDICATOR_LAST
;
480 PciDs
->Indicator
= 0;
484 for (Index
= 0; Index
< FileSize
- 1; Index
++) {
485 ByteCheckSum
= (UINT8
) (ByteCheckSum
+ Buffer
[Index
]);
488 Buffer
[FileSize
- 1] = (UINT8
) ((~ByteCheckSum
) + 1);
489 fprintf (stdout
, "CheckSUm = %02x\n", (UINT32
) Buffer
[FileSize
- 1]);
492 // Now copy the input file contents out to the output file
494 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
495 fprintf (stdout
, "ERROR: Failed to write all file bytes to output file\n");
496 Status
= STATUS_ERROR
;
500 TotalSize
-= FileSize
;
502 // Pad the rest of the image to make it a multiple of 512 bytes
504 while (TotalSize
> 0) {
510 if (InFptr
!= NULL
) {
514 if (Buffer
!= NULL
) {
518 // Print the file name if errors occurred
520 if (Status
!= STATUS_SUCCESS
) {
521 fprintf (stdout
, "Error processing binary file %s\n", InFile
->FileName
);
540 Process a PE32 EFI file.
544 OutFptr - file pointer to output binary ROM image file we're creating
545 InFile - structure contains information on the PE32 file to process
546 VendId - vendor ID as required in the option ROM header
547 DevId - device ID as required in the option ROM header
548 Size - pointer to where to return the size added to the output file
558 EFI_PCI_EXPANSION_ROM_HEADER RomHdr
;
559 PCI_DATA_STRUCTURE PciDs
;
561 UINT32 CompressedFileSize
;
563 UINT8
*CompressedBuffer
;
564 UINT8
*TempBufferPtr
;
569 UINT32 HeaderPadBytes
;
572 // Try to open the input file
574 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
575 fprintf (stdout
, "ERROR: Failed to open input file %s\n", InFile
->FileName
);
579 // Initialize our buffer pointers to null.
582 CompressedBuffer
= NULL
;
585 // Double-check the file to make sure it's what we expect it to be
587 Status
= CheckPE32File (InFptr
, &MachineType
, &SubSystem
);
588 if (Status
!= STATUS_SUCCESS
) {
592 // Seek to the end of the input file and get the file size
594 fseek (InFptr
, 0, SEEK_END
);
595 FileSize
= ftell (InFptr
);
598 // Get the size of the headers we're going to put in front of the image. The
599 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
601 if (sizeof (RomHdr
) & 0x03) {
602 HeaderPadBytes
= 4 - (sizeof (RomHdr
) & 0x03);
607 HeaderSize
= sizeof (PCI_DATA_STRUCTURE
) + HeaderPadBytes
+ sizeof (EFI_PCI_EXPANSION_ROM_HEADER
);
608 if (mOptions
.Verbose
) {
609 fprintf (stdout
, " File size = 0x%X\n", FileSize
);
612 // Allocate memory for the entire file (in case we have to compress), then
613 // seek back to the beginning of the file and read it into our buffer.
615 Buffer
= (INT8
*) malloc (FileSize
);
616 if (Buffer
== NULL
) {
617 fprintf (stdout
, "ERROR: Memory allocation failed\n");
618 Status
= STATUS_ERROR
;
622 fseek (InFptr
, 0, SEEK_SET
);
623 if (fread (Buffer
, FileSize
, 1, InFptr
) != 1) {
624 fprintf (stdout
, "ERROR: Failed to read all bytes from input file\n");
625 Status
= STATUS_ERROR
;
629 // Now determine the size of the final output file. It's either the header size
630 // plus the file's size, or the header size plus the compressed file size.
632 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
634 // Allocate a buffer into which we can compress the image, compress it,
635 // and use that size as the new size.
637 CompressedBuffer
= (INT8
*) malloc (FileSize
);
638 if (CompressedBuffer
== NULL
) {
639 fprintf (stdout
, "ERROR: Memory allocation failed\n");
640 Status
= STATUS_ERROR
;
644 CompressedFileSize
= FileSize
;
645 Status
= EfiCompress (Buffer
, FileSize
, CompressedBuffer
, &CompressedFileSize
);
646 if (Status
!= STATUS_SUCCESS
) {
647 fprintf (stdout
, "ERROR: Compression failed\n");
651 // Now compute the size, then swap buffer pointers.
653 if (mOptions
.Verbose
) {
654 fprintf (stdout
, " Comp size = 0x%X\n", CompressedFileSize
);
657 TotalSize
= CompressedFileSize
+ HeaderSize
;
658 FileSize
= CompressedFileSize
;
659 TempBufferPtr
= Buffer
;
660 Buffer
= CompressedBuffer
;
661 CompressedBuffer
= TempBufferPtr
;
663 TotalSize
= FileSize
+ HeaderSize
;
666 // Total size must be an even multiple of 512 bytes
668 if (TotalSize
& 0x1FF) {
669 TotalSize
= (TotalSize
+ 0x200) &~0x1ff;
674 if (TotalSize
> MAX_OPTION_ROM_SIZE
) {
677 "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
681 Status
= STATUS_ERROR
;
685 // Return the size to the caller so they can keep track of the running total.
690 // Now fill in the ROM header. These values come from chapter 18 of the
691 // EFI 1.02 specification.
693 memset (&RomHdr
, 0, sizeof (RomHdr
));
694 RomHdr
.Signature
= PCI_EXPANSION_ROM_HEADER_SIGNATURE
;
695 RomHdr
.InitializationSize
= (UINT16
) (TotalSize
/ 512);
696 RomHdr
.EfiSignature
= EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
;
697 RomHdr
.EfiSubsystem
= SubSystem
;
698 RomHdr
.EfiMachineType
= MachineType
;
699 RomHdr
.EfiImageHeaderOffset
= (UINT16
) HeaderSize
;
700 RomHdr
.PcirOffset
= (UINT16
) (sizeof (RomHdr
) + HeaderPadBytes
);
702 // Set image as compressed or not
704 if (InFile
->FileFlags
& FILE_FLAG_COMPRESS
) {
705 RomHdr
.CompressionType
= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
;
708 // Fill in the PCI data structure
710 memset (&PciDs
, 0, sizeof (PCI_DATA_STRUCTURE
));
712 PciDs
.Signature
= PCI_DATA_STRUCTURE_SIGNATURE
;
713 PciDs
.VendorId
= VendId
;
714 PciDs
.DeviceId
= DevId
;
715 PciDs
.Length
= (UINT16
) sizeof (PCI_DATA_STRUCTURE
);
718 // Class code and code revision from the command line (optional)
720 PciDs
.ClassCode
[0] = (UINT8
) InFile
->ClassCode
;
721 PciDs
.ClassCode
[1] = (UINT8
) (InFile
->ClassCode
>> 8);
722 PciDs
.ClassCode
[2] = (UINT8
) (InFile
->ClassCode
>> 16);
723 PciDs
.ImageLength
= RomHdr
.InitializationSize
;
724 PciDs
.CodeRevision
= InFile
->CodeRevision
;
725 PciDs
.CodeType
= PCI_CODE_TYPE_EFI_IMAGE
;
728 // If this is the last image, then set the LAST bit unless requested not
729 // to via the command-line -l argument.
731 if ((InFile
->Next
== NULL
) && (mOptions
.NoLast
== 0)) {
732 PciDs
.Indicator
= INDICATOR_LAST
;
735 // Write the ROM header to the output file
737 if (fwrite (&RomHdr
, sizeof (RomHdr
), 1, OutFptr
) != 1) {
738 fprintf (stdout
, "ERROR: Failed to write ROM header to output file\n");
739 Status
= STATUS_ERROR
;
744 // Write pad bytes to align the PciDs
746 while (HeaderPadBytes
> 0) {
747 if (putc (0, OutFptr
) == EOF
) {
748 fprintf (stdout
, "ERROR: Failed to write ROM header pad bytes to output file\n");
749 Status
= STATUS_ERROR
;
756 // Write the PCI data structure header to the output file
758 if (fwrite (&PciDs
, sizeof (PciDs
), 1, OutFptr
) != 1) {
759 fprintf (stdout
, "ERROR: Failed to write PCI ROM header to output file\n");
760 Status
= STATUS_ERROR
;
764 // Keep track of how many bytes left to write
766 TotalSize
-= HeaderSize
;
769 // Now dump the input file's contents to the output file
771 if (fwrite (Buffer
, FileSize
, 1, OutFptr
) != 1) {
772 fprintf (stdout
, "ERROR: Failed to write all file bytes to output file\n");
773 Status
= STATUS_ERROR
;
777 TotalSize
-= FileSize
;
779 // Pad the rest of the image to make it a multiple of 512 bytes
781 while (TotalSize
> 0) {
782 if (putc (~0, OutFptr
) == EOF
) {
783 fprintf (stdout
, "ERROR: Failed to write trailing pad bytes output file\n");
784 Status
= STATUS_ERROR
;
792 if (InFptr
!= NULL
) {
797 // Free up our buffers
799 if (Buffer
!= NULL
) {
803 if (CompressedBuffer
!= NULL
) {
804 free (CompressedBuffer
);
807 // Print the file name if errors occurred
809 if (Status
!= STATUS_SUCCESS
) {
810 fprintf (stdout
, "Error processing EFI file %s\n", InFile
->FileName
);
827 GC_TODO: Add function description
831 Fptr - GC_TODO: add argument description
832 MachineType - GC_TODO: add argument description
833 SubSystem - GC_TODO: add argument description
837 GC_TODO: add return values
845 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
846 PE32 image file, and then return the machine type in the supplied pointer.
850 Fptr File pointer to the already-opened PE32 file
851 MachineType Location to stuff the machine type of the PE32 file. This is needed
852 because the image may be Itanium-based, IA32, or EBC.
860 EFI_IMAGE_DOS_HEADER DosHeader
;
861 EFI_IMAGE_FILE_HEADER FileHdr
;
862 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr
;
866 // Position to the start of the file
868 fseek (Fptr
, 0, SEEK_SET
);
871 // Read the DOS header
873 if (fread (&DosHeader
, sizeof (DosHeader
), 1, Fptr
) != 1) {
874 fprintf (stdout
, "ERROR: Failed to read the DOS stub from the input file\n");
878 // Check the magic number (0x5A4D)
880 if (DosHeader
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
881 fprintf (stdout
, "ERROR: Input file does not appear to be a PE32 image (magic number)\n");
885 // Position into the file and check the PE signature
887 fseek (Fptr
, (long) DosHeader
.e_lfanew
, SEEK_SET
);
888 if (fread (&PESig
, sizeof (PESig
), 1, Fptr
) != 1) {
889 fprintf (stdout
, "ERROR: Failed to read PE signature bytes from input file\n");
893 // Check the PE signature in the header "PE\0\0"
895 if (PESig
!= EFI_IMAGE_NT_SIGNATURE
) {
896 fprintf (stdout
, "ERROR: Input file does not appear to be a PE32 image (signature)\n");
900 // Read the file header and stuff their MachineType
902 if (fread (&FileHdr
, sizeof (FileHdr
), 1, Fptr
) != 1) {
903 fprintf (stdout
, "ERROR: Failed to read PE file header from input file\n");
907 memcpy ((char *) MachineType
, &FileHdr
.Machine
, 2);
910 // Read the optional header so we can get the subsystem
912 if (fread (&OptionalHdr
, sizeof (OptionalHdr
), 1, Fptr
) != 1) {
913 fprintf (stdout
, "ERROR: Failed to read COFF optional header from input file\n");
917 *SubSystem
= OptionalHdr
.Subsystem
;
918 if (mOptions
.Verbose
) {
919 fprintf (stdout
, " Got subsystem = 0x%X from image\n", (int) *SubSystem
);
924 return STATUS_SUCCESS
;
938 Given the Argc/Argv program arguments, and a pointer to an options structure,
939 parse the command-line options and check their validity.
944 Argc - standard C main() argument count
945 Argv[] - standard C main() argument list
946 Options - pointer to a structure to store the options in
950 STATUS_SUCCESS success
958 FILE_LIST
*PrevFileList
;
966 // Clear out the options
968 memset ((char *) Options
, 0, sizeof (OPTIONS
));
971 // To avoid compile warnings
973 FileList
= PrevFileList
= NULL
;
978 // Skip over the program name
984 // If no arguments, assume they want usage info
991 // Process until no more arguments
994 if ((Argv
[0][0] == '-') || (Argv
[0][0] == '/')) {
996 // To simplify string comparisons, replace slashes with dashes
1001 // Vendor ID specified with -v
1003 if (_stricmp (Argv
[0], "-v") == 0) {
1005 // Make sure there's another parameter
1008 Options
->VendId
= (UINT16
) strtol (Argv
[1], NULL
, 16);
1009 Options
->VendIdValid
= 1;
1013 "ERROR: Missing Vendor ID with %s\n\n",
1017 return STATUS_ERROR
;
1022 } else if (_stricmp (Argv
[0], "-d") == 0) {
1024 // Device ID specified with -d
1025 // Make sure there's another parameter
1028 Options
->DevId
= (UINT16
) strtol (Argv
[1], NULL
, 16);
1029 Options
->DevIdValid
= 1;
1033 "ERROR: Missing Device ID with %s\n\n",
1037 return STATUS_ERROR
;
1042 } else if (_stricmp (Argv
[0], "-o") == 0) {
1044 // Output filename specified with -o
1045 // Make sure there's another parameter
1048 strcpy (Options
->OutFileName
, Argv
[1]);
1052 "ERROR: Missing output file name with %s\n\n",
1056 return STATUS_ERROR
;
1061 } else if ((_stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1066 return STATUS_ERROR
;
1067 } else if (_stricmp (Argv
[0], "-b") == 0) {
1069 // Specify binary files with -b
1071 FileFlags
= (FileFlags
&~FILE_FLAG_EFI
) | FILE_FLAG_BINARY
;
1072 } else if ((_stricmp (Argv
[0], "-e") == 0) || (_stricmp (Argv
[0], "-ec") == 0)) {
1074 // Specify EFI files with -e. Specify EFI-compressed with -ec.
1076 FileFlags
= (FileFlags
&~FILE_FLAG_BINARY
) | FILE_FLAG_EFI
;
1077 if ((Argv
[0][2] == 'c') || (Argv
[0][2] == 'C')) {
1078 FileFlags
|= FILE_FLAG_COMPRESS
;
1081 // Specify not to set the LAST bit in the last file with -l
1083 } else if (_stricmp (Argv
[0], "-l") == 0) {
1084 Options
->NoLast
= 1;
1085 } else if (_stricmp (Argv
[0], "-p") == 0) {
1087 // -v for verbose would have been nicer, but it's already used. Let's use
1088 // -p for prolix (wordy) output
1090 Options
->Verbose
= 1;
1091 } else if (_stricmp (Argv
[0], "-dump") == 0) {
1093 // -dump for dumping a ROM image. In this case, say that the device id
1094 // and vendor id are valid so we don't have to specify bogus ones on the
1097 Options
->DumpOption
= 1;
1099 Options
->VendIdValid
= 1;
1100 Options
->DevIdValid
= 1;
1101 FileFlags
= FILE_FLAG_BINARY
;
1102 } else if (_stricmp (Argv
[0], "-cc") == 0) {
1104 // Class code value for the next file in the list.
1105 // Make sure there's another parameter
1109 // No error checking on the return value. Could check for LONG_MAX,
1110 // LONG_MIN, or 0 class code value if desired. Check range (3 bytes)
1113 ClassCode
= (UINT32
) strtol (Argv
[1], NULL
, 16);
1114 if (ClassCode
& 0xFF000000) {
1115 fprintf (stdout
, "ERROR: Class code %s out of range\n", Argv
[1]);
1116 return STATUS_ERROR
;
1121 "ERROR: Missing class code value with %s\n\n",
1125 return STATUS_ERROR
;
1130 } else if (_stricmp (Argv
[0], "-rev") == 0) {
1132 // Code revision in the PCI data structure. The value is for the next
1133 // file in the list.
1134 // Make sure there's another parameter
1138 // No error checking on the return value. Could check for LONG_MAX,
1139 // LONG_MIN, or 0 value if desired. Check range (2 bytes)
1142 CodeRevision
= (UINT32
) strtol (Argv
[1], NULL
, 16);
1143 if (CodeRevision
& 0xFFFF0000) {
1144 fprintf (stdout
, "ERROR: Code revision %s out of range\n", Argv
[1]);
1145 return STATUS_ERROR
;
1150 "ERROR: Missing code revision value with %s\n\n",
1154 return STATUS_ERROR
;
1160 fprintf (stdout
, "ERROR: Invalid option specified: %s\n\n", Argv
[0]);
1162 return STATUS_ERROR
;
1166 // Not a slash-option argument. Must be a file name. Make sure they've specified
1167 // -e or -b already.
1169 if ((FileFlags
& (FILE_FLAG_BINARY
| FILE_FLAG_EFI
)) == 0) {
1170 fprintf (stdout
, "ERROR: Missing -e or -b with input file %s\n", Argv
[0]);
1171 return STATUS_ERROR
;
1174 // Create a new file structure
1176 FileList
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
1177 if (FileList
== NULL
) {
1178 fprintf (stdout
, "ERROR: Memory allocation failure\n");
1179 return STATUS_ERROR
;
1182 memset ((char *) FileList
, 0, sizeof (FILE_LIST
));
1183 FileList
->FileName
= Argv
[0];
1184 FileList
->FileFlags
= FileFlags
;
1185 if (Options
->FileList
== NULL
) {
1186 Options
->FileList
= FileList
;
1188 if (PrevFileList
== NULL
) {
1189 PrevFileList
= FileList
;
1191 PrevFileList
->Next
= FileList
;
1195 PrevFileList
= FileList
;
1197 // Set the class code and code revision for this file, then reset the values.
1199 FileList
->ClassCode
= ClassCode
;
1200 FileList
->CodeRevision
= (UINT16
) CodeRevision
;
1211 // Make sure they specified a device ID and vendor ID
1213 if (!Options
->VendIdValid
) {
1214 fprintf (stdout
, "ERROR: Missing Vendor ID on command line\n\n");
1216 return STATUS_ERROR
;
1219 if (!Options
->DevIdValid
) {
1220 fprintf (stdout
, "ERROR: Missing Device ID on command line\n\n");
1222 return STATUS_ERROR
;
1225 // Must have specified some files
1227 if (Options
->FileList
== NULL
) {
1228 fprintf (stdout
, "ERROR: Missing input file name\n");
1230 return STATUS_ERROR
;
1243 Routine Description:
1245 Print usage information for this utility.
1258 static const char *Msg
[] = {
1259 "EfiRom "UTILITY_VERSION
" - Intel EFI Make Option ROM utility",
1260 " Copyright (C), 1999 - 2002 Intel Coproration\n",
1261 " Create an option ROM image from a list of input files",
1262 " Usage: efirom {-p} [-v VendorId] [-d DeviceId] {-o OutFileName} ",
1263 " [-e|-b] [FileName(s)]",
1265 " VendorId - required hex PCI Vendor ID for the device",
1266 " DeviceId - required hex PCI Device ID for the device",
1267 " OutFileName - optional output file name. Default is the first input",
1268 " file name with a "DEFAULT_OUTPUT_EXTENSION
" file extension",
1269 " FileNames - input PE32 or binary file name(s)",
1270 " BinFileName - input binary file name(s)",
1271 " -p - for verbose output",
1272 " -l - to not automatically set the LAST bit on the last file",
1273 " -b - following FileNames are binary files",
1274 " -e - following FileNames are EFI PE32 image files",
1275 " -ec - following FileNames are EFI PE32 image files, and should",
1276 " be compressed by this utility",
1277 " -cc ClassCode - to use hex ClassCode in the PCI data structure header for",
1278 " the following FileName",
1279 " -rev Revision - to use hex Revision in the PCI data structure header for",
1280 " the following FileName",
1281 " -dump - to dump the headers of an existing option ROM image",
1283 "Example usage: EfiRom -v 0xABCD -d 0x1234 -b File1.bin File2.bin -e File1.efi File2.efi ",
1288 for (Index
= 0; Msg
[Index
] != NULL
; Index
++) {
1289 fprintf (stdout
, "%s\n", Msg
[Index
]);
1300 Routine Description:
1302 GC_TODO: Add function description
1306 InFile - GC_TODO: add argument description
1310 GC_TODO: add return values
1314 PCI_EXPANSION_ROM_HEADER PciRomHdr
;
1318 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr
;
1319 PCI_DATA_STRUCTURE PciDs
;
1322 // Open the input file
1324 if ((InFptr
= fopen (InFile
->FileName
, "rb")) == NULL
) {
1327 "ERROR: Could not open input file %s\n",
1333 // Go through the image and dump the header stuff for each
1338 // Save our postition in the file, since offsets in the headers
1339 // are relative to the particular image.
1341 ImageStart
= ftell (InFptr
);
1345 // Read the option ROM header. Have to assume a raw binary image for now.
1347 if (fread (&PciRomHdr
, sizeof (PciRomHdr
), 1, InFptr
) != 1) {
1348 fprintf (stdout
, "ERROR: Failed to read PCI ROM header from file\n");
1353 // Dump the contents of the header
1355 fprintf (stdout
, "Image %d -- Offset 0x%X\n", ImageCount
, ImageStart
);
1356 fprintf (stdout
, " ROM header contents\n");
1357 fprintf (stdout
, " Signature 0x%04X\n", (UINT32
) PciRomHdr
.Signature
);
1358 fprintf (stdout
, " PCIR offset 0x%04X\n", (UINT32
) PciRomHdr
.PcirOffset
);
1360 // Find PCI data structure
1362 if (fseek (InFptr
, ImageStart
+ PciRomHdr
.PcirOffset
, SEEK_SET
)) {
1363 fprintf (stdout
, "ERROR: Failed to seek to PCI data structure\n");
1367 // Read and dump the PCI data structure
1369 if (fread (&PciDs
, sizeof (PciDs
), 1, InFptr
) != 1) {
1370 fprintf (stdout
, "ERROR: Failed to read PCI data structure from file\n");
1374 fprintf (stdout
, " PCI Data Structure\n");
1377 " Signature %c%c%c%c\n",
1378 (char) PciDs
.Signature
,
1379 (char) (PciDs
.Signature
>> 8),
1380 (char) (PciDs
.Signature
>> 16),
1381 (char) (PciDs
.Signature
>> 24)
1383 fprintf (stdout
, " Vendor ID 0x%04X\n", PciDs
.VendorId
);
1384 fprintf (stdout
, " Device ID 0x%04X\n", PciDs
.DeviceId
);
1387 " Class Code 0x%06X\n",
1388 (UINT32
) (PciDs
.ClassCode
[0] | (PciDs
.ClassCode
[1] << 8) | (PciDs
.ClassCode
[2] << 16))
1390 fprintf (stdout
, " Image size 0x%X\n", PciDs
.ImageLength
* 512);
1391 fprintf (stdout
, " Code revision: 0x%04X\n", PciDs
.CodeRevision
);
1392 fprintf (stdout
, " Indicator 0x%02X", (UINT32
) PciDs
.Indicator
);
1394 // Print the indicator, used to flag the last image
1396 if (PciDs
.Indicator
== INDICATOR_LAST
) {
1397 fprintf (stdout
, " (last image)\n");
1399 fprintf (stdout
, "\n");
1402 // Print the code type. If EFI code, then we can provide more info.
1404 fprintf (stdout
, " Code type 0x%02X", (UINT32
) PciDs
.CodeType
);
1405 if (PciDs
.CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
1406 fprintf (stdout
, " (EFI image)\n");
1408 // Re-read the header as an EFI ROM header, then dump more info
1410 fprintf (stdout
, " EFI ROM header contents\n");
1411 if (fseek (InFptr
, ImageStart
, SEEK_SET
)) {
1412 fprintf (stdout
, "ERROR: Failed to re-seek to ROM header structure\n");
1416 if (fread (&EfiRomHdr
, sizeof (EfiRomHdr
), 1, InFptr
) != 1) {
1417 fprintf (stdout
, "ERROR: Failed to read EFI PCI ROM header from file\n");
1421 // Now dump more info
1423 fprintf (stdout
, " EFI Signature 0x%04X\n", EfiRomHdr
.EfiSignature
);
1426 " Compression Type 0x%04X ",
1427 (UINT32
) EfiRomHdr
.CompressionType
1429 if (EfiRomHdr
.CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
1430 fprintf (stdout
, "(compressed)\n");
1432 fprintf (stdout
, "(not compressed)\n");
1437 " Machine type 0x%04X (%s)\n",
1438 EfiRomHdr
.EfiMachineType
,
1439 GetMachineTypeStr (EfiRomHdr
.EfiMachineType
)
1443 " Subsystem 0x%04X (%s)\n",
1444 EfiRomHdr
.EfiSubsystem
,
1445 GetSubsystemTypeStr (EfiRomHdr
.EfiSubsystem
)
1449 " EFI image offset 0x%04X (@0x%X)\n",
1450 (UINT32
) EfiRomHdr
.EfiImageHeaderOffset
,
1451 (UINT32
) (EfiRomHdr
.EfiImageHeaderOffset
+ ImageStart
)
1458 fprintf (stdout
, "\n");
1461 // If code type is EFI image, then dump it as well?
1463 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
1466 // If last image, then we're done
1468 if (PciDs
.Indicator
== INDICATOR_LAST
) {
1472 // Seek to the start of the next image
1474 if (fseek (InFptr
, ImageStart
+ (PciDs
.ImageLength
* 512), SEEK_SET
)) {
1475 fprintf (stdout
, "ERROR: Failed to seek to next image\n");
1490 Routine Description:
1492 GC_TODO: Add function description
1496 MachineType - GC_TODO: add argument description
1500 GC_TODO: add return values
1506 for (Index
= 0; mMachineTypes
[Index
].Name
!= NULL
; Index
++) {
1507 if (mMachineTypes
[Index
].Value
== MachineType
) {
1508 return mMachineTypes
[Index
].Name
;
1517 GetSubsystemTypeStr (
1518 UINT16 SubsystemType
1522 Routine Description:
1524 GC_TODO: Add function description
1528 SubsystemType - GC_TODO: add argument description
1532 GC_TODO: add return values
1538 for (Index
= 0; mSubsystemTypes
[Index
].Name
!= NULL
; Index
++) {
1539 if (mSubsystemTypes
[Index
].Value
== SubsystemType
) {
1540 return mSubsystemTypes
[Index
].Name
;