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