diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/EfiRom/EfiRom.c | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/EfiRom/EfiRom.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/EfiRom/EfiRom.c | 1712 |
1 files changed, 1712 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/EfiRom/EfiRom.c b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/EfiRom/EfiRom.c new file mode 100644 index 00000000..61e47a6a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/EfiRom/EfiRom.c @@ -0,0 +1,1712 @@ +/** @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.<BR> +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 %d", Argv[1]); + 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<s>] \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"; +} |