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