From 3eb9473ea9a949badfe06ae61d2d3fcfa53651c7 Mon Sep 17 00:00:00 2001 From: qwang12 Date: Thu, 28 Jun 2007 07:00:39 +0000 Subject: Add in the 1st version of ECP. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2832 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Sample/Tools/Source/EfiRom/EfiRom.c | 1545 ++++++++++++++++++++ .../Sample/Tools/Source/EfiRom/Makefile | 85 ++ 2 files changed, 1630 insertions(+) create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/EfiRom.c create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/Makefile (limited to 'EdkCompatibilityPkg/Sample/Tools/Source/EfiRom') diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/EfiRom.c b/EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/EfiRom.c new file mode 100644 index 0000000000..06a8581669 --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/EfiRom.c @@ -0,0 +1,1545 @@ +/*++ + +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + EfiRom.c + +Abstract: + + Utility program to create an EFI option ROM image from binary and + EFI PE32 files. + + +--*/ + +#include +#include +#include + +// +// Includes for EFI 1.1 build +// +// #include "Tiano.h" // required defines for Compress.h +// #include "EfiImage.h" // for PE32 structure definitions +// #include "Compress.h" // for compression function +// Includes for Tiano build +// +#include "TianoCommon.h" +#include "EfiImage.h" // for PE32 structure definitions +#include "Compress.h" + +// +// END include differences +// +#include "Pci22.h" // for option ROM header structures +// +// Version of this utility +// +#define UTILITY_VERSION "v2.5" + +// +// Define some status return values +// +#define STATUS_SUCCESS 0 +#define STATUS_WARNING 1 +#define STATUS_ERROR 2 + +// +// Define the max length of a filename +// +#define MAX_PATH 200 + +#define DEFAULT_OUTPUT_EXTENSION ".rom" + +// +// Max size for an option ROM image +// +#define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB +// +// Values for the indicator field in the PCI data structure +// +#define INDICATOR_LAST 0x80 // last file in series of files +// +// Masks for the FILE_LIST.FileFlags field +// +#define FILE_FLAG_BINARY 0x01 +#define FILE_FLAG_EFI 0x02 +#define FILE_FLAG_COMPRESS 0x04 + +// +// Use this linked list structure to keep track of all the filenames +// specified on the command line. +// +typedef struct _FILE_LIST { + struct _FILE_LIST *Next; + INT8 *FileName; + UINT32 FileFlags; + UINT32 ClassCode; + UINT16 CodeRevision; +} FILE_LIST; + +// +// Use this to track our command-line options +// +typedef struct { + INT8 OutFileName[MAX_PATH]; + INT8 NoLast; + INT8 Verbose; + INT8 DumpOption; + UINT8 DevIdValid; + UINT8 VendIdValid; + UINT16 VendId; + UINT16 DevId; + FILE_LIST *FileList; +} OPTIONS; + +// +// Make a global structure to keep track of command-line options +// +static OPTIONS mOptions; + +// +// Use these to convert from machine type value to a named type +// +typedef struct { + UINT16 Value; + char *Name; +} STRING_LOOKUP; + +static STRING_LOOKUP mMachineTypes[] = { + EFI_IMAGE_MACHINE_IA32, + "IA32", + EFI_IMAGE_MACHINE_IA64, + "IA64", + EFI_IMAGE_MACHINE_EBC, + "EBC", + 0, + NULL +}; + +static STRING_LOOKUP mSubsystemTypes[] = { + EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, + "EFI application", + EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, + "EFI boot service driver", + EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, + "EFI runtime driver", + 0, + NULL +}; +// +// Function prototypes +// +static +void +Usage ( + VOID + ); + +static +int +ParseCommandLine ( + int Argc, + char *Argv[], + OPTIONS *Options + ); + +static +int +CheckPE32File ( + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ); + +static +int +ProcessEfiFile ( + FILE *OutFptr, + FILE_LIST *InFile, + UINT16 VendId, + UINT16 DevId, + UINT32 *Size + ); + +static +int +ProcessBinFile ( + FILE *OutFptr, + FILE_LIST *InFile, + UINT32 *Size + ); + +static +void +DumpImage ( + FILE_LIST *InFile + ); + +char * +GetMachineTypeStr ( + UINT16 MachineType + ); + +static +char * +GetSubsystemTypeStr ( + UINT16 SubsystemType + ); + +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 + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + INT8 *Ext; + FILE *FptrOut; + UINT32 Status; + FILE_LIST *FList; + UINT32 TotalSize; + UINT32 Size; + + Status = STATUS_SUCCESS; + FptrOut = NULL; + + // + // Parse the command line arguments + // + if (ParseCommandLine (Argc, Argv, &mOptions)) { + return STATUS_ERROR; + } + // + // If dumping an image, then do that and quit + // + if (mOptions.DumpOption) { + DumpImage (mOptions.FileList); + 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]) { + strcpy (mOptions.OutFileName, mOptions.FileList->FileName); + // + // Find the last . on the line and replace the filename extension with + // the default + // + for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1; + (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\'); + 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; + fprintf ( + stdout, + "ERROR: Input and output file names must be different - %s = %s\n", + FList->FileName, + mOptions.OutFileName + ); + goto BailOut; + } + } + // + // Now open our output file + // + if ((FptrOut = fopen (mOptions.OutFileName, "w+b")) == NULL) { + fprintf (stdout, "ERROR: Failed to open output file %s\n", 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) { + if (mOptions.Verbose) { + fprintf (stdout, "Processing EFI file %s\n", FList->FileName); + } + + Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size); + } else if (FList->FileFlags & FILE_FLAG_BINARY) { + if (mOptions.Verbose) { + fprintf (stdout, "Processing binary file %s\n", FList->FileName); + } + + Status = ProcessBinFile (FptrOut, FList, &Size); + } else { + fprintf (stdout, "ERROR: File not specified as EFI or binary: %s\n", FList->FileName); + Status = STATUS_ERROR; + } + + if (mOptions.Verbose) { + fprintf (stdout, " Output size = 0x%X\n", Size); + } + + if (Status != STATUS_SUCCESS) { + break; + } + + TotalSize += Size; + } + // + // Check total size + // + if (TotalSize > MAX_OPTION_ROM_SIZE) { + fprintf ( + stdout, + "ERROR: Option ROM image size exceeds limit 0x%X bytes\n", + MAX_OPTION_ROM_SIZE + ); + Status = STATUS_ERROR; + } + +BailOut: + if (FptrOut != NULL) { + fclose (FptrOut); + } + // + // Clean up our file list + // + while (mOptions.FileList != NULL) { + FList = mOptions.FileList->Next; + free (mOptions.FileList); + mOptions.FileList = FList; + } + + return Status; +} + +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 *PciDs; + UINT32 Index; + UINT8 ByteCheckSum; + + Status = STATUS_SUCCESS; + + // + // Try to open the input file + // + if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) { + fprintf (stdout, "ERROR: Failed to open input file %s\n", 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) { + fprintf (stdout, " File size = 0x%X\n", FileSize); + } + + fseek (InFptr, 0, SEEK_SET); + Buffer = (INT8 *) malloc (FileSize); + if (Buffer == NULL) { + fprintf (stdout, "ERROR: Memory allocation failed\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + if (fread (Buffer, FileSize, 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read all bytes from input file\n"); + 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) { + fprintf ( + stdout, + "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n", + 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) { + fprintf (stdout, "ERROR: ROM image file has invalid ROM signature\n"); + 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)) { + fprintf (stdout, "ERROR: Invalid PCI data structure offset\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + PciDs = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset); + if (PciDs->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + fprintf (stdout, "ERROR: PCI data structure has invalid signature\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // If this is the last image, then set the LAST bit unless requested not + // to via the command-line -l argument. Otherwise, make sure you clear it. + // + if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) { + PciDs->Indicator = INDICATOR_LAST; + } else { + PciDs->Indicator = 0; + } + + ByteCheckSum = 0; + for (Index = 0; Index < FileSize - 1; Index++) { + ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]); + } + + Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1); + fprintf (stdout, "CheckSUm = %02x\n", (UINT32) Buffer[FileSize - 1]); + + // + // Now copy the input file contents out to the output file + // + if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write all file bytes to output file\n"); + 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) { + fprintf (stdout, "Error processing binary file %s\n", 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 PciDs; + UINT32 FileSize; + UINT32 CompressedFileSize; + UINT8 *Buffer; + UINT8 *CompressedBuffer; + UINT8 *TempBufferPtr; + UINT32 TotalSize; + UINT32 HeaderSize; + UINT16 MachineType; + UINT16 SubSystem; + UINT32 HeaderPadBytes; + + // + // Try to open the input file + // + if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) { + fprintf (stdout, "ERROR: Failed to open input file %s\n", 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; + } + + HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER); + if (mOptions.Verbose) { + fprintf (stdout, " File size = 0x%X\n", 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 = (INT8 *) malloc (FileSize); + if (Buffer == NULL) { + fprintf (stdout, "ERROR: Memory allocation failed\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + fseek (InFptr, 0, SEEK_SET); + if (fread (Buffer, FileSize, 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read all bytes from input file\n"); + 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) { + // + // Allocate a buffer into which we can compress the image, compress it, + // and use that size as the new size. + // + CompressedBuffer = (INT8 *) malloc (FileSize); + if (CompressedBuffer == NULL) { + fprintf (stdout, "ERROR: Memory allocation failed\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + CompressedFileSize = FileSize; + Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize); + if (Status != STATUS_SUCCESS) { + fprintf (stdout, "ERROR: Compression failed\n"); + goto BailOut; + } + // + // Now compute the size, then swap buffer pointers. + // + if (mOptions.Verbose) { + fprintf (stdout, " Comp size = 0x%X\n", 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; + } + // + // Check size + // + if (TotalSize > MAX_OPTION_ROM_SIZE) { + fprintf ( + stdout, + "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n", + 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; + 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 + // + memset (&PciDs, 0, sizeof (PCI_DATA_STRUCTURE)); + + PciDs.Signature = PCI_DATA_STRUCTURE_SIGNATURE; + PciDs.VendorId = VendId; + PciDs.DeviceId = DevId; + PciDs.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE); + PciDs.Revision = 0; + // + // Class code and code revision from the command line (optional) + // + PciDs.ClassCode[0] = (UINT8) InFile->ClassCode; + PciDs.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8); + PciDs.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16); + PciDs.ImageLength = RomHdr.InitializationSize; + PciDs.CodeRevision = InFile->CodeRevision; + PciDs.CodeType = PCI_CODE_TYPE_EFI_IMAGE; + + // + // If this is the last image, then set the LAST bit unless requested not + // to via the command-line -l argument. + // + if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) { + PciDs.Indicator = INDICATOR_LAST; + } + // + // Write the ROM header to the output file + // + if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write ROM header to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + // + // Write pad bytes to align the PciDs + // + while (HeaderPadBytes > 0) { + if (putc (0, OutFptr) == EOF) { + fprintf (stdout, "ERROR: Failed to write ROM header pad bytes to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + HeaderPadBytes--; + } + // + // Write the PCI data structure header to the output file + // + if (fwrite (&PciDs, sizeof (PciDs), 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write PCI ROM header to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Keep track of how many bytes left to write + // + TotalSize -= HeaderSize; + + // + // Now dump the input file's contents to the output file + // + if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write all file bytes to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + TotalSize -= FileSize; + // + // Pad the rest of the image to make it a multiple of 512 bytes + // + while (TotalSize > 0) { + if (putc (~0, OutFptr) == EOF) { + fprintf (stdout, "ERROR: Failed to write trailing pad bytes output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + TotalSize--; + } + +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) { + fprintf (stdout, "Error processing EFI file %s\n", InFile->FileName); + } + + return Status; +} + +static +int +CheckPE32File ( + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Fptr - GC_TODO: add argument description + MachineType - GC_TODO: add argument description + SubSystem - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + /*++ + +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_FILE_HEADER FileHdr; + EFI_IMAGE_OPTIONAL_HEADER OptionalHdr; + UINT32 PESig; + + // + // Position to the start of the file + // + fseek (Fptr, 0, SEEK_SET); + + // + // Read the DOS header + // + if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read the DOS stub from the input file\n"); + return STATUS_ERROR; + } + // + // Check the magic number (0x5A4D) + // + if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (magic number)\n"); + return STATUS_ERROR; + } + // + // Position into the file and check the PE signature + // + fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET); + if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PE signature bytes from input file\n"); + return STATUS_ERROR; + } + // + // Check the PE signature in the header "PE\0\0" + // + if (PESig != EFI_IMAGE_NT_SIGNATURE) { + fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (signature)\n"); + return STATUS_ERROR; + } + // + // Read the file header and stuff their MachineType + // + if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PE file header from input file\n"); + return STATUS_ERROR; + } + + memcpy ((char *) MachineType, &FileHdr.Machine, 2); + + // + // Read the optional header so we can get the subsystem + // + if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read COFF optional header from input file\n"); + return STATUS_ERROR; + } + + *SubSystem = OptionalHdr.Subsystem; + if (mOptions.Verbose) { + fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem); + } + // + // Good to go + // + 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; + + FileFlags = 0; + + // + // Clear out the options + // + memset ((char *) Options, 0, sizeof (OPTIONS)); + + // + // To avoid compile warnings + // + FileList = PrevFileList = NULL; + + 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; + } + // + // Process until no more arguments + // + while (Argc > 0) { + if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) { + // + // To simplify string comparisons, replace slashes with dashes + // + Argv[0][0] = '-'; + + // + // Vendor ID specified with -v + // + if (_stricmp (Argv[0], "-v") == 0) { + // + // Make sure there's another parameter + // + if (Argc > 1) { + Options->VendId = (UINT16) strtol (Argv[1], NULL, 16); + Options->VendIdValid = 1; + } else { + fprintf ( + stdout, + "ERROR: Missing Vendor ID with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if (_stricmp (Argv[0], "-d") == 0) { + // + // Device ID specified with -d + // Make sure there's another parameter + // + if (Argc > 1) { + Options->DevId = (UINT16) strtol (Argv[1], NULL, 16); + Options->DevIdValid = 1; + } else { + fprintf ( + stdout, + "ERROR: Missing Device ID with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if (_stricmp (Argv[0], "-o") == 0) { + // + // Output filename specified with -o + // Make sure there's another parameter + // + if (Argc > 1) { + strcpy (Options->OutFileName, Argv[1]); + } else { + fprintf ( + stdout, + "ERROR: Missing output file name with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if ((_stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) { + // + // Help option + // + Usage (); + return STATUS_ERROR; + } else if (_stricmp (Argv[0], "-b") == 0) { + // + // Specify binary files with -b + // + FileFlags = (FileFlags &~FILE_FLAG_EFI) | FILE_FLAG_BINARY; + } else if ((_stricmp (Argv[0], "-e") == 0) || (_stricmp (Argv[0], "-ec") == 0)) { + // + // Specify EFI files with -e. Specify EFI-compressed with -ec. + // + FileFlags = (FileFlags &~FILE_FLAG_BINARY) | 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 -l + // + } else if (_stricmp (Argv[0], "-l") == 0) { + Options->NoLast = 1; + } else if (_stricmp (Argv[0], "-p") == 0) { + // + // -v for verbose would have been nicer, but it's already used. Let's use + // -p for prolix (wordy) output + // + Options->Verbose = 1; + } else if (_stricmp (Argv[0], "-dump") == 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->DevIdValid = 1; + FileFlags = FILE_FLAG_BINARY; + } else if (_stricmp (Argv[0], "-cc") == 0) { + // + // Class code value for the next file in the list. + // Make sure there's another parameter + // + if (Argc > 1) { + // + // No error checking on the return value. Could check for LONG_MAX, + // LONG_MIN, or 0 class code value if desired. Check range (3 bytes) + // at least. + // + ClassCode = (UINT32) strtol (Argv[1], NULL, 16); + if (ClassCode & 0xFF000000) { + fprintf (stdout, "ERROR: Class code %s out of range\n", Argv[1]); + return STATUS_ERROR; + } + } else { + fprintf ( + stdout, + "ERROR: Missing class code value with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if (_stricmp (Argv[0], "-rev") == 0) { + // + // Code revision in the PCI data structure. The value is for the next + // file in the list. + // Make sure there's another parameter + // + if (Argc > 1) { + // + // No error checking on the return value. Could check for LONG_MAX, + // LONG_MIN, or 0 value if desired. Check range (2 bytes) + // at least. + // + CodeRevision = (UINT32) strtol (Argv[1], NULL, 16); + if (CodeRevision & 0xFFFF0000) { + fprintf (stdout, "ERROR: Code revision %s out of range\n", Argv[1]); + return STATUS_ERROR; + } + } else { + fprintf ( + stdout, + "ERROR: Missing code revision value with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else { + fprintf (stdout, "ERROR: Invalid option specified: %s\n\n", Argv[0]); + Usage (); + return STATUS_ERROR; + } + } 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) { + fprintf (stdout, "ERROR: Missing -e or -b with input file %s\n", Argv[0]); + return STATUS_ERROR; + } + // + // Create a new file structure + // + FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST)); + if (FileList == NULL) { + fprintf (stdout, "ERROR: Memory allocation failure\n"); + return STATUS_ERROR; + } + + memset ((char *) FileList, 0, sizeof (FILE_LIST)); + FileList->FileName = Argv[0]; + FileList->FileFlags = FileFlags; + if (Options->FileList == NULL) { + Options->FileList = FileList; + } else { + if (PrevFileList == NULL) { + PrevFileList = FileList; + } else { + PrevFileList->Next = FileList; + } + } + + PrevFileList = FileList; + // + // Set the class code and code revision for this file, then reset the values. + // + FileList->ClassCode = ClassCode; + FileList->CodeRevision = (UINT16) CodeRevision; + ClassCode = 0; + CodeRevision = 0; + } + // + // Next argument + // + Argv++; + Argc--; + } + // + // Make sure they specified a device ID and vendor ID + // + if (!Options->VendIdValid) { + fprintf (stdout, "ERROR: Missing Vendor ID on command line\n\n"); + Usage (); + return STATUS_ERROR; + } + + if (!Options->DevIdValid) { + fprintf (stdout, "ERROR: Missing Device ID on command line\n\n"); + Usage (); + return STATUS_ERROR; + } + // + // Must have specified some files + // + if (Options->FileList == NULL) { + fprintf (stdout, "ERROR: Missing input file name\n"); + Usage (); + return STATUS_ERROR; + } + + return 0; +} + +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print usage information for this utility. + +Arguments: + + None. + +Returns: + + Nothing. + +--*/ +{ + int Index; + static const char *Msg[] = { + "EfiRom "UTILITY_VERSION" - Intel EFI Make Option ROM utility", + " Copyright (C), 1999 - 2002 Intel Coproration\n", + " Create an option ROM image from a list of input files", + " Usage: efirom {-p} [-v VendorId] [-d DeviceId] {-o OutFileName} ", + " [-e|-b] [FileName(s)]", + " where:", + " VendorId - required hex PCI Vendor ID for the device", + " DeviceId - required hex PCI Device ID for the device", + " OutFileName - optional output file name. Default is the first input", + " file name with a "DEFAULT_OUTPUT_EXTENSION" file extension", + " FileNames - input PE32 or binary file name(s)", + " BinFileName - input binary file name(s)", + " -p - for verbose output", + " -l - to not automatically set the LAST bit on the last file", + " -b - following FileNames are binary files", + " -e - following FileNames are EFI PE32 image files", + " -ec - following FileNames are EFI PE32 image files, and should", + " be compressed by this utility", + " -cc ClassCode - to use hex ClassCode in the PCI data structure header for", + " the following FileName", + " -rev Revision - to use hex Revision in the PCI data structure header for", + " the following FileName", + " -dump - to dump the headers of an existing option ROM image", + "", + "Example usage: EfiRom -v 0xABCD -d 0x1234 -b File1.bin File2.bin -e File1.efi File2.efi ", + "", + NULL + }; + + for (Index = 0; Msg[Index] != NULL; Index++) { + fprintf (stdout, "%s\n", Msg[Index]); + } +} + +static +void +DumpImage ( + FILE_LIST *InFile + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + InFile - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + PCI_EXPANSION_ROM_HEADER PciRomHdr; + FILE *InFptr; + UINT32 ImageStart; + UINT32 ImageCount; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr; + PCI_DATA_STRUCTURE PciDs; + + // + // Open the input file + // + if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) { + fprintf ( + stdout, + "ERROR: Could not open input file %s\n", + InFile->FileName + ); + return ; + } + // + // Go through the image and dump the header stuff for each + // + ImageCount = 0; + for (;;) { + // + // Save our postition 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) { + fprintf (stdout, "ERROR: Failed to read PCI ROM header from file\n"); + goto BailOut; + } + + // + // Dump the contents of the header + // + fprintf (stdout, "Image %d -- Offset 0x%X\n", ImageCount, ImageStart); + fprintf (stdout, " ROM header contents\n"); + fprintf (stdout, " Signature 0x%04X\n", (UINT32) PciRomHdr.Signature); + fprintf (stdout, " PCIR offset 0x%04X\n", (UINT32) PciRomHdr.PcirOffset); + // + // Find PCI data structure + // + if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) { + fprintf (stdout, "ERROR: Failed to seek to PCI data structure\n"); + goto BailOut; + } + // + // Read and dump the PCI data structure + // + if (fread (&PciDs, sizeof (PciDs), 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PCI data structure from file\n"); + goto BailOut; + } + + fprintf (stdout, " PCI Data Structure\n"); + fprintf ( + stdout, + " Signature %c%c%c%c\n", + (char) PciDs.Signature, + (char) (PciDs.Signature >> 8), + (char) (PciDs.Signature >> 16), + (char) (PciDs.Signature >> 24) + ); + fprintf (stdout, " Vendor ID 0x%04X\n", PciDs.VendorId); + fprintf (stdout, " Device ID 0x%04X\n", PciDs.DeviceId); + fprintf ( + stdout, + " Class Code 0x%06X\n", + (UINT32) (PciDs.ClassCode[0] | (PciDs.ClassCode[1] << 8) | (PciDs.ClassCode[2] << 16)) + ); + fprintf (stdout, " Image size 0x%X\n", PciDs.ImageLength * 512); + fprintf (stdout, " Code revision: 0x%04X\n", PciDs.CodeRevision); + fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs.Indicator); + // + // Print the indicator, used to flag the last image + // + if (PciDs.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. + // + fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs.CodeType); + if (PciDs.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)) { + fprintf (stdout, "ERROR: Failed to re-seek to ROM header structure\n"); + goto BailOut; + } + + if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read EFI PCI ROM header from file\n"); + goto BailOut; + } + // + // Now dump more info + // + fprintf (stdout, " EFI Signature 0x%04X\n", EfiRomHdr.EfiSignature); + fprintf ( + stdout, + " Compression Type 0x%04X ", + (UINT32) 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", + (UINT32) EfiRomHdr.EfiImageHeaderOffset, + (UINT32) (EfiRomHdr.EfiImageHeaderOffset + 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 (PciDs.Indicator == INDICATOR_LAST) { + goto BailOut; + } + // + // Seek to the start of the next image + // + if (fseek (InFptr, ImageStart + (PciDs.ImageLength * 512), SEEK_SET)) { + fprintf (stdout, "ERROR: Failed to seek to next image\n"); + 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"; +} diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/Makefile b/EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/Makefile new file mode 100644 index 0000000000..2832154763 --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/EfiRom/Makefile @@ -0,0 +1,85 @@ +#/*++ +# +# Copyright (c) 2007, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# Makefile +# +# Abstract: +# +# makefile for building the EfiRom utility. +# +#--*/ + +# +# Make sure environmental variable EDK_SOURCE is set +# +!IFNDEF EDK_SOURCE +!ERROR EDK_SOURCE environmental variable not set +!ENDIF + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE $(BUILD_DIR)\PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = EfiRom +TARGET_SOURCE_DIR = $(EDK_TOOLS_SOURCE)\$(TARGET_NAME) + +TARGET_EXE = $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).exe +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(EDK_TOOLS_OUTPUT)\EfiRom.obj \ + $(EDK_TOOLS_OUTPUT)\EfiCompress.obj + +# +# Build the EXE by compiling the source files, then linking the resultant +# object files together. +# + +$(EDK_TOOLS_OUTPUT)\EfiRom.obj : $(TARGET_SOURCE_DIR)\EfiRom.c + $(CC) $(C_FLAGS) $(TARGET_SOURCE_DIR)\EfiRom.c /Fo$@ + +$(EDK_TOOLS_OUTPUT)\EfiCompress.obj : $(EDK_TOOLS_SOURCE)\Common\EfiCompress.c + $(CC) $(C_FLAGS) $(EDK_TOOLS_SOURCE)\Common\EfiCompress.c /Fo$@ + +# +# Add Binary Build description for this tool. +# + +!IF (("$(EFI_BINARY_TOOLS)" == "YES") && EXIST($(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).exe)) +$(TARGET_EXE): $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).exe + copy $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).exe $(TARGET_EXE) /Y + if exist $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).pdb \ + copy $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).pdb $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).pdb /Y +!ELSE +$(TARGET_EXE): $(OBJECTS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + if not exist $(EFI_PLATFORM_BIN)\Tools mkdir $(EFI_PLATFORM_BIN)\Tools + if exist $(TARGET_EXE) copy $(TARGET_EXE) $(EFI_PLATFORM_BIN)\tools\$(TARGET_NAME).exe /Y + if exist $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).pdb \ + copy $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).pdb $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).pdb /Y +!ENDIF + +clean: + @if exist $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL -- cgit v1.2.3