3 Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
18 Utility program to create an EFI option ROM image from binary and
29 // Includes for EFI 1.1 build
31 // #include "Tiano.h" // required defines for Compress.h
32 // #include "EfiImage.h" // for PE32 structure definitions
33 // #include "Compress.h" // for compression function
34 // Includes for Tiano build
36 #include <UefiBaseTypes.h>
37 #include <EfiImage.h> // for PE32 structure definitions
38 #include <EfiCompress.h>
39 #include <CommonLib.h>
40 #include <MultiPhase.h>
43 // END include differences
45 #include "pci22.h" // for option ROM header structures
47 // Version of this utility
49 #define UTILITY_VERSION "v2.5"
52 // Define some status return values
54 #define STATUS_SUCCESS 0
55 #define STATUS_WARNING 1
56 #define STATUS_ERROR 2
59 // Define the max length of a filename
63 #define DEFAULT_OUTPUT_EXTENSION ".rom"
66 // Max size for an option ROM image
68 #define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB
70 // Values for the indicator field in the PCI data structure
72 #define INDICATOR_LAST 0x80 // last file in series of files
74 // Masks for the FILE_LIST.FileFlags field
76 #define FILE_FLAG_BINARY 0x01
77 #define FILE_FLAG_EFI 0x02
78 #define FILE_FLAG_COMPRESS 0x04
81 // Use this linked list structure to keep track of all the filenames
82 // specified on the command line.
84 typedef struct _FILE_LIST
{
85 struct _FILE_LIST
*Next
;
93 // Use this to track our command-line options
96 INT8 OutFileName
[MAX_PATH
];
108 // Make a global structure to keep track of command-line options
110 static OPTIONS mOptions
;
113 // Use these to convert from machine type value to a named type
120 static STRING_LOOKUP mMachineTypes
[] = {
121 EFI_IMAGE_MACHINE_IA32
,
123 EFI_IMAGE_MACHINE_IA64
,
125 EFI_IMAGE_MACHINE_EBC
,
131 static STRING_LOOKUP mSubsystemTypes
[] = {
132 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
,
134 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
,
135 "EFI boot service driver",
136 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
,
137 "EFI runtime driver",
142 // Function prototypes
197 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
= Compress (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
;