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