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