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