]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/EfiRom/EfiRom.c
Sync BaseTool trunk (version r2460) into EDKII BaseTools. The change mainly includes:
[mirror_edk2.git] / BaseTools / Source / C / EfiRom / EfiRom.c
CommitLineData
30fdf114
LG
1/** @file\r
2\r
d0acc87a 3Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR>\r
30fdf114
LG
4This program and the accompanying materials are licensed and made available \r
5under the terms and conditions of the BSD License which accompanies this \r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 EfiRom.c\r
15 \r
16Abstract:\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
27UINT64 DebugLevel = 0;\r
28\r
29int\r
30main (\r
31 int Argc,\r
32 char *Argv[]\r
33 )\r
34/*++\r
35\r
36Routine 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
42Arguments:\r
43\r
44 Argc - standard C main() argument count\r
45\r
46 Argv - standard C main() argument list\r
47\r
48Returns:\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
fd171542 91 if (mOptions.FileList != NULL) {\r
92 if ((Ptr0 = strstr ((CONST CHAR8 *) mOptions.FileList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {\r
30fdf114
LG
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
fd171542 166 VerboseMsg(" Output size = 0x%X\n", (unsigned) Size);\r
30fdf114
LG
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
183BailOut:\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
205static\r
206int\r
207ProcessBinFile (\r
208 FILE *OutFptr,\r
209 FILE_LIST *InFile,\r
210 UINT32 *Size\r
211 )\r
212/*++\r
213\r
214Routine Description:\r
215 \r
216 Process a binary input file.\r
217\r
218Arguments:\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
224Returns:\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
fd171542 241 PciDs23 = NULL;\r
242 PciDs30 = NULL;\r
30fdf114
LG
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
fd171542 259 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);\r
30fdf114
LG
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
fd171542 369 VerboseMsg(" Checksum = %02x\n\n", Buffer[FileSize - 1]);\r
30fdf114
LG
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
390BailOut:\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
408static\r
409int\r
410ProcessEfiFile (\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
419Routine Description:\r
420 \r
421 Process a PE32 EFI file.\r
422\r
423Arguments:\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
431Returns:\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
fd171542 499 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);\r
30fdf114
LG
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
fd171542 544 VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize);\r
30fdf114
LG
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
717BailOut:\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
741static\r
742int\r
743CheckPE32File (\r
744 FILE *Fptr,\r
745 UINT16 *MachineType,\r
746 UINT16 *SubSystem\r
747 )\r
748/*++\r
749\r
750Routine 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
755Arguments:\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
761Returns:\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
fd171542 824 VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem);\r
30fdf114
LG
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
833static\r
834int\r
835ParseCommandLine (\r
836 int Argc,\r
837 char *Argv[],\r
838 OPTIONS *Options\r
839 )\r
840/*++\r
841\r
842Routine 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
848Arguments:\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
854Returns:\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
fd171542 1003 Error (NULL, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv[1]);\r
30fdf114
LG
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
1156static\r
1157void\r
1158Version (\r
1159 VOID\r
1160 )\r
1161/*++\r
1162\r
1163Routine Description:\r
1164 \r
1165 Print version information for this utility.\r
1166\r
1167Arguments:\r
1168\r
1169 None.\r
1170\r
1171Returns:\r
1172\r
1173 Nothing.\r
1174--*/\r
1175{\r
b36d134f 1176 fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
30fdf114
LG
1177}\r
1178 \r
1179static\r
1180void\r
1181Usage (\r
1182 VOID\r
1183 )\r
1184/*++\r
1185\r
1186Routine Description:\r
1187 \r
1188 Print usage information for this utility.\r
1189\r
1190Arguments:\r
1191\r
1192 None.\r
1193\r
1194Returns:\r
1195\r
1196 Nothing.\r
1197\r
1198--*/\r
1199{\r
1200 //\r
1201 // Summary usage\r
1202 //\r
d0acc87a 1203 fprintf (stdout, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME);\r
30fdf114
LG
1204 \r
1205 //\r
1206 // Copyright declaration\r
1207 // \r
d0acc87a 1208 fprintf (stdout, "Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.\n\n");\r
30fdf114
LG
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
d0acc87a 1215 File will be created to store the output content.\n");\r
30fdf114
LG
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
d0acc87a 1227 Hex PCI Vendor ID for the device OpROM, must be specified\n");\r
30fdf114 1228 fprintf (stdout, " -i DeviceId\n\\r
d0acc87a 1229 Hex PCI Device ID for the device OpROM, must be specified\n");\r
30fdf114
LG
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
1246static\r
1247void\r
1248DumpImage (\r
1249 FILE_LIST *InFile\r
1250 )\r
1251/*++\r
1252\r
1253Routine Description:\r
1254\r
1255 Dump the headers of an existing option ROM image\r
1256\r
1257Arguments:\r
1258\r
1259 InFile - the file name of an existing option ROM image\r
1260\r
1261Returns:\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
fd171542 1305 fprintf (stdout, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount, (unsigned) ImageStart);\r
30fdf114 1306 fprintf (stdout, " ROM header contents\n");\r
fd171542 1307 fprintf (stdout, " Signature 0x%04X\n", PciRomHdr.Signature);\r
1308 fprintf (stdout, " PCIR offset 0x%04X\n", PciRomHdr.PcirOffset);\r
30fdf114
LG
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
fd171542 1353 (unsigned) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))\r
30fdf114 1354 );\r
fd171542 1355 fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs23.ImageLength * 512);\r
30fdf114 1356 fprintf (stdout, " Code revision: 0x%04X\n", PciDs23.CodeRevision);\r
fd171542 1357 fprintf (stdout, " Indicator 0x%02X", PciDs23.Indicator);\r
30fdf114
LG
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
fd171542 1371 fprintf (stdout, " DeviceListOffset 0x%02X\n", PciDs30.DeviceListOffset); \r
30fdf114
LG
1372 fprintf (\r
1373 stdout,\r
1374 " Class Code 0x%06X\n",\r
fd171542 1375 (unsigned) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))\r
30fdf114 1376 );\r
fd171542 1377 fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs30.ImageLength * 512);\r
30fdf114 1378 fprintf (stdout, " Code revision: 0x%04X\n", PciDs30.CodeRevision);\r
fd171542 1379 fprintf (stdout, " MaxRuntimeImageLength 0x%02X\n", PciDs30.MaxRuntimeImageLength);\r
1380 fprintf (stdout, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30.ConfigUtilityCodeHeaderOffset);\r
1381 fprintf (stdout, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset); \r
1382 fprintf (stdout, " Indicator 0x%02X", PciDs30.Indicator); \r
30fdf114
LG
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
fd171542 1396 fprintf (stdout, " Code type 0x%02X", PciDs23.CodeType);\r
30fdf114 1397 } else {\r
fd171542 1398 fprintf (stdout, " Code type 0x%02X", PciDs30.CodeType); \r
30fdf114
LG
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
fd171542 1418 fprintf (stdout, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr.EfiSignature);\r
30fdf114
LG
1419 fprintf (\r
1420 stdout,\r
1421 " Compression Type 0x%04X ",\r
fd171542 1422 EfiRomHdr.CompressionType\r
30fdf114
LG
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
fd171542 1445 EfiRomHdr.EfiImageHeaderOffset,\r
1446 EfiRomHdr.EfiImageHeaderOffset + (unsigned) ImageStart\r
30fdf114
LG
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
1482BailOut:\r
1483 fclose (InFptr);\r
1484}\r
1485\r
1486char *\r
1487GetMachineTypeStr (\r
1488 UINT16 MachineType\r
1489 )\r
1490/*++\r
1491\r
1492Routine Description:\r
1493\r
1494 GC_TODO: Add function description\r
1495\r
1496Arguments:\r
1497\r
1498 MachineType - GC_TODO: add argument description\r
1499\r
1500Returns:\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
1517static\r
1518char *\r
1519GetSubsystemTypeStr (\r
1520 UINT16 SubsystemType\r
1521 )\r
1522/*++\r
1523\r
1524Routine Description:\r
1525\r
1526 GC_TODO: Add function description\r
1527\r
1528Arguments:\r
1529\r
1530 SubsystemType - GC_TODO: add argument description\r
1531\r
1532Returns:\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