Home | History | Annotate | Download | only in EfiRom
      1 /** @file
      2 Utility program to create an EFI option ROM image from binary and EFI PE32 files.
      3 
      4 Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed and made available
      6 under the terms and conditions of the BSD License which accompanies this
      7 distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "EfiUtilityMsgs.h"
     16 #include "ParseInf.h"
     17 #include "EfiRom.h"
     18 
     19 UINT64  DebugLevel = 0;
     20 
     21 int
     22 main (
     23   int   Argc,
     24   char  *Argv[]
     25   )
     26 /*++
     27 
     28 Routine Description:
     29 
     30   Given an EFI image filename, create a ROM-able image by creating an option
     31   ROM header and PCI data structure, filling them in, and then writing the
     32   option ROM header + PCI data structure + EFI image out to the output file.
     33 
     34 Arguments:
     35 
     36   Argc            - standard C main() argument count
     37 
     38   Argv            - standard C main() argument list
     39 
     40 Returns:
     41 
     42   0             success
     43   non-zero      otherwise
     44 
     45 --*/
     46 {
     47   CHAR8     *Ext;
     48   FILE      *FptrOut;
     49   UINT32    Status;
     50   FILE_LIST *FList;
     51   UINT32    TotalSize;
     52   UINT32    Size;
     53   CHAR8     *Ptr0;
     54 
     55   SetUtilityName(UTILITY_NAME);
     56 
     57   Status  = STATUS_SUCCESS;
     58   FptrOut = NULL;
     59 
     60   //
     61   // Parse the command line arguments
     62   //
     63   if (ParseCommandLine (Argc, Argv, &mOptions)) {
     64     return STATUS_ERROR;
     65   }
     66 
     67   if (mOptions.Quiet) {
     68     SetPrintLevel(40);
     69   } else if (mOptions.Verbose) {
     70     SetPrintLevel(15);
     71   } else if (mOptions.Debug) {
     72     SetPrintLevel(DebugLevel);
     73   }
     74 
     75   if (mOptions.Verbose) {
     76     VerboseMsg("%s tool start.\n", UTILITY_NAME);
     77   }
     78 
     79   //
     80   // If dumping an image, then do that and quit
     81   //
     82   if (mOptions.DumpOption == 1) {
     83     if (mOptions.FileList != NULL) {
     84       if ((Ptr0 = strstr ((CONST CHAR8 *) mOptions.FileList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {
     85         DumpImage (mOptions.FileList);
     86         goto BailOut;
     87       } else {
     88         Error (NULL, 0, 1002, "No PciRom input file", "No *.rom input file");
     89         goto BailOut;
     90       }
     91     }
     92   }
     93   //
     94   // Determine the output filename. Either what they specified on
     95   // the command line, or the first input filename with a different extension.
     96   //
     97   if (!mOptions.OutFileName[0]) {
     98     strcpy (mOptions.OutFileName, mOptions.FileList->FileName);
     99     //
    100     // Find the last . on the line and replace the filename extension with
    101     // the default
    102     //
    103     for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;
    104          (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');
    105          Ext--
    106         )
    107       ;
    108     //
    109     // If dot here, then insert extension here, otherwise append
    110     //
    111     if (*Ext != '.') {
    112       Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);
    113     }
    114 
    115     strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);
    116   }
    117   //
    118   // Make sure we don't have the same filename for input and output files
    119   //
    120   for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
    121     if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {
    122       Status = STATUS_ERROR;
    123       Error (NULL, 0, 1002, "Invalid input paramter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);
    124       goto BailOut;
    125     }
    126   }
    127   //
    128   // Now open our output file
    129   //
    130   if ((FptrOut = fopen (LongFilePath (mOptions.OutFileName), "wb")) == NULL) {
    131     Error (NULL, 0, 0001, "Error opening file", "Error opening file %s", mOptions.OutFileName);
    132     goto BailOut;
    133   }
    134   //
    135   // Process all our files
    136   //
    137   TotalSize = 0;
    138   for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
    139     Size = 0;
    140     if ((FList->FileFlags & FILE_FLAG_EFI) != 0) {
    141       if (mOptions.Verbose) {
    142         VerboseMsg("Processing EFI file    %s\n", FList->FileName);
    143       }
    144 
    145       Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);
    146     } else if ((FList->FileFlags & FILE_FLAG_BINARY) !=0 ) {
    147       if (mOptions.Verbose) {
    148         VerboseMsg("Processing binary file %s\n", FList->FileName);
    149       }
    150 
    151       Status = ProcessBinFile (FptrOut, FList, &Size);
    152     } else {
    153       Error (NULL, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList->FileName);
    154       Status = STATUS_ERROR;
    155     }
    156 
    157     if (mOptions.Verbose) {
    158       VerboseMsg("  Output size = 0x%X\n", (unsigned) Size);
    159     }
    160 
    161     if (Status != STATUS_SUCCESS) {
    162       break;
    163     }
    164 
    165     TotalSize += Size;
    166   }
    167   //
    168   // Check total size
    169   //
    170   if (TotalSize > MAX_OPTION_ROM_SIZE) {
    171     Error (NULL, 0, 2000, "Invalid paramter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);
    172     Status = STATUS_ERROR;
    173   }
    174 
    175 BailOut:
    176   if (Status == STATUS_SUCCESS) {
    177     if (FptrOut != NULL) {
    178       fclose (FptrOut);
    179     }
    180     //
    181     // Clean up our file list
    182     //
    183     while (mOptions.FileList != NULL) {
    184       FList = mOptions.FileList->Next;
    185       free (mOptions.FileList);
    186       mOptions.FileList = FList;
    187     }
    188   }
    189 
    190   if (mOptions.Verbose) {
    191     VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());
    192   }
    193 
    194   return GetUtilityStatus ();
    195 }
    196 
    197 static
    198 int
    199 ProcessBinFile (
    200   FILE      *OutFptr,
    201   FILE_LIST *InFile,
    202   UINT32    *Size
    203   )
    204 /*++
    205 
    206 Routine Description:
    207 
    208   Process a binary input file.
    209 
    210 Arguments:
    211 
    212   OutFptr     - file pointer to output binary ROM image file we're creating
    213   InFile      - structure contains information on the binary file to process
    214   Size        - pointer to where to return the size added to the output file
    215 
    216 Returns:
    217 
    218   0 - successful
    219 
    220 --*/
    221 {
    222   FILE                      *InFptr;
    223   UINT32                    TotalSize;
    224   UINT32                    FileSize;
    225   UINT8                     *Buffer;
    226   UINT32                    Status;
    227   PCI_EXPANSION_ROM_HEADER  *RomHdr;
    228   PCI_DATA_STRUCTURE        *PciDs23;
    229   PCI_3_0_DATA_STRUCTURE    *PciDs30;
    230   UINT32                    Index;
    231   UINT8                     ByteCheckSum;
    232   UINT16                    CodeType;
    233 
    234   PciDs23 = NULL;
    235   PciDs30 = NULL;
    236   Status = STATUS_SUCCESS;
    237 
    238   //
    239   // Try to open the input file
    240   //
    241   if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {
    242     Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
    243     return STATUS_ERROR;
    244   }
    245   //
    246   // Seek to the end of the input file and get the file size. Then allocate
    247   // a buffer to read it in to.
    248   //
    249   fseek (InFptr, 0, SEEK_END);
    250   FileSize = ftell (InFptr);
    251   if (mOptions.Verbose) {
    252     VerboseMsg("  File size   = 0x%X\n", (unsigned) FileSize);
    253   }
    254 
    255   fseek (InFptr, 0, SEEK_SET);
    256   Buffer = (UINT8 *) malloc (FileSize);
    257   if (Buffer == NULL) {
    258     Error (NULL, 0, 4003, "Resource", "memory cannot be allocated!");
    259     Status = STATUS_ERROR;
    260     goto BailOut;
    261   }
    262 
    263   if (fread (Buffer, FileSize, 1, InFptr) != 1) {
    264     Error (NULL, 0, 2000, "Invalid", "Failed to read all bytes from input file.");
    265     Status = STATUS_ERROR;
    266     goto BailOut;
    267   }
    268   //
    269   // Total size must be an even multiple of 512 bytes, and can't exceed
    270   // the option ROM image size.
    271   //
    272   TotalSize = FileSize;
    273   if (TotalSize & 0x1FF) {
    274     TotalSize = (TotalSize + 0x200) &~0x1ff;
    275   }
    276 
    277   if (TotalSize > MAX_OPTION_ROM_SIZE) {
    278     Error (NULL, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);
    279     Status = STATUS_ERROR;
    280     goto BailOut;
    281   }
    282   //
    283   // Return the size to the caller so they can keep track of the running total.
    284   //
    285   *Size = TotalSize;
    286 
    287   //
    288   // Crude check to make sure it's a legitimate ROM image
    289   //
    290   RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;
    291   if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
    292     Error (NULL, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");
    293     Status = STATUS_ERROR;
    294     goto BailOut;
    295   }
    296   //
    297   // Make sure the pointer to the PCI data structure is within the size of the image.
    298   // Then check it for valid signature.
    299   //
    300   if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {
    301     Error (NULL, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");
    302     Status = STATUS_ERROR;
    303     goto BailOut;
    304   }
    305 
    306   //
    307   // Check the header is conform to PCI2.3 or PCI3.0
    308   //
    309   if (mOptions.Pci23 == 1) {
    310     PciDs23 = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);
    311     if (PciDs23->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
    312       Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
    313       Status = STATUS_ERROR;
    314       goto BailOut;
    315     }
    316   } else {
    317     //
    318     // Default setting is PCI3.0 header
    319     //
    320     PciDs30 = (PCI_3_0_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);
    321     if (PciDs30->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
    322       Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
    323       Status = STATUS_ERROR;
    324       goto BailOut;
    325     }
    326   }
    327 
    328   //
    329   // ReSet Option Rom size
    330   //
    331   if (mOptions.Pci23 == 1) {
    332     PciDs23->ImageLength = (UINT16) (TotalSize / 512);
    333     CodeType = PciDs23->CodeType;
    334   } else {
    335     PciDs30->ImageLength = (UINT16) (TotalSize / 512);
    336     CodeType = PciDs30->CodeType;
    337 	}
    338 
    339   //
    340   // If this is the last image, then set the LAST bit unless requested not
    341   // to via the command-line -n argument. Otherwise, make sure you clear it.
    342   //
    343   if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
    344     if (mOptions.Pci23 == 1) {
    345       PciDs23->Indicator = INDICATOR_LAST;
    346     } else {
    347       PciDs30->Indicator = INDICATOR_LAST;
    348 		}
    349   } else {
    350     if (mOptions.Pci23 == 1) {
    351       PciDs23->Indicator = 0;
    352     } else {
    353       PciDs30->Indicator = 0;
    354 		}
    355   }
    356 
    357   if (CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
    358     ByteCheckSum = 0;
    359     for (Index = 0; Index < FileSize - 1; Index++) {
    360       ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);
    361     }
    362 
    363     Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);
    364     if (mOptions.Verbose) {
    365       VerboseMsg("  Checksum = %02x\n\n", Buffer[FileSize - 1]);
    366     }
    367   }
    368 
    369   //
    370   // Now copy the input file contents out to the output file
    371   //
    372   if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
    373     Error (NULL, 0, 0005, "Failed to write all file bytes to output file.", NULL);
    374     Status = STATUS_ERROR;
    375     goto BailOut;
    376   }
    377 
    378   TotalSize -= FileSize;
    379   //
    380   // Pad the rest of the image to make it a multiple of 512 bytes
    381   //
    382   while (TotalSize > 0) {
    383     putc (~0, OutFptr);
    384     TotalSize--;
    385   }
    386 
    387 BailOut:
    388   if (InFptr != NULL) {
    389     fclose (InFptr);
    390   }
    391 
    392   if (Buffer != NULL) {
    393     free (Buffer);
    394   }
    395   //
    396   // Print the file name if errors occurred
    397   //
    398   if (Status != STATUS_SUCCESS) {
    399     Error (NULL, 0, 0003, "Error", "Error parsing file: %s", InFile->FileName);
    400   }
    401 
    402   return Status;
    403 }
    404 
    405 static
    406 int
    407 ProcessEfiFile (
    408   FILE      *OutFptr,
    409   FILE_LIST *InFile,
    410   UINT16    VendId,
    411   UINT16    DevId,
    412   UINT32    *Size
    413   )
    414 /*++
    415 
    416 Routine Description:
    417 
    418   Process a PE32 EFI file.
    419 
    420 Arguments:
    421 
    422   OutFptr     - file pointer to output binary ROM image file we're creating
    423   InFile      - structure contains information on the PE32 file to process
    424   VendId      - vendor ID as required in the option ROM header
    425   DevId       - device ID as required in the option ROM header
    426   Size        - pointer to where to return the size added to the output file
    427 
    428 Returns:
    429 
    430   0 - successful
    431 
    432 --*/
    433 {
    434   UINT32                        Status;
    435   FILE                          *InFptr;
    436   EFI_PCI_EXPANSION_ROM_HEADER  RomHdr;
    437   PCI_DATA_STRUCTURE            PciDs23;
    438   PCI_3_0_DATA_STRUCTURE        PciDs30;
    439   UINT32                        FileSize;
    440   UINT32                        CompressedFileSize;
    441   UINT8                         *Buffer;
    442   UINT8                         *CompressedBuffer;
    443   UINT8                         *TempBufferPtr;
    444   UINT32                        TotalSize;
    445   UINT32                        HeaderSize;
    446   UINT16                        MachineType;
    447   UINT16                        SubSystem;
    448   UINT32                        HeaderPadBytes;
    449   UINT32                        PadBytesBeforeImage;
    450   UINT32                        PadBytesAfterImage;
    451 
    452   //
    453   // Try to open the input file
    454   //
    455   if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {
    456     Error (NULL, 0, 0001, "Open file error", "Error opening file: %s", InFile->FileName);
    457     return STATUS_ERROR;
    458   }
    459   //
    460   // Initialize our buffer pointers to null.
    461   //
    462   Buffer            = NULL;
    463   CompressedBuffer  = NULL;
    464 
    465   //
    466   // Double-check the file to make sure it's what we expect it to be
    467   //
    468   Status = CheckPE32File (InFptr, &MachineType, &SubSystem);
    469   if (Status != STATUS_SUCCESS) {
    470     goto BailOut;
    471   }
    472   //
    473   // Seek to the end of the input file and get the file size
    474   //
    475   fseek (InFptr, 0, SEEK_END);
    476   FileSize = ftell (InFptr);
    477 
    478   //
    479   // Get the size of the headers we're going to put in front of the image. The
    480   // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
    481   //
    482   if (sizeof (RomHdr) & 0x03) {
    483     HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);
    484   } else {
    485     HeaderPadBytes = 0;
    486   }
    487 
    488   //
    489   // For Pci3.0 to use the different data structure.
    490   //
    491   if (mOptions.Pci23 == 1) {
    492     HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
    493   } else {
    494     HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
    495   }
    496 
    497   if (mOptions.Verbose) {
    498     VerboseMsg("  File size   = 0x%X\n", (unsigned) FileSize);
    499   }
    500   //
    501   // Allocate memory for the entire file (in case we have to compress), then
    502   // seek back to the beginning of the file and read it into our buffer.
    503   //
    504   Buffer = (UINT8 *) malloc (FileSize);
    505   if (Buffer == NULL) {
    506     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    507     Status = STATUS_ERROR;
    508     goto BailOut;
    509   }
    510 
    511   fseek (InFptr, 0, SEEK_SET);
    512   if (fread (Buffer, FileSize, 1, InFptr) != 1) {
    513     Error (NULL, 0, 0004, "Error reading file", "File %s", InFile->FileName);
    514     Status = STATUS_ERROR;
    515     goto BailOut;
    516   }
    517   //
    518   // Now determine the size of the final output file. It's either the header size
    519   // plus the file's size, or the header size plus the compressed file size.
    520   //
    521   if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {
    522     //
    523     // Allocate a buffer into which we can compress the image, compress it,
    524     // and use that size as the new size.
    525     //
    526     CompressedBuffer = (UINT8 *) malloc (FileSize);
    527     if (CompressedBuffer == NULL) {
    528       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    529       Status = STATUS_ERROR;
    530       goto BailOut;
    531     }
    532 
    533     CompressedFileSize  = FileSize;
    534     Status              = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);
    535     if (Status != STATUS_SUCCESS) {
    536       Error (NULL, 0, 0007, "Error compressing file!", NULL);
    537       goto BailOut;
    538     }
    539     //
    540     // Now compute the size, then swap buffer pointers.
    541     //
    542     if (mOptions.Verbose) {
    543       VerboseMsg("  Comp size   = 0x%X\n", (unsigned) CompressedFileSize);
    544     }
    545 
    546     TotalSize         = CompressedFileSize + HeaderSize;
    547     FileSize          = CompressedFileSize;
    548     TempBufferPtr     = Buffer;
    549     Buffer            = CompressedBuffer;
    550     CompressedBuffer  = TempBufferPtr;
    551   } else {
    552     TotalSize = FileSize + HeaderSize;
    553   }
    554   //
    555   // Total size must be an even multiple of 512 bytes
    556   //
    557   if (TotalSize & 0x1FF) {
    558     TotalSize = (TotalSize + 0x200) &~0x1ff;
    559   }
    560   //
    561   // Workaround:
    562   //   If compressed, put the pad bytes after the image,
    563   //   else put the pad bytes before the image.
    564   //
    565   if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {
    566     PadBytesBeforeImage = 0;
    567     PadBytesAfterImage = TotalSize - (FileSize + HeaderSize);
    568   } else {
    569     PadBytesBeforeImage = TotalSize - (FileSize + HeaderSize);
    570     PadBytesAfterImage = 0;
    571   }
    572   //
    573   // Check size
    574   //
    575   if (TotalSize > MAX_OPTION_ROM_SIZE) {
    576     Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);
    577     Status = STATUS_ERROR;
    578     goto BailOut;
    579   }
    580   //
    581   // Return the size to the caller so they can keep track of the running total.
    582   //
    583   *Size = TotalSize;
    584 
    585   //
    586   // Now fill in the ROM header. These values come from chapter 18 of the
    587   // EFI 1.02 specification.
    588   //
    589   memset (&RomHdr, 0, sizeof (RomHdr));
    590   RomHdr.Signature            = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
    591   RomHdr.InitializationSize   = (UINT16) (TotalSize / 512);
    592   RomHdr.EfiSignature         = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
    593   RomHdr.EfiSubsystem         = SubSystem;
    594   RomHdr.EfiMachineType       = MachineType;
    595   RomHdr.EfiImageHeaderOffset = (UINT16) (HeaderSize + PadBytesBeforeImage);
    596   RomHdr.PcirOffset           = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);
    597   //
    598   // Set image as compressed or not
    599   //
    600   if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
    601     RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;
    602   }
    603   //
    604   // Fill in the PCI data structure
    605   //
    606   if (mOptions.Pci23 == 1) {
    607     memset (&PciDs23, 0, sizeof (PCI_DATA_STRUCTURE));
    608   } else {
    609     memset (&PciDs30, 0, sizeof (PCI_3_0_DATA_STRUCTURE));
    610   }
    611 
    612   if (mOptions.Pci23 == 1) {
    613     PciDs23.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
    614     PciDs23.VendorId  = VendId;
    615     PciDs23.DeviceId  = DevId;
    616     PciDs23.Length    = (UINT16) sizeof (PCI_DATA_STRUCTURE);
    617     PciDs23.Revision  = 0;
    618     //
    619     // Class code and code revision from the command line (optional)
    620     //
    621     PciDs23.ClassCode[0]  = (UINT8) InFile->ClassCode;
    622     PciDs23.ClassCode[1]  = (UINT8) (InFile->ClassCode >> 8);
    623     PciDs23.ClassCode[2]  = (UINT8) (InFile->ClassCode >> 16);
    624     PciDs23.ImageLength   = RomHdr.InitializationSize;
    625     PciDs23.CodeRevision  = InFile->CodeRevision;
    626     PciDs23.CodeType      = PCI_CODE_TYPE_EFI_IMAGE;
    627   } else {
    628     PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
    629     PciDs30.VendorId  = VendId;
    630     PciDs30.DeviceId  = DevId;
    631     PciDs30.DeviceListOffset = 0; // to be fixed
    632     PciDs30.Length    = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);
    633     PciDs30.Revision  = 0x3;
    634     //
    635     // Class code and code revision from the command line (optional)
    636     //
    637     PciDs30.ClassCode[0]  = (UINT8) InFile->ClassCode;
    638     PciDs30.ClassCode[1]  = (UINT8) (InFile->ClassCode >> 8);
    639     PciDs30.ClassCode[2]  = (UINT8) (InFile->ClassCode >> 16);
    640     PciDs30.ImageLength   = RomHdr.InitializationSize;
    641     PciDs30.CodeRevision  = InFile->CodeRevision;
    642     PciDs30.CodeType      = PCI_CODE_TYPE_EFI_IMAGE;
    643     PciDs30.MaxRuntimeImageLength = 0; // to be fixed
    644     PciDs30.ConfigUtilityCodeHeaderOffset = 0; // to be fixed
    645     PciDs30.DMTFCLPEntryPointOffset = 0; // to be fixed
    646   }
    647   //
    648   // If this is the last image, then set the LAST bit unless requested not
    649   // to via the command-line -n argument.
    650   //
    651   if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
    652     if (mOptions.Pci23 == 1) {
    653       PciDs23.Indicator = INDICATOR_LAST;
    654 	  } else {
    655     PciDs30.Indicator = INDICATOR_LAST;}
    656   } else {
    657     if (mOptions.Pci23 == 1) {
    658       PciDs23.Indicator = 0;
    659 	} else {
    660       PciDs30.Indicator = 0;
    661     }
    662   }
    663   //
    664   // Write the ROM header to the output file
    665   //
    666   if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {
    667     Error (NULL, 0, 0002, "Failed to write ROM header to output file!", NULL);
    668     Status = STATUS_ERROR;
    669     goto BailOut;
    670   }
    671 
    672   //
    673   // Write pad bytes to align the PciDs
    674   //
    675   while (HeaderPadBytes > 0) {
    676     if (putc (0, OutFptr) == EOF) {
    677       Error (NULL, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL);
    678       Status = STATUS_ERROR;
    679       goto BailOut;
    680     }
    681 
    682     HeaderPadBytes--;
    683   }
    684   //
    685   // Write the PCI data structure header to the output file
    686   //
    687   if (mOptions.Pci23 == 1) {
    688     if (fwrite (&PciDs23, sizeof (PciDs23), 1, OutFptr) != 1) {
    689       Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);
    690       Status = STATUS_ERROR;
    691       goto BailOut;
    692     }
    693   } else {
    694     if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {
    695       Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);
    696       Status = STATUS_ERROR;
    697       goto BailOut;
    698     }
    699   }
    700 
    701   //
    702   // Pad head to make it a multiple of 512 bytes
    703   //
    704   while (PadBytesBeforeImage > 0) {
    705     if (putc (~0, OutFptr) == EOF) {
    706       Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);
    707       Status = STATUS_ERROR;
    708       goto BailOut;
    709     }
    710     PadBytesBeforeImage--;
    711   }
    712   //
    713   // Now dump the input file's contents to the output file
    714   //
    715   if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
    716     Error (NULL, 0, 0002, "Failed to write all file bytes to output file!", NULL);
    717     Status = STATUS_ERROR;
    718     goto BailOut;
    719   }
    720 
    721   //
    722   // Pad the rest of the image to make it a multiple of 512 bytes
    723   //
    724   while (PadBytesAfterImage > 0) {
    725     if (putc (~0, OutFptr) == EOF) {
    726       Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);
    727       Status = STATUS_ERROR;
    728       goto BailOut;
    729     }
    730 
    731     PadBytesAfterImage--;
    732   }
    733 
    734 BailOut:
    735   if (InFptr != NULL) {
    736     fclose (InFptr);
    737   }
    738   //
    739   // Free up our buffers
    740   //
    741   if (Buffer != NULL) {
    742     free (Buffer);
    743   }
    744 
    745   if (CompressedBuffer != NULL) {
    746     free (CompressedBuffer);
    747   }
    748   //
    749   // Print the file name if errors occurred
    750   //
    751   if (Status != STATUS_SUCCESS) {
    752     Error (NULL, 0, 0003, "Error parsing", "Error parsing file: %s", InFile->FileName);
    753   }
    754 
    755   return Status;
    756 }
    757 
    758 static
    759 int
    760 CheckPE32File (
    761   FILE      *Fptr,
    762   UINT16    *MachineType,
    763   UINT16    *SubSystem
    764   )
    765 /*++
    766 
    767 Routine Description:
    768 
    769   Given a file pointer to a supposed PE32 image file, verify that it is indeed a
    770   PE32 image file, and then return the machine type in the supplied pointer.
    771 
    772 Arguments:
    773 
    774   Fptr          File pointer to the already-opened PE32 file
    775   MachineType   Location to stuff the machine type of the PE32 file. This is needed
    776                 because the image may be Itanium-based, IA32, or EBC.
    777 
    778 Returns:
    779 
    780   0             success
    781   non-zero      otherwise
    782 
    783 --*/
    784 {
    785   EFI_IMAGE_DOS_HEADER            DosHeader;
    786   EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
    787 
    788   //
    789   // Position to the start of the file
    790   //
    791   fseek (Fptr, 0, SEEK_SET);
    792 
    793   //
    794   // Read the DOS header
    795   //
    796   if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {
    797     Error (NULL, 0, 0004, "Failed to read the DOS stub from the input file!", NULL);
    798     return STATUS_ERROR;
    799   }
    800   //
    801   // Check the magic number (0x5A4D)
    802   //
    803   if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
    804     Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");
    805     return STATUS_ERROR;
    806   }
    807   //
    808   // Position into the file and check the PE signature
    809   //
    810   fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);
    811 
    812   //
    813   // Read PE headers
    814   //
    815   if (fread (&PeHdr, sizeof (PeHdr), 1, Fptr) != 1) {
    816     Error (NULL, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL);
    817     return STATUS_ERROR;
    818   }
    819 
    820 
    821   //
    822   // Check the PE signature in the header "PE\0\0"
    823   //
    824   if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
    825     Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");
    826     return STATUS_ERROR;
    827   }
    828 
    829   memcpy ((char *) MachineType, &PeHdr.Pe32.FileHeader.Machine, 2);
    830 
    831   if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    832     *SubSystem = PeHdr.Pe32.OptionalHeader.Subsystem;
    833   } else if (PeHdr.Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    834     *SubSystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
    835   } else {
    836     Error (NULL, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");
    837     return STATUS_ERROR;
    838   }
    839 
    840   if (mOptions.Verbose) {
    841     VerboseMsg("  Got subsystem = 0x%X from image\n", *SubSystem);
    842   }
    843 
    844   //
    845   // File was successfully identified as a PE32
    846   //
    847   return STATUS_SUCCESS;
    848 }
    849 
    850 static
    851 int
    852 ParseCommandLine (
    853   int         Argc,
    854   char        *Argv[],
    855   OPTIONS     *Options
    856   )
    857 /*++
    858 
    859 Routine Description:
    860 
    861   Given the Argc/Argv program arguments, and a pointer to an options structure,
    862   parse the command-line options and check their validity.
    863 
    864 
    865 Arguments:
    866 
    867   Argc            - standard C main() argument count
    868   Argv[]          - standard C main() argument list
    869   Options         - pointer to a structure to store the options in
    870 
    871 Returns:
    872 
    873   STATUS_SUCCESS    success
    874   non-zero          otherwise
    875 
    876 --*/
    877 {
    878   FILE_LIST *FileList;
    879   FILE_LIST *PrevFileList;
    880   UINT32    FileFlags;
    881   UINT32    ClassCode;
    882   UINT32    CodeRevision;
    883   EFI_STATUS Status;
    884   BOOLEAN    EfiRomFlag;
    885   UINT64     TempValue;
    886 
    887   FileFlags = 0;
    888   EfiRomFlag = FALSE;
    889 
    890   //
    891   // Clear out the options
    892   //
    893   memset ((char *) Options, 0, sizeof (OPTIONS));
    894 
    895   //
    896   // To avoid compile warnings
    897   //
    898   FileList                = PrevFileList = NULL;
    899 
    900   ClassCode               = 0;
    901   CodeRevision            = 0;
    902   //
    903   // Skip over the program name
    904   //
    905   Argc--;
    906   Argv++;
    907 
    908   //
    909   // If no arguments, assume they want usage info
    910   //
    911   if (Argc == 0) {
    912     Usage ();
    913     return STATUS_ERROR;
    914   }
    915 
    916   if ((stricmp(Argv[0], "-h") == 0) || (stricmp(Argv[0], "--help") == 0)) {
    917     Usage();
    918     return STATUS_ERROR;
    919   }
    920 
    921   if ((stricmp(Argv[0], "--version") == 0)) {
    922     Version();
    923     return STATUS_ERROR;
    924   }
    925 
    926   //
    927   // Process until no more arguments
    928   //
    929   while (Argc > 0) {
    930     if (Argv[0][0] == '-') {
    931       //
    932       // Vendor ID specified with -f
    933       //
    934       if (stricmp (Argv[0], "-f") == 0) {
    935         //
    936         // Make sure there's another parameter
    937         //
    938         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
    939         if (EFI_ERROR (Status)) {
    940           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
    941           return 1;
    942         }
    943         if (TempValue >= 0x10000) {
    944           Error (NULL, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv[1]);
    945           return 1;
    946         }
    947         Options->VendId       = (UINT16) TempValue;
    948         Options->VendIdValid  = 1;
    949 
    950         Argv++;
    951         Argc--;
    952       } else if (stricmp (Argv[0], "-i") == 0) {
    953         //
    954         // Device ID specified with -i
    955         // Make sure there's another parameter
    956         //
    957         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
    958         if (EFI_ERROR (Status)) {
    959           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
    960           return 1;
    961         }
    962         if (TempValue >= 0x10000) {
    963           Error (NULL, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv[1]);
    964           return 1;
    965         }
    966         Options->DevId      = (UINT16) TempValue;
    967         Options->DevIdValid = 1;
    968 
    969         Argv++;
    970         Argc--;
    971       } else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {
    972         //
    973         // Output filename specified with -o
    974         // Make sure there's another parameter
    975         //
    976         if (Argv[1] == NULL || Argv[1][0] == '-') {
    977           Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv[0]);
    978           return STATUS_ERROR;
    979         }
    980         strcpy (Options->OutFileName, Argv[1]);
    981 
    982         Argv++;
    983         Argc--;
    984       } else if ((stricmp (Argv[0], "-h") == 0) || (stricmp (Argv[0], "--help") == 0)) {
    985         //
    986         // Help option
    987         //
    988         Usage ();
    989         return STATUS_ERROR;
    990       } else if (stricmp (Argv[0], "-b") == 0) {
    991         //
    992         // Specify binary files with -b
    993         //
    994         FileFlags = FILE_FLAG_BINARY;
    995       } else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) {
    996         //
    997         // Specify EFI files with -e. Specify EFI-compressed with -c.
    998         //
    999         FileFlags = FILE_FLAG_EFI;
   1000         if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {
   1001           FileFlags |= FILE_FLAG_COMPRESS;
   1002         }
   1003         //
   1004         // Specify not to set the LAST bit in the last file with -n
   1005         //
   1006       } else if (stricmp (Argv[0], "-n") == 0) {
   1007         Options->NoLast = 1;
   1008       } else if (((stricmp (Argv[0], "-v") == 0)) || ((stricmp (Argv[0], "--verbose") == 0))) {
   1009         //
   1010         // -v for verbose
   1011         //
   1012         Options->Verbose = 1;
   1013       } else if (stricmp (Argv[0], "--debug") == 0) {
   1014         Status = AsciiStringToUint64(Argv[1], FALSE, &DebugLevel);
   1015         if (EFI_ERROR (Status)) {
   1016           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
   1017           return 1;
   1018         }
   1019         if (DebugLevel > 9)  {
   1020           Error (NULL, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv[1]);
   1021           return 1;
   1022         }
   1023         if (DebugLevel>=5 && DebugLevel<=9) {
   1024           Options->Debug = TRUE;
   1025         } else {
   1026           Options->Debug = FALSE;
   1027         }
   1028         Argv++;
   1029         Argc--;
   1030       } else if ((stricmp (Argv[0], "--quiet") == 0) || (stricmp (Argv[0], "-q") == 0)) {
   1031         Options->Quiet = TRUE;
   1032       } else if ((stricmp (Argv[0], "--dump") == 0) || (stricmp (Argv[0], "-d") == 0)) {
   1033         //
   1034         // -dump for dumping a ROM image. In this case, say that the device id
   1035         // and vendor id are valid so we don't have to specify bogus ones on the
   1036         // command line.
   1037         //
   1038         Options->DumpOption   = 1;
   1039 
   1040         Options->VendIdValid  = 1;
   1041         Options->DevIdValid   = 1;
   1042         FileFlags             = FILE_FLAG_BINARY;
   1043       } else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {
   1044         //
   1045         // Class code value for the next file in the list.
   1046         // Make sure there's another parameter
   1047         //
   1048         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
   1049         if (EFI_ERROR (Status)) {
   1050           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
   1051           return 1;
   1052         }
   1053         ClassCode = (UINT32) TempValue;
   1054         if (ClassCode & 0xFF000000) {
   1055           Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv[1]);
   1056           return STATUS_ERROR;
   1057         }
   1058         if (FileList != NULL && FileList->ClassCode == 0) {
   1059           FileList->ClassCode = ClassCode;
   1060         }
   1061         Argv++;
   1062         Argc--;
   1063       } else if ((stricmp (Argv[0], "-r") == 0) || (stricmp (Argv[0], "--Revision") == 0)) {
   1064         //
   1065         // Code revision in the PCI data structure. The value is for the next
   1066         // file in the list.
   1067         // Make sure there's another parameter
   1068         //
   1069         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);
   1070         if (EFI_ERROR (Status)) {
   1071           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);
   1072           return 1;
   1073         }
   1074         CodeRevision = (UINT32) TempValue;
   1075         if (CodeRevision & 0xFFFF0000) {
   1076           Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv[1]);
   1077           return STATUS_ERROR;
   1078         }
   1079         if (FileList != NULL && FileList->CodeRevision == 0) {
   1080           FileList->CodeRevision = (UINT16) CodeRevision;
   1081         }
   1082         Argv++;
   1083         Argc--;
   1084       } else if ((stricmp (Argv[0], "-p") == 0) || (stricmp (Argv[0], "--pci23") == 0)) {
   1085         //
   1086         // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
   1087         //
   1088         mOptions.Pci23 = 1;
   1089       } else {
   1090         Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);
   1091         return STATUS_ERROR;
   1092       }
   1093     } else {
   1094       //
   1095       // Not a slash-option argument. Must be a file name. Make sure they've specified
   1096       // -e or -b already.
   1097       //
   1098       if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {
   1099         Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv[0]);
   1100         return STATUS_ERROR;
   1101       }
   1102       //
   1103       // Check Efi Option RomImage
   1104       //
   1105       if ((FileFlags & FILE_FLAG_EFI) == FILE_FLAG_EFI) {
   1106         EfiRomFlag = TRUE;
   1107       }
   1108       //
   1109       // Create a new file structure
   1110       //
   1111       FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));
   1112       if (FileList == NULL) {
   1113         Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);
   1114         return STATUS_ERROR;
   1115       }
   1116 
   1117       //
   1118       // set flag and class code for this image.
   1119       //
   1120       memset ((char *) FileList, 0, sizeof (FILE_LIST));
   1121       FileList->FileName      = Argv[0];
   1122       FileList->FileFlags     = FileFlags;
   1123       FileList->ClassCode     = ClassCode;
   1124       FileList->CodeRevision  = (UINT16) CodeRevision;
   1125       ClassCode               = 0;
   1126       CodeRevision            = 0;
   1127 
   1128       if (Options->FileList == NULL) {
   1129         Options->FileList = FileList;
   1130       } else {
   1131         if (PrevFileList == NULL) {
   1132           PrevFileList = FileList;
   1133         } else {
   1134           PrevFileList->Next = FileList;
   1135         }
   1136       }
   1137 
   1138       PrevFileList = FileList;
   1139     }
   1140     //
   1141     // Next argument
   1142     //
   1143     Argv++;
   1144     Argc--;
   1145   }
   1146 
   1147   //
   1148   // Must have specified some files
   1149   //
   1150   if (Options->FileList == NULL) {
   1151     Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name!");
   1152     return STATUS_ERROR;
   1153   }
   1154 
   1155   //
   1156   // For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.
   1157   //
   1158   if (EfiRomFlag) {
   1159     if (!Options->VendIdValid) {
   1160       Error (NULL, 0, 2000, "Missing Vendor ID in command line", NULL);
   1161       return STATUS_ERROR;
   1162     }
   1163 
   1164     if (!Options->DevIdValid) {
   1165       Error (NULL, 0, 2000, "Missing Device ID in command line", NULL);
   1166       return STATUS_ERROR;
   1167     }
   1168   }
   1169 
   1170   return 0;
   1171 }
   1172 
   1173 static
   1174 void
   1175 Version (
   1176   VOID
   1177   )
   1178 /*++
   1179 
   1180 Routine Description:
   1181 
   1182   Print version information for this utility.
   1183 
   1184 Arguments:
   1185 
   1186   None.
   1187 
   1188 Returns:
   1189 
   1190   Nothing.
   1191 --*/
   1192 {
   1193  fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
   1194 }
   1195 
   1196 static
   1197 void
   1198 Usage (
   1199   VOID
   1200   )
   1201 /*++
   1202 
   1203 Routine Description:
   1204 
   1205   Print usage information for this utility.
   1206 
   1207 Arguments:
   1208 
   1209   None.
   1210 
   1211 Returns:
   1212 
   1213   Nothing.
   1214 
   1215 --*/
   1216 {
   1217   //
   1218   // Summary usage
   1219   //
   1220   fprintf (stdout, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME);
   1221 
   1222   //
   1223   // Copyright declaration
   1224   //
   1225   fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");
   1226 
   1227   //
   1228   // Details Option
   1229   //
   1230   fprintf (stdout, "Options:\n");
   1231   fprintf (stdout, "  -o FileName, --output FileName\n\
   1232             File will be created to store the output content.\n");
   1233   fprintf (stdout, "  -e EfiFileName\n\
   1234             EFI PE32 image files.\n");
   1235   fprintf (stdout, "  -ec EfiFileName\n\
   1236             EFI PE32 image files and will be compressed.\n");
   1237   fprintf (stdout, "  -b BinFileName\n\
   1238             Legacy binary files.\n");
   1239   fprintf (stdout, "  -l ClassCode\n\
   1240             Hex ClassCode in the PCI data structure header.\n");
   1241   fprintf (stdout, "  -r Rev    Hex Revision in the PCI data structure header.\n");
   1242   fprintf (stdout, "  -n        Not to automatically set the LAST bit in the last file.\n");
   1243   fprintf (stdout, "  -f VendorId\n\
   1244             Hex PCI Vendor ID for the device OpROM, must be specified\n");
   1245   fprintf (stdout, "  -i DeviceId\n\
   1246             Hex PCI Device ID for the device OpROM, must be specified\n");
   1247   fprintf (stdout, "  -p, --pci23\n\
   1248             Default layout meets PCI 3.0 specifications\n\
   1249             specifying this flag will for a PCI 2.3 layout.\n");
   1250   fprintf (stdout, "  -d, --dump\n\
   1251             Dump the headers of an existing option ROM image.\n");
   1252   fprintf (stdout, "  -v, --verbose\n\
   1253             Turn on verbose output with informational messages.\n");
   1254   fprintf (stdout, "  --version Show program's version number and exit.\n");
   1255   fprintf (stdout, "  -h, --help\n\
   1256             Show this help message and exit.\n");
   1257   fprintf (stdout, "  -q, --quiet\n\
   1258             Disable all messages except FATAL ERRORS.\n");
   1259   fprintf (stdout, "  --debug [#,0-9]\n\
   1260             Enable debug messages at level #.\n");
   1261 }
   1262 
   1263 static
   1264 void
   1265 DumpImage (
   1266   FILE_LIST *InFile
   1267   )
   1268 /*++
   1269 
   1270 Routine Description:
   1271 
   1272   Dump the headers of an existing option ROM image
   1273 
   1274 Arguments:
   1275 
   1276   InFile  - the file name of an existing option ROM image
   1277 
   1278 Returns:
   1279 
   1280   none
   1281 
   1282 --*/
   1283 {
   1284   PCI_EXPANSION_ROM_HEADER      PciRomHdr;
   1285   FILE                          *InFptr;
   1286   UINT32                        ImageStart;
   1287   UINT32                        ImageCount;
   1288   EFI_PCI_EXPANSION_ROM_HEADER  EfiRomHdr;
   1289   PCI_DATA_STRUCTURE            PciDs23;
   1290   PCI_3_0_DATA_STRUCTURE        PciDs30;
   1291 
   1292   //
   1293   // Open the input file
   1294   //
   1295   if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {
   1296     Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
   1297     return ;
   1298   }
   1299   //
   1300   // Go through the image and dump the header stuff for each
   1301   //
   1302   ImageCount = 0;
   1303   for (;;) {
   1304     //
   1305     // Save our postition in the file, since offsets in the headers
   1306     // are relative to the particular image.
   1307     //
   1308     ImageStart = ftell (InFptr);
   1309     ImageCount++;
   1310 
   1311     //
   1312     // Read the option ROM header. Have to assume a raw binary image for now.
   1313     //
   1314     if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {
   1315       Error (NULL, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");
   1316       goto BailOut;
   1317     }
   1318 
   1319     //
   1320     // Dump the contents of the header
   1321     //
   1322     fprintf (stdout, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount, (unsigned) ImageStart);
   1323     fprintf (stdout, "  ROM header contents\n");
   1324     fprintf (stdout, "    Signature              0x%04X\n", PciRomHdr.Signature);
   1325     fprintf (stdout, "    PCIR offset            0x%04X\n", PciRomHdr.PcirOffset);
   1326     //
   1327     // Find PCI data structure
   1328     //
   1329     if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {
   1330       Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");
   1331       goto BailOut;
   1332     }
   1333     //
   1334     // Read and dump the PCI data structure
   1335     //
   1336     memset (&PciDs23, 0, sizeof (PciDs23));
   1337     memset (&PciDs30, 0, sizeof (PciDs30));
   1338     if (mOptions.Pci23 == 1) {
   1339       if (fread (&PciDs23, sizeof (PciDs23), 1, InFptr) != 1) {
   1340         Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);
   1341         goto BailOut;
   1342       }
   1343     } else {
   1344       if (fread (&PciDs30, sizeof (PciDs30), 1, InFptr) != 1) {
   1345         Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);
   1346         goto BailOut;
   1347       }
   1348     }
   1349     if (mOptions.Verbose) {
   1350       VerboseMsg("Read PCI data structure from file %s", InFile->FileName);
   1351     }
   1352 
   1353     //fprintf (stdout, "  PCI Data Structure\n");
   1354     if (mOptions.Pci23 == 1) {
   1355     fprintf (
   1356       stdout,
   1357       "    Signature              %c%c%c%c\n",
   1358       (char) PciDs23.Signature,
   1359       (char) (PciDs23.Signature >> 8),
   1360       (char) (PciDs23.Signature >> 16),
   1361       (char) (PciDs23.Signature >> 24)
   1362       );
   1363     fprintf (stdout, "    Vendor ID              0x%04X\n", PciDs23.VendorId);
   1364     fprintf (stdout, "    Device ID              0x%04X\n", PciDs23.DeviceId);
   1365     fprintf (stdout, "    Length                 0x%04X\n", PciDs23.Length);
   1366     fprintf (stdout, "    Revision               0x%04X\n", PciDs23.Revision);
   1367     fprintf (
   1368       stdout,
   1369       "    Class Code             0x%06X\n",
   1370       (unsigned) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))
   1371       );
   1372     fprintf (stdout, "    Image size             0x%X\n", (unsigned) PciDs23.ImageLength * 512);
   1373     fprintf (stdout, "    Code revision:         0x%04X\n", PciDs23.CodeRevision);
   1374     fprintf (stdout, "    Indicator              0x%02X", PciDs23.Indicator);
   1375     } else {
   1376     fprintf (
   1377       stdout,
   1378       "    Signature               %c%c%c%c\n",
   1379       (char) PciDs30.Signature,
   1380       (char) (PciDs30.Signature >> 8),
   1381       (char) (PciDs30.Signature >> 16),
   1382       (char) (PciDs30.Signature >> 24)
   1383       );
   1384     fprintf (stdout, "    Vendor ID               0x%04X\n", PciDs30.VendorId);
   1385     fprintf (stdout, "    Device ID               0x%04X\n", PciDs30.DeviceId);
   1386     fprintf (stdout, "    Length                  0x%04X\n", PciDs30.Length);
   1387     fprintf (stdout, "    Revision                0x%04X\n", PciDs30.Revision);
   1388     fprintf (stdout, "    DeviceListOffset        0x%02X\n", PciDs30.DeviceListOffset);
   1389     fprintf (
   1390       stdout,
   1391       "    Class Code              0x%06X\n",
   1392       (unsigned) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))
   1393       );
   1394     fprintf (stdout, "    Image size              0x%X\n", (unsigned) PciDs30.ImageLength * 512);
   1395     fprintf (stdout, "    Code revision:          0x%04X\n", PciDs30.CodeRevision);
   1396     fprintf (stdout, "    MaxRuntimeImageLength   0x%02X\n", PciDs30.MaxRuntimeImageLength);
   1397     fprintf (stdout, "    ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30.ConfigUtilityCodeHeaderOffset);
   1398     fprintf (stdout, "    DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset);
   1399     fprintf (stdout, "    Indicator               0x%02X", PciDs30.Indicator);
   1400     }
   1401     //
   1402     // Print the indicator, used to flag the last image
   1403     //
   1404     if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
   1405       fprintf (stdout, "   (last image)\n");
   1406     } else {
   1407       fprintf (stdout, "\n");
   1408     }
   1409     //
   1410     // Print the code type. If EFI code, then we can provide more info.
   1411     //
   1412     if (mOptions.Pci23 == 1) {
   1413       fprintf (stdout, "    Code type              0x%02X", PciDs23.CodeType);
   1414     } else {
   1415       fprintf (stdout, "    Code type               0x%02X", PciDs30.CodeType);
   1416     }
   1417     if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
   1418       fprintf (stdout, "   (EFI image)\n");
   1419       //
   1420       // Re-read the header as an EFI ROM header, then dump more info
   1421       //
   1422       fprintf (stdout, "  EFI ROM header contents\n");
   1423       if (fseek (InFptr, ImageStart, SEEK_SET)) {
   1424         Error (NULL, 0, 5001, "Failed to re-seek to ROM header structure!", NULL);
   1425         goto BailOut;
   1426       }
   1427 
   1428       if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {
   1429         Error (NULL, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL);
   1430         goto BailOut;
   1431       }
   1432       //
   1433       // Now dump more info
   1434       //
   1435       fprintf (stdout, "    EFI Signature          0x%04X\n", (unsigned) EfiRomHdr.EfiSignature);
   1436       fprintf (
   1437         stdout,
   1438         "    Compression Type       0x%04X ",
   1439         EfiRomHdr.CompressionType
   1440         );
   1441       if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
   1442         fprintf (stdout, "(compressed)\n");
   1443       } else {
   1444         fprintf (stdout, "(not compressed)\n");
   1445       }
   1446 
   1447       fprintf (
   1448         stdout,
   1449         "    Machine type           0x%04X (%s)\n",
   1450         EfiRomHdr.EfiMachineType,
   1451         GetMachineTypeStr (EfiRomHdr.EfiMachineType)
   1452         );
   1453       fprintf (
   1454         stdout,
   1455         "    Subsystem              0x%04X (%s)\n",
   1456         EfiRomHdr.EfiSubsystem,
   1457         GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)
   1458         );
   1459       fprintf (
   1460         stdout,
   1461         "    EFI image offset       0x%04X (@0x%X)\n",
   1462         EfiRomHdr.EfiImageHeaderOffset,
   1463         EfiRomHdr.EfiImageHeaderOffset + (unsigned) ImageStart
   1464         );
   1465 
   1466     } else {
   1467       //
   1468       // Not an EFI image
   1469       //
   1470       fprintf (stdout, "\n");
   1471     }
   1472     //
   1473     // If code type is EFI image, then dump it as well?
   1474     //
   1475     // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
   1476     // }
   1477     //
   1478     // If last image, then we're done
   1479     //
   1480     if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
   1481       goto BailOut;
   1482     }
   1483     //
   1484     // Seek to the start of the next image
   1485     //
   1486     if (mOptions.Pci23 == 1) {
   1487       if (fseek (InFptr, ImageStart + (PciDs23.ImageLength * 512), SEEK_SET)) {
   1488         Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");
   1489         goto BailOut;
   1490       }
   1491     } else {
   1492       if (fseek (InFptr, ImageStart + (PciDs30.ImageLength * 512), SEEK_SET)) {
   1493         Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");
   1494         goto BailOut;
   1495       }
   1496     }
   1497   }
   1498 
   1499 BailOut:
   1500   fclose (InFptr);
   1501 }
   1502 
   1503 char *
   1504 GetMachineTypeStr (
   1505   UINT16    MachineType
   1506   )
   1507 /*++
   1508 
   1509 Routine Description:
   1510 
   1511   GC_TODO: Add function description
   1512 
   1513 Arguments:
   1514 
   1515   MachineType - GC_TODO: add argument description
   1516 
   1517 Returns:
   1518 
   1519   GC_TODO: add return values
   1520 
   1521 --*/
   1522 {
   1523   int Index;
   1524 
   1525   for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {
   1526     if (mMachineTypes[Index].Value == MachineType) {
   1527       return mMachineTypes[Index].Name;
   1528     }
   1529   }
   1530 
   1531   return "unknown";
   1532 }
   1533 
   1534 static
   1535 char *
   1536 GetSubsystemTypeStr (
   1537   UINT16  SubsystemType
   1538   )
   1539 /*++
   1540 
   1541 Routine Description:
   1542 
   1543   GC_TODO: Add function description
   1544 
   1545 Arguments:
   1546 
   1547   SubsystemType - GC_TODO: add argument description
   1548 
   1549 Returns:
   1550 
   1551   GC_TODO: add return values
   1552 
   1553 --*/
   1554 {
   1555   int Index;
   1556 
   1557   for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {
   1558     if (mSubsystemTypes[Index].Value == SubsystemType) {
   1559       return mSubsystemTypes[Index].Name;
   1560     }
   1561   }
   1562 
   1563   return "unknown";
   1564 }
   1565