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
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
;