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