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