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