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