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