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