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