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