/** @file
Utility program to create an EFI option ROM image from binary and EFI PE32 files.
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "EfiUtilityMsgs.h"
#include "ParseInf.h"
#include "EfiRom.h"
UINT64 DebugLevel = 0;
int
main (
int Argc,
char *Argv[]
)
/*++
Routine Description:
Given an EFI image filename, create a ROM-able image by creating an option
ROM header and PCI data structure, filling them in, and then writing the
option ROM header + PCI data structure + EFI image out to the output file.
Arguments:
Argc - standard C main() argument count
Argv - standard C main() argument list
Returns:
0 success
non-zero otherwise
--*/
{
CHAR8 *Ext;
FILE *FptrOut;
UINT32 Status;
FILE_LIST *FList;
UINT32 TotalSize;
UINT32 Size;
CHAR8 *Ptr0;
SetUtilityName(UTILITY_NAME);
Status = STATUS_SUCCESS;
FptrOut = NULL;
//
// Parse the command line arguments
//
if (ParseCommandLine (Argc, Argv, &mOptions)) {
return STATUS_ERROR;
}
if (mOptions.Quiet) {
SetPrintLevel(40);
} else if (mOptions.Verbose) {
SetPrintLevel(15);
} else if (mOptions.Debug) {
SetPrintLevel(DebugLevel);
}
if (mOptions.Verbose) {
VerboseMsg("%s tool start.\n", UTILITY_NAME);
}
//
// If dumping an image, then do that and quit
//
if (mOptions.DumpOption == 1) {
if (mOptions.FileList != NULL) {
if ((Ptr0 = strstr ((CONST CHAR8 *) mOptions.FileList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {
DumpImage (mOptions.FileList);
goto BailOut;
} else {
Error (NULL, 0, 1002, "No PciRom input file", "No *.rom input file");
goto BailOut;
}
}
}
//
// Determine the output filename. Either what they specified on
// the command line, or the first input filename with a different extension.
//
if (!mOptions.OutFileName[0]) {
if (mOptions.FileList != NULL) {
if (strlen (mOptions.FileList->FileName) >= MAX_PATH) {
Status = STATUS_ERROR;
Error (NULL, 0, 2000, "Invalid parameter", "Input file name is too long - %s.", mOptions.FileList->FileName);
goto BailOut;
}
strncpy (mOptions.OutFileName, mOptions.FileList->FileName, MAX_PATH - 1);
mOptions.OutFileName[MAX_PATH - 1] = 0;
//
// Find the last . on the line and replace the filename extension with
// the default
//
Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;
while (Ext >= mOptions.OutFileName) {
if ((*Ext == '.') || (*Ext == '\\')) {
break;
}
Ext--;
}
//
// If dot here, then insert extension here, otherwise append
//
if (*Ext != '.') {
Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);
}
strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);
}
}
//
// Make sure we don't have the same filename for input and output files
//
for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {
Status = STATUS_ERROR;
Error (NULL, 0, 1002, "Invalid input parameter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);
goto BailOut;
}
}
//
// Now open our output file
//
if ((FptrOut = fopen (LongFilePath (mOptions.OutFileName), "wb")) == NULL) {
Error (NULL, 0, 0001, "Error opening file", "Error opening file %s", mOptions.OutFileName);
goto BailOut;
}
//
// Process all our files
//
TotalSize = 0;
for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
Size = 0;
if ((FList->FileFlags & FILE_FLAG_EFI) != 0) {
if (mOptions.Verbose) {
VerboseMsg("Processing EFI file %s\n", FList->FileName);
}
Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevIdList[0], &Size);
} else if ((FList->FileFlags & FILE_FLAG_BINARY) !=0 ) {
if (mOptions.Verbose) {
VerboseMsg("Processing binary file %s\n", FList->FileName);
}
Status = ProcessBinFile (FptrOut, FList, &Size);
} else {
Error (NULL, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList->FileName);
Status = STATUS_ERROR;
}
if (mOptions.Verbose) {
VerboseMsg(" Output size = 0x%X\n", (unsigned) Size);
}
if (Status != STATUS_SUCCESS) {
break;
}
TotalSize += Size;
}
//
// Check total size
//
if (TotalSize > MAX_OPTION_ROM_SIZE) {
Error (NULL, 0, 2000, "Invalid parameter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);
Status = STATUS_ERROR;
}
BailOut:
if (Status == STATUS_SUCCESS) {
//
// Clean up our file list
//
while (mOptions.FileList != NULL) {
FList = mOptions.FileList->Next;
free (mOptions.FileList);
mOptions.FileList = FList;
}
//
// Clean up device ID list
//
if (mOptions.DevIdList != NULL) {
free (mOptions.DevIdList);
}
}
if (FptrOut != NULL) {
fclose (FptrOut);
}
if (mOptions.Verbose) {
VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());
}
return GetUtilityStatus ();
}
static
int
ProcessBinFile (
FILE *OutFptr,
FILE_LIST *InFile,
UINT32 *Size
)
/*++
Routine Description:
Process a binary input file.
Arguments:
OutFptr - file pointer to output binary ROM image file we're creating
InFile - structure contains information on the binary file to process
Size - pointer to where to return the size added to the output file
Returns:
0 - successful
--*/
{
FILE *InFptr;
UINT32 TotalSize;
UINT32 FileSize;
UINT8 *Buffer;
UINT32 Status;
PCI_EXPANSION_ROM_HEADER *RomHdr;
PCI_DATA_STRUCTURE *PciDs23;
PCI_3_0_DATA_STRUCTURE *PciDs30;
UINT32 Index;
UINT8 ByteCheckSum;
UINT16 CodeType;
PciDs23 = NULL;
PciDs30 = NULL;
Status = STATUS_SUCCESS;
//
// Try to open the input file
//
if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {
Error (NULL, 0, 0001, "Error opening file", "%s", InFile->FileName);
return STATUS_ERROR;
}
//
// Seek to the end of the input file and get the file size. Then allocate
// a buffer to read it in to.
//
fseek (InFptr, 0, SEEK_END);
FileSize = ftell (InFptr);
if (mOptions.Verbose) {
VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);
}
fseek (InFptr, 0, SEEK_SET);
Buffer = (UINT8 *) malloc (FileSize);
if (Buffer == NULL) {
Error (NULL, 0, 4003, "Resource", "memory cannot be allocated!");
Status = STATUS_ERROR;
goto BailOut;
}
if (fread (Buffer, FileSize, 1, InFptr) != 1) {
Error (NULL, 0, 2000, "Invalid", "Failed to read all bytes from input file.");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Total size must be an even multiple of 512 bytes, and can't exceed
// the option ROM image size.
//
TotalSize = FileSize;
if (TotalSize & 0x1FF) {
TotalSize = (TotalSize + 0x200) &~0x1ff;
}
if (TotalSize > MAX_OPTION_ROM_SIZE) {
Error (NULL, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Return the size to the caller so they can keep track of the running total.
//
*Size = TotalSize;
//
// Crude check to make sure it's a legitimate ROM image
//
RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;
if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
Error (NULL, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Make sure the pointer to the PCI data structure is within the size of the image.
// Then check it for valid signature.
//
if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {
Error (NULL, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Check the header is conform to PCI2.3 or PCI3.0
//
if (mOptions.Pci23 == 1) {
PciDs23 = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);
if (PciDs23->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
Status = STATUS_ERROR;
goto BailOut;
}
} else {
//
// Default setting is PCI3.0 header
//
PciDs30 = (PCI_3_0_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);
if (PciDs30->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
Status = STATUS_ERROR;
goto BailOut;
}
}
//
// ReSet Option Rom size
//
if (mOptions.Pci23 == 1) {
PciDs23->ImageLength = (UINT16) (TotalSize / 512);
CodeType = PciDs23->CodeType;
} else {
PciDs30->ImageLength = (UINT16) (TotalSize / 512);
CodeType = PciDs30->CodeType;
}
//
// If this is the last image, then set the LAST bit unless requested not
// to via the command-line -n argument. Otherwise, make sure you clear it.
//
if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
if (mOptions.Pci23 == 1) {
PciDs23->Indicator = INDICATOR_LAST;
} else {
PciDs30->Indicator = INDICATOR_LAST;
}
} else {
if (mOptions.Pci23 == 1) {
PciDs23->Indicator = 0;
} else {
PciDs30->Indicator = 0;
}
}
if (CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
ByteCheckSum = 0;
for (Index = 0; Index < FileSize - 1; Index++) {
ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);
}
Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);
if (mOptions.Verbose) {
VerboseMsg(" Checksum = %02x\n\n", Buffer[FileSize - 1]);
}
}
//
// Now copy the input file contents out to the output file
//
if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
Error (NULL, 0, 0005, "Failed to write all file bytes to output file.", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
TotalSize -= FileSize;
//
// Pad the rest of the image to make it a multiple of 512 bytes
//
while (TotalSize > 0) {
putc (~0, OutFptr);
TotalSize--;
}
BailOut:
if (InFptr != NULL) {
fclose (InFptr);
}
if (Buffer != NULL) {
free (Buffer);
}
//
// Print the file name if errors occurred
//
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0003, "Error", "Error parsing file: %s", InFile->FileName);
}
return Status;
}
static
int
ProcessEfiFile (
FILE *OutFptr,
FILE_LIST *InFile,
UINT16 VendId,
UINT16 DevId,
UINT32 *Size
)
/*++
Routine Description:
Process a PE32 EFI file.
Arguments:
OutFptr - file pointer to output binary ROM image file we're creating
InFile - structure contains information on the PE32 file to process
VendId - vendor ID as required in the option ROM header
DevId - device ID as required in the option ROM header
Size - pointer to where to return the size added to the output file
Returns:
0 - successful
--*/
{
UINT32 Status;
FILE *InFptr;
EFI_PCI_EXPANSION_ROM_HEADER RomHdr;
PCI_DATA_STRUCTURE PciDs23;
PCI_3_0_DATA_STRUCTURE PciDs30;
UINT32 FileSize;
UINT32 CompressedFileSize;
UINT8 *Buffer;
UINT8 *CompressedBuffer;
UINT8 *TempBufferPtr;
UINT32 TotalSize;
UINT32 HeaderSize;
UINT16 MachineType;
UINT16 SubSystem;
UINT32 HeaderPadBytes;
UINT32 PadBytesBeforeImage;
UINT32 PadBytesAfterImage;
UINT32 DevIdListSize;
//
// Try to open the input file
//
if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {
Error (NULL, 0, 0001, "Open file error", "Error opening file: %s", InFile->FileName);
return STATUS_ERROR;
}
//
// Initialize our buffer pointers to null.
//
Buffer = NULL;
CompressedBuffer = NULL;
//
// Double-check the file to make sure it's what we expect it to be
//
Status = CheckPE32File (InFptr, &MachineType, &SubSystem);
if (Status != STATUS_SUCCESS) {
goto BailOut;
}
//
// Seek to the end of the input file and get the file size
//
fseek (InFptr, 0, SEEK_END);
FileSize = ftell (InFptr);
//
// Get the size of the headers we're going to put in front of the image. The
// EFI header must be aligned on a 4-byte boundary, so pad accordingly.
//
if (sizeof (RomHdr) & 0x03) {
HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);
} else {
HeaderPadBytes = 0;
}
//
// For Pci3.0 to use the different data structure.
//
if (mOptions.Pci23 == 1) {
HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
} else {
if (mOptions.DevIdCount > 1) {
//
// Write device ID list when more than one device ID is specified.
// Leave space for list plus terminator.
//
DevIdListSize = (mOptions.DevIdCount + 1) * sizeof (UINT16);
} else {
DevIdListSize = 0;
}
HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + DevIdListSize + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
}
if (mOptions.Verbose) {
VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);
}
//
// Allocate memory for the entire file (in case we have to compress), then
// seek back to the beginning of the file and read it into our buffer.
//
Buffer = (UINT8 *) malloc (FileSize);
if (Buffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
Status = STATUS_ERROR;
goto BailOut;
}
fseek (InFptr, 0, SEEK_SET);
if (fread (Buffer, FileSize, 1, InFptr) != 1) {
Error (NULL, 0, 0004, "Error reading file", "File %s", InFile->FileName);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Now determine the size of the final output file. It's either the header size
// plus the file's size, or the header size plus the compressed file size.
//
if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {
//
// Allocate a buffer into which we can compress the image, compress it,
// and use that size as the new size.
//
CompressedBuffer = (UINT8 *) malloc (FileSize);
if (CompressedBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
Status = STATUS_ERROR;
goto BailOut;
}
CompressedFileSize = FileSize;
Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0007, "Error compressing file!", NULL);
goto BailOut;
}
//
// Now compute the size, then swap buffer pointers.
//
if (mOptions.Verbose) {
VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize);
}
TotalSize = CompressedFileSize + HeaderSize;
FileSize = CompressedFileSize;
TempBufferPtr = Buffer;
Buffer = CompressedBuffer;
CompressedBuffer = TempBufferPtr;
} else {
TotalSize = FileSize + HeaderSize;
}
//
// Total size must be an even multiple of 512 bytes
//
if (TotalSize & 0x1FF) {
TotalSize = (TotalSize + 0x200) &~0x1ff;
}
//
// Workaround:
// If compressed, put the pad bytes after the image,
// else put the pad bytes before the image.
//
if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {
PadBytesBeforeImage = 0;
PadBytesAfterImage = TotalSize - (FileSize + HeaderSize);
} else {
PadBytesBeforeImage = TotalSize - (FileSize + HeaderSize);
PadBytesAfterImage = 0;
}
//
// Check size
//
if (TotalSize > MAX_OPTION_ROM_SIZE) {
Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Return the size to the caller so they can keep track of the running total.
//
*Size = TotalSize;
//
// Now fill in the ROM header. These values come from chapter 18 of the
// EFI 1.02 specification.
//
memset (&RomHdr, 0, sizeof (RomHdr));
RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
RomHdr.InitializationSize = (UINT16) (TotalSize / 512);
RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
RomHdr.EfiSubsystem = SubSystem;
RomHdr.EfiMachineType = MachineType;
RomHdr.EfiImageHeaderOffset = (UINT16) (HeaderSize + PadBytesBeforeImage);
RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);
//
// Set image as compressed or not
//
if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;
}
//
// Fill in the PCI data structure
//
if (mOptions.Pci23 == 1) {
memset (&PciDs23, 0, sizeof (PCI_DATA_STRUCTURE));
} else {
memset (&PciDs30, 0, sizeof (PCI_3_0_DATA_STRUCTURE));
}
if (mOptions.Pci23 == 1) {
PciDs23.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
PciDs23.VendorId = VendId;
PciDs23.DeviceId = DevId;
PciDs23.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);
PciDs23.Revision = 0;
//
// Class code and code revision from the command line (optional)
//
PciDs23.ClassCode[0] = (UINT8) InFile->ClassCode;
PciDs23.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);
PciDs23.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);
PciDs23.ImageLength = RomHdr.InitializationSize;
PciDs23.CodeRevision = InFile->CodeRevision;
PciDs23.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
} else {
PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
PciDs30.VendorId = VendId;
PciDs30.DeviceId = DevId;
if (mOptions.DevIdCount > 1) {
//
// Place device list immediately after PCI structure
//
PciDs30.DeviceListOffset = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);
} else {
PciDs30.DeviceListOffset = 0;
}
PciDs30.Length = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);
PciDs30.Revision = 0x3;
//
// Class code and code revision from the command line (optional)
//
PciDs30.ClassCode[0] = (UINT8) InFile->ClassCode;
PciDs30.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);
PciDs30.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);
PciDs30.ImageLength = RomHdr.InitializationSize;
PciDs30.CodeRevision = InFile->CodeRevision;
PciDs30.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
PciDs30.MaxRuntimeImageLength = 0; // to be fixed
PciDs30.ConfigUtilityCodeHeaderOffset = 0; // to be fixed
PciDs30.DMTFCLPEntryPointOffset = 0; // to be fixed
}
//
// If this is the last image, then set the LAST bit unless requested not
// to via the command-line -n argument.
//
if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
if (mOptions.Pci23 == 1) {
PciDs23.Indicator = INDICATOR_LAST;
} else {
PciDs30.Indicator = INDICATOR_LAST;}
} else {
if (mOptions.Pci23 == 1) {
PciDs23.Indicator = 0;
} else {
PciDs30.Indicator = 0;
}
}
//
// Write the ROM header to the output file
//
if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {
Error (NULL, 0, 0002, "Failed to write ROM header to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Write pad bytes to align the PciDs
//
while (HeaderPadBytes > 0) {
if (putc (0, OutFptr) == EOF) {
Error (NULL, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
HeaderPadBytes--;
}
//
// Write the PCI data structure header to the output file
//
if (mOptions.Pci23 == 1) {
if (fwrite (&PciDs23, sizeof (PciDs23), 1, OutFptr) != 1) {
Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
} else {
if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {
Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
}
//
// Write the Device ID list to the output file
//
if (mOptions.DevIdCount > 1) {
if (fwrite (mOptions.DevIdList, sizeof (UINT16), mOptions.DevIdCount, OutFptr) != mOptions.DevIdCount) {
Error (NULL, 0, 0002, "Failed to write PCI device list to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Write two-byte terminating 0 at the end of the device list
//
if (putc (0, OutFptr) == EOF || putc (0, OutFptr) == EOF) {
Error (NULL, 0, 0002, "Failed to write PCI device list to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
}
//
// Pad head to make it a multiple of 512 bytes
//
while (PadBytesBeforeImage > 0) {
if (putc (~0, OutFptr) == EOF) {
Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
PadBytesBeforeImage--;
}
//
// Now dump the input file's contents to the output file
//
if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
Error (NULL, 0, 0002, "Failed to write all file bytes to output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Pad the rest of the image to make it a multiple of 512 bytes
//
while (PadBytesAfterImage > 0) {
if (putc (~0, OutFptr) == EOF) {
Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);
Status = STATUS_ERROR;
goto BailOut;
}
PadBytesAfterImage--;
}
BailOut:
if (InFptr != NULL) {
fclose (InFptr);
}
//
// Free up our buffers
//
if (Buffer != NULL) {
free (Buffer);
}
if (CompressedBuffer != NULL) {
free (CompressedBuffer);
}
//
// Print the file name if errors occurred
//
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0003, "Error parsing", "Error parsing file: %s", InFile->FileName);
}
return Status;
}
static
int
CheckPE32File (
FILE *Fptr,
UINT16 *MachineType,
UINT16 *SubSystem
)
/*++
Routine Description:
Given a file pointer to a supposed PE32 image file, verify that it is indeed a
PE32 image file, and then return the machine type in the supplied pointer.
Arguments:
Fptr File pointer to the already-opened PE32 file
MachineType Location to stuff the machine type of the PE32 file. This is needed
because the image may be Itanium-based, IA32, or EBC.
Returns:
0 success
non-zero otherwise
--*/
{
EFI_IMAGE_DOS_HEADER DosHeader;
EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
//
// Position to the start of the file
//
fseek (Fptr, 0, SEEK_SET);
//
// Read the DOS header
//
if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {
Error (NULL, 0, 0004, "Failed to read the DOS stub from the input file!", NULL);
return STATUS_ERROR;
}
//
// Check the magic number (0x5A4D)
//
if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");
return STATUS_ERROR;
}
//
// Position into the file and check the PE signature
//
fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);
//
// Read PE headers
//
if (fread (&PeHdr, sizeof (PeHdr), 1, Fptr) != 1) {
Error (NULL, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL);
return STATUS_ERROR;
}
//
// Check the PE signature in the header "PE\0\0"
//
if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");
return STATUS_ERROR;
}
memcpy ((char *) MachineType, &PeHdr.Pe32.FileHeader.Machine, 2);
if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
*SubSystem = PeHdr.Pe32.OptionalHeader.Subsystem;
} else if (PeHdr.Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
*SubSystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
} else {
Error (NULL, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");
return STATUS_ERROR;
}
if (mOptions.Verbose) {
VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem);
}
//
// File was successfully identified as a PE32
//
return STATUS_SUCCESS;
}
static
int
ParseCommandLine (
int Argc,
char *Argv[],
OPTIONS *Options
)
/*++
Routine Description:
Given the Argc/Argv program arguments, and a pointer to an options structure,
parse the command-line options and check their validity.
Arguments:
Argc - standard C main() argument count
Argv[] - standard C main() argument list
Options - pointer to a structure to store the options in
Returns:
STATUS_SUCCESS success
non-zero otherwise
--*/
{
FILE_LIST *FileList;
FILE_LIST *PrevFileList;
UINT32 FileFlags;
UINT32 ClassCode;
UINT32 CodeRevision;
EFI_STATUS Status;
INTN ReturnStatus;
BOOLEAN EfiRomFlag;
UINT64 TempValue;
char *OptionName;
UINT16 *DevIdList;
ReturnStatus = 0;
FileFlags = 0;
EfiRomFlag = FALSE;
//
// Clear out the options
//
memset ((char *) Options, 0, sizeof (OPTIONS));
//
// To avoid compile warnings
//
FileList = PrevFileList = NULL;
Options->DevIdList = NULL;
Options->DevIdCount = 0;
ClassCode = 0;
CodeRevision = 0;
//
// Skip over the program name
//
Argc--;
Argv++;
//
// If no arguments, assume they want usage info
//
if (Argc == 0) {
Usage ();
return STATUS_ERROR;
}
if ((stricmp(Argv[0], "-h") == 0) || (stricmp(Argv[0], "--help") == 0)) {
Usage();
return STATUS_ERROR;
}
if ((stricmp(Argv[0], "--version") == 0)) {
Version();
return STATUS_ERROR;
}
//
// Process until no more arguments
//
while (Argc > 0) {
if (Argv[0][0] == '-') {
//
// Vendor ID specified with -f
//
if (stricmp (Argv[0], "-f") == 0) {
//
// Make sure there's another parameter
//
Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
ReturnStatus = 1;
goto Done;
}
if (TempValue >= 0x10000) {
Error (NULL, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv[1]);
ReturnStatus = 1;
goto Done;
}
Options->VendId = (UINT16) TempValue;
Options->VendIdValid = 1;
Argv++;
Argc--;
} else if (stricmp (Argv[0], "-i") == 0) {
OptionName = Argv[0];
//
// Device IDs specified with -i
// Make sure there's at least one more parameter
//
if (Argc == 1) {
Error (NULL, 0, 2000, "Invalid parameter", "Missing Device Id with %s option!", OptionName);
ReturnStatus = 1;
goto Done;
}
//
// Process until another dash-argument parameter or the end of the list
//
while (Argc > 1 && Argv[1][0] != '-') {
Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 2000, "Invalid option value", "%s = %s", OptionName, Argv[1]);
ReturnStatus = 1;
goto Done;
}
//
// Don't allow device IDs greater than 16 bits
// Don't allow 0, since it is used as a list terminator
//
if (TempValue >= 0x10000 || TempValue == 0) {
Error (NULL, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv[1]);
ReturnStatus = 1;
goto Done;
}
DevIdList = (UINT16*) realloc (Options->DevIdList, (Options->DevIdCount + 1) * sizeof (UINT16));
if (DevIdList == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);
ReturnStatus = 1;
goto Done;
}
Options->DevIdList = DevIdList;
Options->DevIdList[Options->DevIdCount++] = (UINT16) TempValue;
Argv++;
Argc--;
}
} else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {
//
// Output filename specified with -o
// Make sure there's another parameter
//
if (Argv[1] == NULL || Argv[1][0] == '-') {
Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv[0]);
ReturnStatus = STATUS_ERROR;
goto Done;
}
if (strlen (Argv[1]) > MAX_PATH - 1) {
Error (NULL, 0, 2000, "Invalid parameter", "Output file name %s is too long!", Argv[1]);
ReturnStatus = STATUS_ERROR;
goto Done;
}
strncpy (Options->OutFileName, Argv[1], MAX_PATH - 1);
Options->OutFileName[MAX_PATH - 1] = 0;
Argv++;
Argc--;
} else if ((stricmp (Argv[0], "-h") == 0) || (stricmp (Argv[0], "--help") == 0)) {
//
// Help option
//
Usage ();
ReturnStatus = STATUS_ERROR;
goto Done;
} else if (stricmp (Argv[0], "-b") == 0) {
//
// Specify binary files with -b
//
FileFlags = FILE_FLAG_BINARY;
} else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) {
//
// Specify EFI files with -e. Specify EFI-compressed with -c.
//
FileFlags = FILE_FLAG_EFI;
if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {
FileFlags |= FILE_FLAG_COMPRESS;
}
//
// Specify not to set the LAST bit in the last file with -n
//
} else if (stricmp (Argv[0], "-n") == 0) {
Options->NoLast = 1;
} else if (((stricmp (Argv[0], "-v") == 0)) || ((stricmp (Argv[0], "--verbose") == 0))) {
//
// -v for verbose
//
Options->Verbose = 1;
} else if (stricmp (Argv[0], "--debug") == 0) {
Status = AsciiStringToUint64(Argv[1], FALSE, &DebugLevel);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
ReturnStatus = 1;
goto Done;
}
if (DebugLevel > 9) {
Error (NULL, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %llu", DebugLevel);
ReturnStatus = 1;
goto Done;
}
if (DebugLevel>=5 && DebugLevel<=9) {
Options->Debug = TRUE;
} else {
Options->Debug = FALSE;
}
Argv++;
Argc--;
} else if ((stricmp (Argv[0], "--quiet") == 0) || (stricmp (Argv[0], "-q") == 0)) {
Options->Quiet = TRUE;
} else if ((stricmp (Argv[0], "--dump") == 0) || (stricmp (Argv[0], "-d") == 0)) {
//
// -dump for dumping a ROM image. In this case, say that the device id
// and vendor id are valid so we don't have to specify bogus ones on the
// command line.
//
Options->DumpOption = 1;
Options->VendIdValid = 1;
Options->DevIdCount = 1;
FileFlags = FILE_FLAG_BINARY;
} else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {
//
// Class code value for the next file in the list.
// Make sure there's another parameter
//
Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
ReturnStatus = 1;
goto Done;
}
ClassCode = (UINT32) TempValue;
if (ClassCode & 0xFF000000) {
Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv[1]);
ReturnStatus = STATUS_ERROR;
goto Done;
}
if (FileList != NULL && FileList->ClassCode == 0) {
FileList->ClassCode = ClassCode;
}
Argv++;
Argc--;
} else if ((stricmp (Argv[0], "-r") == 0) || (stricmp (Argv[0], "--Revision") == 0)) {
//
// Code revision in the PCI data structure. The value is for the next
// file in the list.
// Make sure there's another parameter
//
Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
ReturnStatus = 1;
goto Done;
}
CodeRevision = (UINT32) TempValue;
if (CodeRevision & 0xFFFF0000) {
Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv[1]);
ReturnStatus = STATUS_ERROR;
goto Done;
}
if (FileList != NULL && FileList->CodeRevision == 0) {
FileList->CodeRevision = (UINT16) CodeRevision;
}
Argv++;
Argc--;
} else if ((stricmp (Argv[0], "-p") == 0) || (stricmp (Argv[0], "--pci23") == 0)) {
//
// Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
//
mOptions.Pci23 = 1;
} else {
Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);
ReturnStatus = STATUS_ERROR;
goto Done;
}
} else {
//
// Not a slash-option argument. Must be a file name. Make sure they've specified
// -e or -b already.
//
if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {
Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv[0]);
ReturnStatus = STATUS_ERROR;
goto Done;
}
//
// Check Efi Option RomImage
//
if ((FileFlags & FILE_FLAG_EFI) == FILE_FLAG_EFI) {
EfiRomFlag = TRUE;
}
//
// Create a new file structure
//
FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));
if (FileList == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);
ReturnStatus = STATUS_ERROR;
goto Done;
}
//
// set flag and class code for this image.
//
memset ((char *) FileList, 0, sizeof (FILE_LIST));
FileList->FileName = Argv[0];
FileList->FileFlags = FileFlags;
FileList->ClassCode = ClassCode;
FileList->CodeRevision = (UINT16) CodeRevision;
ClassCode = 0;
CodeRevision = 0;
if (Options->FileList == NULL) {
Options->FileList = FileList;
} else {
if (PrevFileList == NULL) {
PrevFileList = FileList;
} else {
PrevFileList->Next = FileList;
}
}
PrevFileList = FileList;
}
//
// Next argument
//
Argv++;
Argc--;
}
//
// Must have specified some files
//
if (Options->FileList == NULL) {
Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name!");
//
// No memory allocation, return directly.
//
return STATUS_ERROR;
}
//
// For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.
//
if (EfiRomFlag) {
if (!Options->VendIdValid) {
Error (NULL, 0, 2000, "Missing Vendor ID in command line", NULL);
ReturnStatus = STATUS_ERROR;
goto Done;
}
if (!Options->DevIdCount) {
Error (NULL, 0, 2000, "Missing Device ID in command line", NULL);
ReturnStatus = STATUS_ERROR;
goto Done;
}
}
if (Options->DevIdCount > 1 && Options->Pci23) {
Error (NULL, 0, 2000, "Invalid parameter", "PCI 3.0 is required when specifying multiple Device IDs");
ReturnStatus = STATUS_ERROR;
goto Done;
}
Done:
if (ReturnStatus != 0) {
while (Options->FileList != NULL) {
FileList = Options->FileList->Next;
free (Options->FileList);
Options->FileList = FileList;
}
}
return ReturnStatus;
}
static
void
Version (
VOID
)
/*++
Routine Description:
Print version information for this utility.
Arguments:
None.
Returns:
Nothing.
--*/
{
fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
}
static
void
Usage (
VOID
)
/*++
Routine Description:
Print usage information for this utility.
Arguments:
None.
Returns:
Nothing.
--*/
{
//
// Summary usage
//
fprintf (stdout, "Usage: %s -f VendorId -i DeviceId [options] [file name] \n\n", UTILITY_NAME);
//
// Copyright declaration
//
fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
//
// Details Option
//
fprintf (stdout, "Options:\n");
fprintf (stdout, " -o FileName, --output FileName\n\
File will be created to store the output content.\n");
fprintf (stdout, " -e EfiFileName\n\
EFI PE32 image files.\n");
fprintf (stdout, " -ec EfiFileName\n\
EFI PE32 image files and will be compressed.\n");
fprintf (stdout, " -b BinFileName\n\
Legacy binary files.\n");
fprintf (stdout, " -l ClassCode\n\
Hex ClassCode in the PCI data structure header.\n");
fprintf (stdout, " -r Rev Hex Revision in the PCI data structure header.\n");
fprintf (stdout, " -n Not to automatically set the LAST bit in the last file.\n");
fprintf (stdout, " -f VendorId\n\
Hex PCI Vendor ID for the device OpROM, must be specified\n");
fprintf (stdout, " -i DeviceId\n\
One or more hex PCI Device IDs for the device OpROM, must be specified\n");
fprintf (stdout, " -p, --pci23\n\
Default layout meets PCI 3.0 specifications\n\
specifying this flag will for a PCI 2.3 layout.\n");
fprintf (stdout, " -d, --dump\n\
Dump the headers of an existing option ROM image.\n");
fprintf (stdout, " -v, --verbose\n\
Turn on verbose output with informational messages.\n");
fprintf (stdout, " --version Show program's version number and exit.\n");
fprintf (stdout, " -h, --help\n\
Show this help message and exit.\n");
fprintf (stdout, " -q, --quiet\n\
Disable all messages except FATAL ERRORS.\n");
fprintf (stdout, " --debug [#,0-9]\n\
Enable debug messages at level #.\n");
}
static
void
DumpImage (
FILE_LIST *InFile
)
/*++
Routine Description:
Dump the headers of an existing option ROM image
Arguments:
InFile - the file name of an existing option ROM image
Returns:
none
--*/
{
PCI_EXPANSION_ROM_HEADER PciRomHdr;
FILE *InFptr;
UINT32 ImageStart;
UINT32 ImageCount;
EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr;
PCI_DATA_STRUCTURE PciDs23;
PCI_3_0_DATA_STRUCTURE PciDs30;
UINT16 DevId;
//
// Open the input file
//
if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {
Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
return ;
}
//
// Go through the image and dump the header stuff for each
//
ImageCount = 0;
for (;;) {
//
// Save our position in the file, since offsets in the headers
// are relative to the particular image.
//
ImageStart = ftell (InFptr);
ImageCount++;
//
// Read the option ROM header. Have to assume a raw binary image for now.
//
if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {
Error (NULL, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");
goto BailOut;
}
//
// Dump the contents of the header
//
fprintf (stdout, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount, (unsigned) ImageStart);
fprintf (stdout, " ROM header contents\n");
fprintf (stdout, " Signature 0x%04X\n", PciRomHdr.Signature);
fprintf (stdout, " PCIR offset 0x%04X\n", PciRomHdr.PcirOffset);
//
// Find PCI data structure
//
if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {
Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");
goto BailOut;
}
//
// Read and dump the PCI data structure
//
memset (&PciDs23, 0, sizeof (PciDs23));
memset (&PciDs30, 0, sizeof (PciDs30));
if (mOptions.Pci23 == 1) {
if (fread (&PciDs23, sizeof (PciDs23), 1, InFptr) != 1) {
Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);
goto BailOut;
}
} else {
if (fread (&PciDs30, sizeof (PciDs30), 1, InFptr) != 1) {
Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);
goto BailOut;
}
}
if (mOptions.Verbose) {
VerboseMsg("Read PCI data structure from file %s", InFile->FileName);
}
//fprintf (stdout, " PCI Data Structure\n");
if (mOptions.Pci23 == 1) {
fprintf (
stdout,
" Signature %c%c%c%c\n",
(char) PciDs23.Signature,
(char) (PciDs23.Signature >> 8),
(char) (PciDs23.Signature >> 16),
(char) (PciDs23.Signature >> 24)
);
fprintf (stdout, " Vendor ID 0x%04X\n", PciDs23.VendorId);
fprintf (stdout, " Device ID 0x%04X\n", PciDs23.DeviceId);
fprintf (stdout, " Length 0x%04X\n", PciDs23.Length);
fprintf (stdout, " Revision 0x%04X\n", PciDs23.Revision);
fprintf (
stdout,
" Class Code 0x%06X\n",
(unsigned) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))
);
fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs23.ImageLength * 512);
fprintf (stdout, " Code revision: 0x%04X\n", PciDs23.CodeRevision);
fprintf (stdout, " Indicator 0x%02X", PciDs23.Indicator);
} else {
fprintf (
stdout,
" Signature %c%c%c%c\n",
(char) PciDs30.Signature,
(char) (PciDs30.Signature >> 8),
(char) (PciDs30.Signature >> 16),
(char) (PciDs30.Signature >> 24)
);
fprintf (stdout, " Vendor ID 0x%04X\n", PciDs30.VendorId);
fprintf (stdout, " Device ID 0x%04X\n", PciDs30.DeviceId);
fprintf (stdout, " Length 0x%04X\n", PciDs30.Length);
fprintf (stdout, " Revision 0x%04X\n", PciDs30.Revision);
fprintf (stdout, " DeviceListOffset 0x%02X\n", PciDs30.DeviceListOffset);
if (PciDs30.DeviceListOffset) {
//
// Print device ID list
//
fprintf (stdout, " Device list contents\n");
if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset + PciDs30.DeviceListOffset, SEEK_SET)) {
Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI device ID list!");
goto BailOut;
}
//
// Loop until terminating 0
//
do {
if (fread (&DevId, sizeof (DevId), 1, InFptr) != 1) {
Error (NULL, 0, 3001, "Not supported", "Failed to read PCI device ID list from file %s!", InFile->FileName);
goto BailOut;
}
if (DevId) {
fprintf (stdout, " 0x%04X\n", DevId);
}
} while (DevId);
}
fprintf (
stdout,
" Class Code 0x%06X\n",
(unsigned) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))
);
fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs30.ImageLength * 512);
fprintf (stdout, " Code revision: 0x%04X\n", PciDs30.CodeRevision);
fprintf (stdout, " MaxRuntimeImageLength 0x%02X\n", PciDs30.MaxRuntimeImageLength);
fprintf (stdout, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30.ConfigUtilityCodeHeaderOffset);
fprintf (stdout, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset);
fprintf (stdout, " Indicator 0x%02X", PciDs30.Indicator);
}
//
// Print the indicator, used to flag the last image
//
if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
fprintf (stdout, " (last image)\n");
} else {
fprintf (stdout, "\n");
}
//
// Print the code type. If EFI code, then we can provide more info.
//
if (mOptions.Pci23 == 1) {
fprintf (stdout, " Code type 0x%02X", PciDs23.CodeType);
} else {
fprintf (stdout, " Code type 0x%02X", PciDs30.CodeType);
}
if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
fprintf (stdout, " (EFI image)\n");
//
// Re-read the header as an EFI ROM header, then dump more info
//
fprintf (stdout, " EFI ROM header contents\n");
if (fseek (InFptr, ImageStart, SEEK_SET)) {
Error (NULL, 0, 5001, "Failed to re-seek to ROM header structure!", NULL);
goto BailOut;
}
if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {
Error (NULL, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL);
goto BailOut;
}
//
// Now dump more info
//
fprintf (stdout, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr.EfiSignature);
fprintf (
stdout,
" Compression Type 0x%04X ",
EfiRomHdr.CompressionType
);
if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
fprintf (stdout, "(compressed)\n");
} else {
fprintf (stdout, "(not compressed)\n");
}
fprintf (
stdout,
" Machine type 0x%04X (%s)\n",
EfiRomHdr.EfiMachineType,
GetMachineTypeStr (EfiRomHdr.EfiMachineType)
);
fprintf (
stdout,
" Subsystem 0x%04X (%s)\n",
EfiRomHdr.EfiSubsystem,
GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)
);
fprintf (
stdout,
" EFI image offset 0x%04X (@0x%X)\n",
EfiRomHdr.EfiImageHeaderOffset,
EfiRomHdr.EfiImageHeaderOffset + (unsigned) ImageStart
);
} else {
//
// Not an EFI image
//
fprintf (stdout, "\n");
}
//
// If code type is EFI image, then dump it as well?
//
// if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
// }
//
// If last image, then we're done
//
if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
goto BailOut;
}
//
// Seek to the start of the next image
//
if (mOptions.Pci23 == 1) {
if (fseek (InFptr, ImageStart + (PciDs23.ImageLength * 512), SEEK_SET)) {
Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");
goto BailOut;
}
} else {
if (fseek (InFptr, ImageStart + (PciDs30.ImageLength * 512), SEEK_SET)) {
Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");
goto BailOut;
}
}
}
BailOut:
fclose (InFptr);
}
char *
GetMachineTypeStr (
UINT16 MachineType
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
MachineType - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
int Index;
for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {
if (mMachineTypes[Index].Value == MachineType) {
return mMachineTypes[Index].Name;
}
}
return "unknown";
}
static
char *
GetSubsystemTypeStr (
UINT16 SubsystemType
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SubsystemType - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
int Index;
for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {
if (mSubsystemTypes[Index].Value == SubsystemType) {
return mSubsystemTypes[Index].Name;
}
}
return "unknown";
}