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