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