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