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