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