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