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