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