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