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