--- /dev/null
+/*++\r
+\r
+Copyright (c) 2007, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+\r
+Module Name:\r
+\r
+ EfiRom.c\r
+ \r
+Abstract:\r
+\r
+ Utility program to create an EFI option ROM image from binary and \r
+ EFI PE32 files.\r
+\r
+\r
+--*/\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+//\r
+// Includes for EFI 1.1 build\r
+//\r
+// #include "Tiano.h" // required defines for Compress.h\r
+// #include "EfiImage.h" // for PE32 structure definitions\r
+// #include "Compress.h" // for compression function\r
+// Includes for Tiano build\r
+//\r
+#include "TianoCommon.h"\r
+#include "EfiImage.h" // for PE32 structure definitions\r
+#include "Compress.h"\r
+\r
+//\r
+// END include differences\r
+//\r
+#include "Pci22.h" // for option ROM header structures\r
+//\r
+// Version of this utility\r
+//\r
+#define UTILITY_VERSION "v2.5"\r
+\r
+//\r
+// Define some status return values\r
+//\r
+#define STATUS_SUCCESS 0\r
+#define STATUS_WARNING 1\r
+#define STATUS_ERROR 2\r
+\r
+//\r
+// Define the max length of a filename\r
+//\r
+#define MAX_PATH 200\r
+\r
+#define DEFAULT_OUTPUT_EXTENSION ".rom"\r
+\r
+//\r
+// Max size for an option ROM image\r
+//\r
+#define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB\r
+//\r
+// Values for the indicator field in the PCI data structure\r
+//\r
+#define INDICATOR_LAST 0x80 // last file in series of files\r
+//\r
+// Masks for the FILE_LIST.FileFlags field\r
+//\r
+#define FILE_FLAG_BINARY 0x01\r
+#define FILE_FLAG_EFI 0x02\r
+#define FILE_FLAG_COMPRESS 0x04\r
+\r
+//\r
+// Use this linked list structure to keep track of all the filenames\r
+// specified on the command line.\r
+//\r
+typedef struct _FILE_LIST {\r
+ struct _FILE_LIST *Next;\r
+ INT8 *FileName;\r
+ UINT32 FileFlags;\r
+ UINT32 ClassCode;\r
+ UINT16 CodeRevision;\r
+} FILE_LIST;\r
+\r
+//\r
+// Use this to track our command-line options\r
+//\r
+typedef struct {\r
+ INT8 OutFileName[MAX_PATH];\r
+ INT8 NoLast;\r
+ INT8 Verbose;\r
+ INT8 DumpOption;\r
+ UINT8 DevIdValid;\r
+ UINT8 VendIdValid;\r
+ UINT16 VendId;\r
+ UINT16 DevId;\r
+ FILE_LIST *FileList;\r
+} OPTIONS;\r
+\r
+//\r
+// Make a global structure to keep track of command-line options\r
+//\r
+static OPTIONS mOptions;\r
+\r
+//\r
+// Use these to convert from machine type value to a named type\r
+//\r
+typedef struct {\r
+ UINT16 Value;\r
+ char *Name;\r
+} STRING_LOOKUP;\r
+\r
+static STRING_LOOKUP mMachineTypes[] = {\r
+ EFI_IMAGE_MACHINE_IA32,\r
+ "IA32",\r
+ EFI_IMAGE_MACHINE_IA64,\r
+ "IA64",\r
+ EFI_IMAGE_MACHINE_EBC,\r
+ "EBC",\r
+ 0,\r
+ NULL\r
+};\r
+\r
+static STRING_LOOKUP mSubsystemTypes[] = {\r
+ EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,\r
+ "EFI application",\r
+ EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,\r
+ "EFI boot service driver",\r
+ EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,\r
+ "EFI runtime driver",\r
+ 0,\r
+ NULL\r
+};\r
+//\r
+// Function prototypes\r
+//\r
+static\r
+void\r
+Usage (\r
+ VOID\r
+ );\r
+\r
+static\r
+int\r
+ParseCommandLine (\r
+ int Argc,\r
+ char *Argv[],\r
+ OPTIONS *Options\r
+ );\r
+\r
+static\r
+int\r
+CheckPE32File (\r
+ FILE *Fptr,\r
+ UINT16 *MachineType,\r
+ UINT16 *SubSystem\r
+ );\r
+\r
+static\r
+int\r
+ProcessEfiFile (\r
+ FILE *OutFptr,\r
+ FILE_LIST *InFile,\r
+ UINT16 VendId,\r
+ UINT16 DevId,\r
+ UINT32 *Size\r
+ );\r
+\r
+static\r
+int\r
+ProcessBinFile (\r
+ FILE *OutFptr,\r
+ FILE_LIST *InFile,\r
+ UINT32 *Size\r
+ );\r
+\r
+static\r
+void\r
+DumpImage (\r
+ FILE_LIST *InFile\r
+ );\r
+\r
+char *\r
+GetMachineTypeStr (\r
+ UINT16 MachineType\r
+ );\r
+\r
+static\r
+char *\r
+GetSubsystemTypeStr (\r
+ UINT16 SubsystemType\r
+ );\r
+\r
+int\r
+main (\r
+ int Argc,\r
+ char *Argv[]\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Given an EFI image filename, create a ROM-able image by creating an option \r
+ ROM header and PCI data structure, filling them in, and then writing the\r
+ option ROM header + PCI data structure + EFI image out to the output file.\r
+\r
+Arguments:\r
+\r
+ Argc - standard C main() argument count\r
+\r
+ Argv - standard C main() argument list\r
+\r
+Returns:\r
+\r
+ 0 success\r
+ non-zero otherwise\r
+\r
+--*/\r
+// GC_TODO: ] - add argument and description to function comment\r
+{\r
+ INT8 *Ext;\r
+ FILE *FptrOut;\r
+ UINT32 Status;\r
+ FILE_LIST *FList;\r
+ UINT32 TotalSize;\r
+ UINT32 Size;\r
+\r
+ Status = STATUS_SUCCESS;\r
+ FptrOut = NULL;\r
+\r
+ //\r
+ // Parse the command line arguments\r
+ //\r
+ if (ParseCommandLine (Argc, Argv, &mOptions)) {\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // If dumping an image, then do that and quit\r
+ //\r
+ if (mOptions.DumpOption) {\r
+ DumpImage (mOptions.FileList);\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Determine the output filename. Either what they specified on\r
+ // the command line, or the first input filename with a different extension.\r
+ //\r
+ if (!mOptions.OutFileName[0]) {\r
+ strcpy (mOptions.OutFileName, mOptions.FileList->FileName);\r
+ //\r
+ // Find the last . on the line and replace the filename extension with\r
+ // the default\r
+ //\r
+ for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
+ (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');\r
+ Ext--\r
+ )\r
+ ;\r
+ //\r
+ // If dot here, then insert extension here, otherwise append\r
+ //\r
+ if (*Ext != '.') {\r
+ Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
+ }\r
+\r
+ strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
+ }\r
+ //\r
+ // Make sure we don't have the same filename for input and output files\r
+ //\r
+ for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
+ if (_stricmp (mOptions.OutFileName, FList->FileName) == 0) {\r
+ Status = STATUS_ERROR;\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Input and output file names must be different - %s = %s\n",\r
+ FList->FileName,\r
+ mOptions.OutFileName\r
+ );\r
+ goto BailOut;\r
+ }\r
+ }\r
+ //\r
+ // Now open our output file\r
+ //\r
+ if ((FptrOut = fopen (mOptions.OutFileName, "w+b")) == NULL) {\r
+ fprintf (stdout, "ERROR: Failed to open output file %s\n", mOptions.OutFileName);\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Process all our files\r
+ //\r
+ TotalSize = 0;\r
+ for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
+ Size = 0;\r
+ if (FList->FileFlags & FILE_FLAG_EFI) {\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, "Processing EFI file %s\n", FList->FileName);\r
+ }\r
+\r
+ Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);\r
+ } else if (FList->FileFlags & FILE_FLAG_BINARY) {\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, "Processing binary file %s\n", FList->FileName);\r
+ }\r
+\r
+ Status = ProcessBinFile (FptrOut, FList, &Size);\r
+ } else {\r
+ fprintf (stdout, "ERROR: File not specified as EFI or binary: %s\n", FList->FileName);\r
+ Status = STATUS_ERROR;\r
+ }\r
+\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, " Output size = 0x%X\n", Size);\r
+ }\r
+\r
+ if (Status != STATUS_SUCCESS) {\r
+ break;\r
+ }\r
+\r
+ TotalSize += Size;\r
+ }\r
+ //\r
+ // Check total size\r
+ //\r
+ if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Option ROM image size exceeds limit 0x%X bytes\n",\r
+ MAX_OPTION_ROM_SIZE\r
+ );\r
+ Status = STATUS_ERROR;\r
+ }\r
+\r
+BailOut:\r
+ if (FptrOut != NULL) {\r
+ fclose (FptrOut);\r
+ }\r
+ //\r
+ // Clean up our file list\r
+ //\r
+ while (mOptions.FileList != NULL) {\r
+ FList = mOptions.FileList->Next;\r
+ free (mOptions.FileList);\r
+ mOptions.FileList = FList;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+static\r
+int\r
+ProcessBinFile (\r
+ FILE *OutFptr,\r
+ FILE_LIST *InFile,\r
+ UINT32 *Size\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Process a binary input file.\r
+\r
+Arguments:\r
+\r
+ OutFptr - file pointer to output binary ROM image file we're creating\r
+ InFile - structure contains information on the binary file to process\r
+ Size - pointer to where to return the size added to the output file\r
+\r
+Returns:\r
+\r
+ 0 - successful\r
+\r
+--*/\r
+{\r
+ FILE *InFptr;\r
+ UINT32 TotalSize;\r
+ UINT32 FileSize;\r
+ UINT8 *Buffer;\r
+ UINT32 Status;\r
+ PCI_EXPANSION_ROM_HEADER *RomHdr;\r
+ PCI_DATA_STRUCTURE *PciDs;\r
+ UINT32 Index;\r
+ UINT8 ByteCheckSum;\r
+\r
+ Status = STATUS_SUCCESS;\r
+\r
+ //\r
+ // Try to open the input file\r
+ //\r
+ if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {\r
+ fprintf (stdout, "ERROR: Failed to open input file %s\n", InFile->FileName);\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Seek to the end of the input file and get the file size. Then allocate\r
+ // a buffer to read it in to.\r
+ //\r
+ fseek (InFptr, 0, SEEK_END);\r
+ FileSize = ftell (InFptr);\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, " File size = 0x%X\n", FileSize);\r
+ }\r
+\r
+ fseek (InFptr, 0, SEEK_SET);\r
+ Buffer = (INT8 *) malloc (FileSize);\r
+ if (Buffer == NULL) {\r
+ fprintf (stdout, "ERROR: Memory allocation failed\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read all bytes from input file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Total size must be an even multiple of 512 bytes, and can't exceed\r
+ // the option ROM image size.\r
+ //\r
+ TotalSize = FileSize;\r
+ if (TotalSize & 0x1FF) {\r
+ TotalSize = (TotalSize + 0x200) &~0x1ff;\r
+ }\r
+\r
+ if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",\r
+ InFile->FileName,\r
+ MAX_OPTION_ROM_SIZE\r
+ );\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Return the size to the caller so they can keep track of the running total.\r
+ //\r
+ *Size = TotalSize;\r
+\r
+ //\r
+ // Crude check to make sure it's a legitimate ROM image\r
+ //\r
+ RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;\r
+ if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
+ fprintf (stdout, "ERROR: ROM image file has invalid ROM signature\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Make sure the pointer to the PCI data structure is within the size of the image.\r
+ // Then check it for valid signature.\r
+ //\r
+ if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {\r
+ fprintf (stdout, "ERROR: Invalid PCI data structure offset\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ PciDs = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);\r
+ if (PciDs->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
+ fprintf (stdout, "ERROR: PCI data structure has invalid signature\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // If this is the last image, then set the LAST bit unless requested not\r
+ // to via the command-line -l argument. Otherwise, make sure you clear it.\r
+ //\r
+ if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
+ PciDs->Indicator = INDICATOR_LAST;\r
+ } else {\r
+ PciDs->Indicator = 0;\r
+ }\r
+\r
+ ByteCheckSum = 0;\r
+ for (Index = 0; Index < FileSize - 1; Index++) {\r
+ ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);\r
+ }\r
+\r
+ Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);\r
+ fprintf (stdout, "CheckSUm = %02x\n", (UINT32) Buffer[FileSize - 1]);\r
+\r
+ //\r
+ // Now copy the input file contents out to the output file\r
+ //\r
+ if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to write all file bytes to output file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ TotalSize -= FileSize;\r
+ //\r
+ // Pad the rest of the image to make it a multiple of 512 bytes\r
+ //\r
+ while (TotalSize > 0) {\r
+ putc (~0, OutFptr);\r
+ TotalSize--;\r
+ }\r
+\r
+BailOut:\r
+ if (InFptr != NULL) {\r
+ fclose (InFptr);\r
+ }\r
+\r
+ if (Buffer != NULL) {\r
+ free (Buffer);\r
+ }\r
+ //\r
+ // Print the file name if errors occurred\r
+ //\r
+ if (Status != STATUS_SUCCESS) {\r
+ fprintf (stdout, "Error processing binary file %s\n", InFile->FileName);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+static\r
+int\r
+ProcessEfiFile (\r
+ FILE *OutFptr,\r
+ FILE_LIST *InFile,\r
+ UINT16 VendId,\r
+ UINT16 DevId,\r
+ UINT32 *Size\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Process a PE32 EFI file.\r
+\r
+Arguments:\r
+\r
+ OutFptr - file pointer to output binary ROM image file we're creating\r
+ InFile - structure contains information on the PE32 file to process\r
+ VendId - vendor ID as required in the option ROM header\r
+ DevId - device ID as required in the option ROM header\r
+ Size - pointer to where to return the size added to the output file\r
+\r
+Returns:\r
+\r
+ 0 - successful\r
+\r
+--*/\r
+{\r
+ UINT32 Status;\r
+ FILE *InFptr;\r
+ EFI_PCI_EXPANSION_ROM_HEADER RomHdr;\r
+ PCI_DATA_STRUCTURE PciDs;\r
+ UINT32 FileSize;\r
+ UINT32 CompressedFileSize;\r
+ UINT8 *Buffer;\r
+ UINT8 *CompressedBuffer;\r
+ UINT8 *TempBufferPtr;\r
+ UINT32 TotalSize;\r
+ UINT32 HeaderSize;\r
+ UINT16 MachineType;\r
+ UINT16 SubSystem;\r
+ UINT32 HeaderPadBytes;\r
+\r
+ //\r
+ // Try to open the input file\r
+ //\r
+ if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {\r
+ fprintf (stdout, "ERROR: Failed to open input file %s\n", InFile->FileName);\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Initialize our buffer pointers to null.\r
+ //\r
+ Buffer = NULL;\r
+ CompressedBuffer = NULL;\r
+\r
+ //\r
+ // Double-check the file to make sure it's what we expect it to be\r
+ //\r
+ Status = CheckPE32File (InFptr, &MachineType, &SubSystem);\r
+ if (Status != STATUS_SUCCESS) {\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Seek to the end of the input file and get the file size\r
+ //\r
+ fseek (InFptr, 0, SEEK_END);\r
+ FileSize = ftell (InFptr);\r
+\r
+ //\r
+ // Get the size of the headers we're going to put in front of the image. The\r
+ // EFI header must be aligned on a 4-byte boundary, so pad accordingly.\r
+ //\r
+ if (sizeof (RomHdr) & 0x03) {\r
+ HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);\r
+ } else {\r
+ HeaderPadBytes = 0;\r
+ }\r
+\r
+ HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, " File size = 0x%X\n", FileSize);\r
+ }\r
+ //\r
+ // Allocate memory for the entire file (in case we have to compress), then\r
+ // seek back to the beginning of the file and read it into our buffer.\r
+ //\r
+ Buffer = (INT8 *) malloc (FileSize);\r
+ if (Buffer == NULL) {\r
+ fprintf (stdout, "ERROR: Memory allocation failed\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ fseek (InFptr, 0, SEEK_SET);\r
+ if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read all bytes from input file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Now determine the size of the final output file. It's either the header size\r
+ // plus the file's size, or the header size plus the compressed file size.\r
+ //\r
+ if (InFile->FileFlags & FILE_FLAG_COMPRESS) {\r
+ //\r
+ // Allocate a buffer into which we can compress the image, compress it,\r
+ // and use that size as the new size.\r
+ //\r
+ CompressedBuffer = (INT8 *) malloc (FileSize);\r
+ if (CompressedBuffer == NULL) {\r
+ fprintf (stdout, "ERROR: Memory allocation failed\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ CompressedFileSize = FileSize;\r
+ Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);\r
+ if (Status != STATUS_SUCCESS) {\r
+ fprintf (stdout, "ERROR: Compression failed\n");\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Now compute the size, then swap buffer pointers.\r
+ //\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, " Comp size = 0x%X\n", CompressedFileSize);\r
+ }\r
+\r
+ TotalSize = CompressedFileSize + HeaderSize;\r
+ FileSize = CompressedFileSize;\r
+ TempBufferPtr = Buffer;\r
+ Buffer = CompressedBuffer;\r
+ CompressedBuffer = TempBufferPtr;\r
+ } else {\r
+ TotalSize = FileSize + HeaderSize;\r
+ }\r
+ //\r
+ // Total size must be an even multiple of 512 bytes\r
+ //\r
+ if (TotalSize & 0x1FF) {\r
+ TotalSize = (TotalSize + 0x200) &~0x1ff;\r
+ }\r
+ //\r
+ // Check size\r
+ //\r
+ if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",\r
+ InFile->FileName,\r
+ MAX_OPTION_ROM_SIZE\r
+ );\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Return the size to the caller so they can keep track of the running total.\r
+ //\r
+ *Size = TotalSize;\r
+\r
+ //\r
+ // Now fill in the ROM header. These values come from chapter 18 of the\r
+ // EFI 1.02 specification.\r
+ //\r
+ memset (&RomHdr, 0, sizeof (RomHdr));\r
+ RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;\r
+ RomHdr.InitializationSize = (UINT16) (TotalSize / 512);\r
+ RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;\r
+ RomHdr.EfiSubsystem = SubSystem;\r
+ RomHdr.EfiMachineType = MachineType;\r
+ RomHdr.EfiImageHeaderOffset = (UINT16) HeaderSize;\r
+ RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);\r
+ //\r
+ // Set image as compressed or not\r
+ //\r
+ if (InFile->FileFlags & FILE_FLAG_COMPRESS) {\r
+ RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;\r
+ }\r
+ //\r
+ // Fill in the PCI data structure\r
+ //\r
+ memset (&PciDs, 0, sizeof (PCI_DATA_STRUCTURE));\r
+\r
+ PciDs.Signature = PCI_DATA_STRUCTURE_SIGNATURE;\r
+ PciDs.VendorId = VendId;\r
+ PciDs.DeviceId = DevId;\r
+ PciDs.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);\r
+ PciDs.Revision = 0;\r
+ //\r
+ // Class code and code revision from the command line (optional)\r
+ //\r
+ PciDs.ClassCode[0] = (UINT8) InFile->ClassCode;\r
+ PciDs.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);\r
+ PciDs.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);\r
+ PciDs.ImageLength = RomHdr.InitializationSize;\r
+ PciDs.CodeRevision = InFile->CodeRevision;\r
+ PciDs.CodeType = PCI_CODE_TYPE_EFI_IMAGE;\r
+\r
+ //\r
+ // If this is the last image, then set the LAST bit unless requested not\r
+ // to via the command-line -l argument.\r
+ //\r
+ if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
+ PciDs.Indicator = INDICATOR_LAST;\r
+ }\r
+ //\r
+ // Write the ROM header to the output file\r
+ //\r
+ if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to write ROM header to output file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ //\r
+ // Write pad bytes to align the PciDs\r
+ //\r
+ while (HeaderPadBytes > 0) {\r
+ if (putc (0, OutFptr) == EOF) {\r
+ fprintf (stdout, "ERROR: Failed to write ROM header pad bytes to output file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ HeaderPadBytes--;\r
+ }\r
+ //\r
+ // Write the PCI data structure header to the output file\r
+ //\r
+ if (fwrite (&PciDs, sizeof (PciDs), 1, OutFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to write PCI ROM header to output file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Keep track of how many bytes left to write\r
+ //\r
+ TotalSize -= HeaderSize;\r
+\r
+ //\r
+ // Now dump the input file's contents to the output file\r
+ //\r
+ if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to write all file bytes to output file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ TotalSize -= FileSize;\r
+ //\r
+ // Pad the rest of the image to make it a multiple of 512 bytes\r
+ //\r
+ while (TotalSize > 0) {\r
+ if (putc (~0, OutFptr) == EOF) {\r
+ fprintf (stdout, "ERROR: Failed to write trailing pad bytes output file\n");\r
+ Status = STATUS_ERROR;\r
+ goto BailOut;\r
+ }\r
+\r
+ TotalSize--;\r
+ }\r
+\r
+BailOut:\r
+ if (InFptr != NULL) {\r
+ fclose (InFptr);\r
+ }\r
+\r
+ //\r
+ // Free up our buffers\r
+ //\r
+ if (Buffer != NULL) {\r
+ free (Buffer);\r
+ }\r
+\r
+ if (CompressedBuffer != NULL) {\r
+ free (CompressedBuffer);\r
+ }\r
+ //\r
+ // Print the file name if errors occurred\r
+ //\r
+ if (Status != STATUS_SUCCESS) {\r
+ fprintf (stdout, "Error processing EFI file %s\n", InFile->FileName);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+static\r
+int\r
+CheckPE32File (\r
+ FILE *Fptr,\r
+ UINT16 *MachineType,\r
+ UINT16 *SubSystem\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Fptr - GC_TODO: add argument description\r
+ MachineType - GC_TODO: add argument description\r
+ SubSystem - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ /*++\r
+\r
+Routine Description:\r
+ \r
+ Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
+ PE32 image file, and then return the machine type in the supplied pointer.\r
+\r
+Arguments:\r
+\r
+ Fptr File pointer to the already-opened PE32 file\r
+ MachineType Location to stuff the machine type of the PE32 file. This is needed\r
+ because the image may be Itanium-based, IA32, or EBC.\r
+\r
+Returns:\r
+\r
+ 0 success\r
+ non-zero otherwise\r
+\r
+--*/\r
+ EFI_IMAGE_DOS_HEADER DosHeader;\r
+ EFI_IMAGE_FILE_HEADER FileHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;\r
+ UINT32 PESig;\r
+\r
+ //\r
+ // Position to the start of the file\r
+ //\r
+ fseek (Fptr, 0, SEEK_SET);\r
+\r
+ //\r
+ // Read the DOS header\r
+ //\r
+ if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read the DOS stub from the input file\n");\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Check the magic number (0x5A4D)\r
+ //\r
+ if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
+ fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (magic number)\n");\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Position into the file and check the PE signature\r
+ //\r
+ fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
+ if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read PE signature bytes from input file\n");\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Check the PE signature in the header "PE\0\0"\r
+ //\r
+ if (PESig != EFI_IMAGE_NT_SIGNATURE) {\r
+ fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (signature)\n");\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Read the file header and stuff their MachineType\r
+ //\r
+ if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read PE file header from input file\n");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memcpy ((char *) MachineType, &FileHdr.Machine, 2);\r
+\r
+ //\r
+ // Read the optional header so we can get the subsystem\r
+ //\r
+ if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read COFF optional header from input file\n");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ *SubSystem = OptionalHdr.Subsystem;\r
+ if (mOptions.Verbose) {\r
+ fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem);\r
+ }\r
+ //\r
+ // Good to go\r
+ //\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+int\r
+ParseCommandLine (\r
+ int Argc,\r
+ char *Argv[],\r
+ OPTIONS *Options\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Given the Argc/Argv program arguments, and a pointer to an options structure,\r
+ parse the command-line options and check their validity.\r
+\r
+\r
+Arguments:\r
+\r
+ Argc - standard C main() argument count\r
+ Argv[] - standard C main() argument list\r
+ Options - pointer to a structure to store the options in\r
+\r
+Returns:\r
+\r
+ STATUS_SUCCESS success\r
+ non-zero otherwise\r
+\r
+--*/\r
+//\r
+{\r
+ FILE_LIST *FileList;\r
+\r
+ FILE_LIST *PrevFileList;\r
+ UINT32 FileFlags;\r
+ UINT32 ClassCode;\r
+ UINT32 CodeRevision;\r
+\r
+ FileFlags = 0;\r
+\r
+ //\r
+ // Clear out the options\r
+ //\r
+ memset ((char *) Options, 0, sizeof (OPTIONS));\r
+\r
+ //\r
+ // To avoid compile warnings\r
+ //\r
+ FileList = PrevFileList = NULL;\r
+\r
+ ClassCode = 0;\r
+ CodeRevision = 0;\r
+ //\r
+ // Skip over the program name\r
+ //\r
+ Argc--;\r
+ Argv++;\r
+\r
+ //\r
+ // If no arguments, assume they want usage info\r
+ //\r
+ if (Argc == 0) {\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Process until no more arguments\r
+ //\r
+ while (Argc > 0) {\r
+ if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) {\r
+ //\r
+ // To simplify string comparisons, replace slashes with dashes\r
+ //\r
+ Argv[0][0] = '-';\r
+\r
+ //\r
+ // Vendor ID specified with -v\r
+ //\r
+ if (_stricmp (Argv[0], "-v") == 0) {\r
+ //\r
+ // Make sure there's another parameter\r
+ //\r
+ if (Argc > 1) {\r
+ Options->VendId = (UINT16) strtol (Argv[1], NULL, 16);\r
+ Options->VendIdValid = 1;\r
+ } else {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Missing Vendor ID with %s\n\n",\r
+ Argv[0]\r
+ );\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argv++;\r
+ Argc--;\r
+ } else if (_stricmp (Argv[0], "-d") == 0) {\r
+ //\r
+ // Device ID specified with -d\r
+ // Make sure there's another parameter\r
+ //\r
+ if (Argc > 1) {\r
+ Options->DevId = (UINT16) strtol (Argv[1], NULL, 16);\r
+ Options->DevIdValid = 1;\r
+ } else {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Missing Device ID with %s\n\n",\r
+ Argv[0]\r
+ );\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argv++;\r
+ Argc--;\r
+ } else if (_stricmp (Argv[0], "-o") == 0) {\r
+ //\r
+ // Output filename specified with -o\r
+ // Make sure there's another parameter\r
+ //\r
+ if (Argc > 1) {\r
+ strcpy (Options->OutFileName, Argv[1]);\r
+ } else {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Missing output file name with %s\n\n",\r
+ Argv[0]\r
+ );\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argv++;\r
+ Argc--;\r
+ } else if ((_stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
+ //\r
+ // Help option\r
+ //\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ } else if (_stricmp (Argv[0], "-b") == 0) {\r
+ //\r
+ // Specify binary files with -b\r
+ //\r
+ FileFlags = (FileFlags &~FILE_FLAG_EFI) | FILE_FLAG_BINARY;\r
+ } else if ((_stricmp (Argv[0], "-e") == 0) || (_stricmp (Argv[0], "-ec") == 0)) {\r
+ //\r
+ // Specify EFI files with -e. Specify EFI-compressed with -ec.\r
+ //\r
+ FileFlags = (FileFlags &~FILE_FLAG_BINARY) | FILE_FLAG_EFI;\r
+ if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {\r
+ FileFlags |= FILE_FLAG_COMPRESS;\r
+ }\r
+ //\r
+ // Specify not to set the LAST bit in the last file with -l\r
+ //\r
+ } else if (_stricmp (Argv[0], "-l") == 0) {\r
+ Options->NoLast = 1;\r
+ } else if (_stricmp (Argv[0], "-p") == 0) {\r
+ //\r
+ // -v for verbose would have been nicer, but it's already used. Let's use\r
+ // -p for prolix (wordy) output\r
+ //\r
+ Options->Verbose = 1;\r
+ } else if (_stricmp (Argv[0], "-dump") == 0) {\r
+ //\r
+ // -dump for dumping a ROM image. In this case, say that the device id\r
+ // and vendor id are valid so we don't have to specify bogus ones on the\r
+ // command line.\r
+ //\r
+ Options->DumpOption = 1;\r
+\r
+ Options->VendIdValid = 1;\r
+ Options->DevIdValid = 1;\r
+ FileFlags = FILE_FLAG_BINARY;\r
+ } else if (_stricmp (Argv[0], "-cc") == 0) {\r
+ //\r
+ // Class code value for the next file in the list.\r
+ // Make sure there's another parameter\r
+ //\r
+ if (Argc > 1) {\r
+ //\r
+ // No error checking on the return value. Could check for LONG_MAX,\r
+ // LONG_MIN, or 0 class code value if desired. Check range (3 bytes)\r
+ // at least.\r
+ //\r
+ ClassCode = (UINT32) strtol (Argv[1], NULL, 16);\r
+ if (ClassCode & 0xFF000000) {\r
+ fprintf (stdout, "ERROR: Class code %s out of range\n", Argv[1]);\r
+ return STATUS_ERROR;\r
+ }\r
+ } else {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Missing class code value with %s\n\n",\r
+ Argv[0]\r
+ );\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argv++;\r
+ Argc--;\r
+ } else if (_stricmp (Argv[0], "-rev") == 0) {\r
+ //\r
+ // Code revision in the PCI data structure. The value is for the next\r
+ // file in the list.\r
+ // Make sure there's another parameter\r
+ //\r
+ if (Argc > 1) {\r
+ //\r
+ // No error checking on the return value. Could check for LONG_MAX,\r
+ // LONG_MIN, or 0 value if desired. Check range (2 bytes)\r
+ // at least.\r
+ //\r
+ CodeRevision = (UINT32) strtol (Argv[1], NULL, 16);\r
+ if (CodeRevision & 0xFFFF0000) {\r
+ fprintf (stdout, "ERROR: Code revision %s out of range\n", Argv[1]);\r
+ return STATUS_ERROR;\r
+ }\r
+ } else {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Missing code revision value with %s\n\n",\r
+ Argv[0]\r
+ );\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argv++;\r
+ Argc--;\r
+ } else {\r
+ fprintf (stdout, "ERROR: Invalid option specified: %s\n\n", Argv[0]);\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+ } else {\r
+ //\r
+ // Not a slash-option argument. Must be a file name. Make sure they've specified\r
+ // -e or -b already.\r
+ //\r
+ if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {\r
+ fprintf (stdout, "ERROR: Missing -e or -b with input file %s\n", Argv[0]);\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Create a new file structure\r
+ //\r
+ FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
+ if (FileList == NULL) {\r
+ fprintf (stdout, "ERROR: Memory allocation failure\n");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memset ((char *) FileList, 0, sizeof (FILE_LIST));\r
+ FileList->FileName = Argv[0];\r
+ FileList->FileFlags = FileFlags;\r
+ if (Options->FileList == NULL) {\r
+ Options->FileList = FileList;\r
+ } else {\r
+ if (PrevFileList == NULL) {\r
+ PrevFileList = FileList;\r
+ } else { \r
+ PrevFileList->Next = FileList;\r
+ }\r
+ }\r
+\r
+ PrevFileList = FileList;\r
+ //\r
+ // Set the class code and code revision for this file, then reset the values.\r
+ //\r
+ FileList->ClassCode = ClassCode;\r
+ FileList->CodeRevision = (UINT16) CodeRevision;\r
+ ClassCode = 0;\r
+ CodeRevision = 0;\r
+ }\r
+ //\r
+ // Next argument\r
+ //\r
+ Argv++;\r
+ Argc--;\r
+ }\r
+ //\r
+ // Make sure they specified a device ID and vendor ID\r
+ //\r
+ if (!Options->VendIdValid) {\r
+ fprintf (stdout, "ERROR: Missing Vendor ID on command line\n\n");\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if (!Options->DevIdValid) {\r
+ fprintf (stdout, "ERROR: Missing Device ID on command line\n\n");\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Must have specified some files\r
+ //\r
+ if (Options->FileList == NULL) {\r
+ fprintf (stdout, "ERROR: Missing input file name\n");\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static\r
+void\r
+Usage (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Print usage information for this utility.\r
+\r
+Arguments:\r
+\r
+ None.\r
+\r
+Returns:\r
+\r
+ Nothing.\r
+\r
+--*/\r
+{\r
+ int Index;\r
+ static const char *Msg[] = {\r
+ "EfiRom "UTILITY_VERSION" - Intel EFI Make Option ROM utility",\r
+ " Copyright (C), 1999 - 2002 Intel Coproration\n",\r
+ " Create an option ROM image from a list of input files",\r
+ " Usage: efirom {-p} [-v VendorId] [-d DeviceId] {-o OutFileName} ",\r
+ " [-e|-b] [FileName(s)]",\r
+ " where:",\r
+ " VendorId - required hex PCI Vendor ID for the device",\r
+ " DeviceId - required hex PCI Device ID for the device",\r
+ " OutFileName - optional output file name. Default is the first input",\r
+ " file name with a "DEFAULT_OUTPUT_EXTENSION" file extension",\r
+ " FileNames - input PE32 or binary file name(s)",\r
+ " BinFileName - input binary file name(s)",\r
+ " -p - for verbose output",\r
+ " -l - to not automatically set the LAST bit on the last file",\r
+ " -b - following FileNames are binary files",\r
+ " -e - following FileNames are EFI PE32 image files",\r
+ " -ec - following FileNames are EFI PE32 image files, and should",\r
+ " be compressed by this utility",\r
+ " -cc ClassCode - to use hex ClassCode in the PCI data structure header for",\r
+ " the following FileName",\r
+ " -rev Revision - to use hex Revision in the PCI data structure header for",\r
+ " the following FileName",\r
+ " -dump - to dump the headers of an existing option ROM image",\r
+ "",\r
+ "Example usage: EfiRom -v 0xABCD -d 0x1234 -b File1.bin File2.bin -e File1.efi File2.efi ",\r
+ "",\r
+ NULL\r
+ };\r
+\r
+ for (Index = 0; Msg[Index] != NULL; Index++) {\r
+ fprintf (stdout, "%s\n", Msg[Index]);\r
+ }\r
+}\r
+\r
+static\r
+void\r
+DumpImage (\r
+ FILE_LIST *InFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ InFile - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ PCI_EXPANSION_ROM_HEADER PciRomHdr;\r
+ FILE *InFptr;\r
+ UINT32 ImageStart;\r
+ UINT32 ImageCount;\r
+ EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr;\r
+ PCI_DATA_STRUCTURE PciDs;\r
+\r
+ //\r
+ // Open the input file\r
+ //\r
+ if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {\r
+ fprintf (\r
+ stdout,\r
+ "ERROR: Could not open input file %s\n",\r
+ InFile->FileName\r
+ );\r
+ return ;\r
+ }\r
+ //\r
+ // Go through the image and dump the header stuff for each\r
+ //\r
+ ImageCount = 0;\r
+ for (;;) {\r
+ //\r
+ // Save our postition in the file, since offsets in the headers\r
+ // are relative to the particular image.\r
+ //\r
+ ImageStart = ftell (InFptr);\r
+ ImageCount++;\r
+\r
+ //\r
+ // Read the option ROM header. Have to assume a raw binary image for now.\r
+ //\r
+ if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read PCI ROM header from file\n");\r
+ goto BailOut;\r
+ }\r
+\r
+ //\r
+ // Dump the contents of the header\r
+ //\r
+ fprintf (stdout, "Image %d -- Offset 0x%X\n", ImageCount, ImageStart);\r
+ fprintf (stdout, " ROM header contents\n");\r
+ fprintf (stdout, " Signature 0x%04X\n", (UINT32) PciRomHdr.Signature);\r
+ fprintf (stdout, " PCIR offset 0x%04X\n", (UINT32) PciRomHdr.PcirOffset);\r
+ //\r
+ // Find PCI data structure\r
+ //\r
+ if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {\r
+ fprintf (stdout, "ERROR: Failed to seek to PCI data structure\n");\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Read and dump the PCI data structure\r
+ //\r
+ if (fread (&PciDs, sizeof (PciDs), 1, InFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read PCI data structure from file\n");\r
+ goto BailOut;\r
+ }\r
+\r
+ fprintf (stdout, " PCI Data Structure\n");\r
+ fprintf (\r
+ stdout,\r
+ " Signature %c%c%c%c\n",\r
+ (char) PciDs.Signature,\r
+ (char) (PciDs.Signature >> 8),\r
+ (char) (PciDs.Signature >> 16),\r
+ (char) (PciDs.Signature >> 24)\r
+ );\r
+ fprintf (stdout, " Vendor ID 0x%04X\n", PciDs.VendorId);\r
+ fprintf (stdout, " Device ID 0x%04X\n", PciDs.DeviceId);\r
+ fprintf (\r
+ stdout,\r
+ " Class Code 0x%06X\n",\r
+ (UINT32) (PciDs.ClassCode[0] | (PciDs.ClassCode[1] << 8) | (PciDs.ClassCode[2] << 16))\r
+ );\r
+ fprintf (stdout, " Image size 0x%X\n", PciDs.ImageLength * 512);\r
+ fprintf (stdout, " Code revision: 0x%04X\n", PciDs.CodeRevision);\r
+ fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs.Indicator);\r
+ //\r
+ // Print the indicator, used to flag the last image\r
+ //\r
+ if (PciDs.Indicator == INDICATOR_LAST) {\r
+ fprintf (stdout, " (last image)\n");\r
+ } else {\r
+ fprintf (stdout, "\n");\r
+ }\r
+ //\r
+ // Print the code type. If EFI code, then we can provide more info.\r
+ //\r
+ fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs.CodeType);\r
+ if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
+ fprintf (stdout, " (EFI image)\n");\r
+ //\r
+ // Re-read the header as an EFI ROM header, then dump more info\r
+ //\r
+ fprintf (stdout, " EFI ROM header contents\n");\r
+ if (fseek (InFptr, ImageStart, SEEK_SET)) {\r
+ fprintf (stdout, "ERROR: Failed to re-seek to ROM header structure\n");\r
+ goto BailOut;\r
+ }\r
+\r
+ if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {\r
+ fprintf (stdout, "ERROR: Failed to read EFI PCI ROM header from file\n");\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Now dump more info\r
+ //\r
+ fprintf (stdout, " EFI Signature 0x%04X\n", EfiRomHdr.EfiSignature);\r
+ fprintf (\r
+ stdout,\r
+ " Compression Type 0x%04X ",\r
+ (UINT32) EfiRomHdr.CompressionType\r
+ );\r
+ if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
+ fprintf (stdout, "(compressed)\n");\r
+ } else {\r
+ fprintf (stdout, "(not compressed)\n");\r
+ }\r
+\r
+ fprintf (\r
+ stdout,\r
+ " Machine type 0x%04X (%s)\n",\r
+ EfiRomHdr.EfiMachineType,\r
+ GetMachineTypeStr (EfiRomHdr.EfiMachineType)\r
+ );\r
+ fprintf (\r
+ stdout,\r
+ " Subsystem 0x%04X (%s)\n",\r
+ EfiRomHdr.EfiSubsystem,\r
+ GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)\r
+ );\r
+ fprintf (\r
+ stdout,\r
+ " EFI image offset 0x%04X (@0x%X)\n",\r
+ (UINT32) EfiRomHdr.EfiImageHeaderOffset,\r
+ (UINT32) (EfiRomHdr.EfiImageHeaderOffset + ImageStart)\r
+ );\r
+\r
+ } else {\r
+ //\r
+ // Not an EFI image\r
+ //\r
+ fprintf (stdout, "\n");\r
+ }\r
+ //\r
+ // If code type is EFI image, then dump it as well?\r
+ //\r
+ // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
+ // }\r
+ //\r
+ // If last image, then we're done\r
+ //\r
+ if (PciDs.Indicator == INDICATOR_LAST) {\r
+ goto BailOut;\r
+ }\r
+ //\r
+ // Seek to the start of the next image\r
+ //\r
+ if (fseek (InFptr, ImageStart + (PciDs.ImageLength * 512), SEEK_SET)) {\r
+ fprintf (stdout, "ERROR: Failed to seek to next image\n");\r
+ goto BailOut;\r
+ }\r
+ }\r
+\r
+BailOut:\r
+ fclose (InFptr);\r
+}\r
+\r
+char *\r
+GetMachineTypeStr (\r
+ UINT16 MachineType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ MachineType - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ int Index;\r
+\r
+ for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {\r
+ if (mMachineTypes[Index].Value == MachineType) {\r
+ return mMachineTypes[Index].Name;\r
+ }\r
+ }\r
+\r
+ return "unknown";\r
+}\r
+\r
+static\r
+char *\r
+GetSubsystemTypeStr (\r
+ UINT16 SubsystemType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SubsystemType - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ int Index;\r
+\r
+ for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {\r
+ if (mSubsystemTypes[Index].Value == SubsystemType) {\r
+ return mSubsystemTypes[Index].Name;\r
+ }\r
+ }\r
+\r
+ return "unknown";\r
+}\r