3 Copyright (c) 1999-2008 Intel Corporation. All rights reserved
\r
4 This program and the accompanying materials are licensed and made available
\r
5 under the terms and conditions of the BSD License which accompanies this
\r
6 distribution. The full text of the license may be found at
\r
7 http://opensource.org/licenses/bsd-license.php
\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
\r
18 Utility program to create an EFI option ROM image from binary and
\r
31 Routine Description:
\r
33 Given an EFI image filename, create a ROM-able image by creating an option
\r
34 ROM header and PCI data structure, filling them in, and then writing the
\r
35 option ROM header + PCI data structure + EFI image out to the output file.
\r
39 Argc - standard C main() argument count
\r
41 Argv - standard C main() argument list
\r
58 SetUtilityName(UTILITY_NAME);
\r
60 Status = STATUS_SUCCESS;
\r
64 // Parse the command line arguments
\r
66 if (ParseCommandLine (Argc, Argv, &mOptions)) {
\r
67 return STATUS_ERROR;
\r
70 if (mOptions.Quiet) {
\r
72 } else if (mOptions.Verbose) {
\r
74 } else if (mOptions.Debug) {
\r
75 SetPrintLevel(DebugLevel);
\r
78 if (mOptions.Verbose) {
\r
79 VerboseMsg("%s tool start.\n", UTILITY_NAME);
\r
82 if (mOptions.FileList == NULL) {
\r
83 Error (NULL, 0, 1002, "No input file", NULL);
\r
87 // If dumping an image, then do that and quit
\r
89 if (mOptions.DumpOption == 1) {
\r
90 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
\r
91 if ((Ptr0 = strstr ((CONST CHAR8 *)FList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {
\r
92 DumpImage (mOptions.FileList);
\r
95 Error (NULL, 0, 1002, "No PciRom input file", "No *.rom input file");
\r
101 // Determine the output filename. Either what they specified on
\r
102 // the command line, or the first input filename with a different extension.
\r
104 if (!mOptions.OutFileName[0]) {
\r
105 strcpy (mOptions.OutFileName, mOptions.FileList->FileName);
\r
107 // Find the last . on the line and replace the filename extension with
\r
110 for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;
\r
111 (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');
\r
116 // If dot here, then insert extension here, otherwise append
\r
119 Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);
\r
122 strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);
\r
125 // Make sure we don't have the same filename for input and output files
\r
127 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
\r
128 if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {
\r
129 Status = STATUS_ERROR;
\r
130 Error (NULL, 0, 1002, "Invalid input paramter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);
\r
135 // Now open our output file
\r
137 if ((FptrOut = fopen (mOptions.OutFileName, "wb")) == NULL) {
\r
138 Error (stdout, 0, 0001, "Error opening file", mOptions.OutFileName);
\r
142 // Process all our files
\r
145 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
\r
147 if ((FList->FileFlags & FILE_FLAG_EFI) != 0) {
\r
148 if (mOptions.Verbose) {
\r
149 VerboseMsg("Processing EFI file %s\n", FList->FileName);
\r
152 Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);
\r
153 } else if ((FList->FileFlags & FILE_FLAG_BINARY) !=0 ) {
\r
154 if (mOptions.Verbose) {
\r
155 VerboseMsg("Processing binary file %s\n", FList->FileName);
\r
158 Status = ProcessBinFile (FptrOut, FList, &Size);
\r
160 Error (stdout, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList->FileName);
\r
161 Status = STATUS_ERROR;
\r
164 if (mOptions.Verbose) {
\r
165 VerboseMsg(" Output size = 0x%X\n", Size);
\r
168 if (Status != STATUS_SUCCESS) {
\r
175 // Check total size
\r
177 if (TotalSize > MAX_OPTION_ROM_SIZE) {
\r
178 Error (NULL, 0, 2000, "Invalid paramter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);
\r
179 Status = STATUS_ERROR;
\r
183 if (Status == STATUS_SUCCESS) {
\r
184 if (FptrOut != NULL) {
\r
188 // Clean up our file list
\r
190 while (mOptions.FileList != NULL) {
\r
191 FList = mOptions.FileList->Next;
\r
192 free (mOptions.FileList);
\r
193 mOptions.FileList = FList;
\r
197 if (mOptions.Verbose) {
\r
198 VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());
\r
201 return GetUtilityStatus ();
\r
213 Routine Description:
\r
215 Process a binary input file.
\r
219 OutFptr - file pointer to output binary ROM image file we're creating
\r
220 InFile - structure contains information on the binary file to process
\r
221 Size - pointer to where to return the size added to the output file
\r
234 PCI_EXPANSION_ROM_HEADER *RomHdr;
\r
235 PCI_DATA_STRUCTURE *PciDs23;
\r
236 PCI_3_0_DATA_STRUCTURE *PciDs30;
\r
238 UINT8 ByteCheckSum;
\r
241 Status = STATUS_SUCCESS;
\r
244 // Try to open the input file
\r
246 if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
\r
247 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
\r
248 return STATUS_ERROR;
\r
251 // Seek to the end of the input file and get the file size. Then allocate
\r
252 // a buffer to read it in to.
\r
254 fseek (InFptr, 0, SEEK_END);
\r
255 FileSize = ftell (InFptr);
\r
256 if (mOptions.Verbose) {
\r
257 VerboseMsg(" File size = 0x%X\n", FileSize);
\r
260 fseek (InFptr, 0, SEEK_SET);
\r
261 Buffer = (INT8 *) malloc (FileSize);
\r
262 if (Buffer == NULL) {
\r
263 Error (NULL, 0, 4003, "Resource", "memory cannot be allocated!", NULL);
\r
264 Status = STATUS_ERROR;
\r
268 if (fread (Buffer, FileSize, 1, InFptr) != 1) {
\r
269 Error (NULL, 0, 2000, "Invalid", "Failed to read all bytes from input file.");
\r
270 Status = STATUS_ERROR;
\r
274 // Total size must be an even multiple of 512 bytes, and can't exceed
\r
275 // the option ROM image size.
\r
277 TotalSize = FileSize;
\r
278 if (TotalSize & 0x1FF) {
\r
279 TotalSize = (TotalSize + 0x200) &~0x1ff;
\r
282 if (TotalSize > MAX_OPTION_ROM_SIZE) {
\r
283 Error (NULL, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);
\r
284 Status = STATUS_ERROR;
\r
288 // Return the size to the caller so they can keep track of the running total.
\r
293 // Crude check to make sure it's a legitimate ROM image
\r
295 RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;
\r
296 if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
\r
297 Error (NULL, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");
\r
298 Status = STATUS_ERROR;
\r
302 // Make sure the pointer to the PCI data structure is within the size of the image.
\r
303 // Then check it for valid signature.
\r
305 if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {
\r
306 Error (NULL, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");
\r
307 Status = STATUS_ERROR;
\r
312 // Check the header is conform to PCI2.3 or PCI3.0
\r
314 if (mOptions.Pci23 == 1) {
\r
315 PciDs23 = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);
\r
316 if (PciDs23->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
\r
317 Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
\r
318 Status = STATUS_ERROR;
\r
323 // Default setting is PCI3.0 header
\r
325 PciDs30 = (PCI_3_0_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);
\r
326 if (PciDs30->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
\r
327 Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");
\r
328 Status = STATUS_ERROR;
\r
335 // If this is the last image, then set the LAST bit unless requested not
\r
336 // to via the command-line -n argument. Otherwise, make sure you clear it.
\r
338 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
\r
339 if (mOptions.Pci23 == 1) {
\r
340 PciDs23->Indicator = INDICATOR_LAST;
\r
342 PciDs30->Indicator = INDICATOR_LAST;
\r
345 if (mOptions.Pci23 == 1) {
\r
346 PciDs23->Indicator = 0;
\r
348 PciDs30->Indicator = 0;
\r
353 for (Index = 0; Index < FileSize - 1; Index++) {
\r
354 ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);
\r
357 Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);
\r
358 if (mOptions.Verbose) {
\r
359 VerboseMsg(" Checksum = %02x\n\n", (UINT32) Buffer[FileSize - 1]);
\r
363 // Now copy the input file contents out to the output file
\r
365 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
\r
366 Error (NULL, 0, 0005, "Failed to write all file bytes to output file.");
\r
367 Status = STATUS_ERROR;
\r
371 TotalSize -= FileSize;
\r
373 // Pad the rest of the image to make it a multiple of 512 bytes
\r
375 while (TotalSize > 0) {
\r
376 putc (~0, OutFptr);
\r
381 if (InFptr != NULL) {
\r
385 if (Buffer != NULL) {
\r
389 // Print the file name if errors occurred
\r
391 if (Status != STATUS_SUCCESS) {
\r
392 Error (NULL, 0, 0003, "Error", "Error parsing file: %s", InFile->FileName);
\r
409 Routine Description:
\r
411 Process a PE32 EFI file.
\r
415 OutFptr - file pointer to output binary ROM image file we're creating
\r
416 InFile - structure contains information on the PE32 file to process
\r
417 VendId - vendor ID as required in the option ROM header
\r
418 DevId - device ID as required in the option ROM header
\r
419 Size - pointer to where to return the size added to the output file
\r
429 EFI_PCI_EXPANSION_ROM_HEADER RomHdr;
\r
430 PCI_DATA_STRUCTURE PciDs23;
\r
431 PCI_3_0_DATA_STRUCTURE PciDs30;
\r
433 UINT32 CompressedFileSize;
\r
435 UINT8 *CompressedBuffer;
\r
436 UINT8 *TempBufferPtr;
\r
439 UINT16 MachineType;
\r
441 UINT32 HeaderPadBytes;
\r
444 // Try to open the input file
\r
446 if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
\r
447 Error (NULL, 0, 0001, "Open file error", "Error opening file: %s", InFile->FileName);
\r
448 return STATUS_ERROR;
\r
451 // Initialize our buffer pointers to null.
\r
454 CompressedBuffer = NULL;
\r
457 // Double-check the file to make sure it's what we expect it to be
\r
459 Status = CheckPE32File (InFptr, &MachineType, &SubSystem);
\r
460 if (Status != STATUS_SUCCESS) {
\r
464 // Seek to the end of the input file and get the file size
\r
466 fseek (InFptr, 0, SEEK_END);
\r
467 FileSize = ftell (InFptr);
\r
470 // Get the size of the headers we're going to put in front of the image. The
\r
471 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
\r
473 if (sizeof (RomHdr) & 0x03) {
\r
474 HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);
\r
476 HeaderPadBytes = 0;
\r
480 // For Pci3.0 to use the different data structure.
\r
482 if (mOptions.Pci23 == 1) {
\r
483 HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
\r
485 HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
\r
488 if (mOptions.Verbose) {
\r
489 VerboseMsg(" File size = 0x%X\n", FileSize);
\r
492 // Allocate memory for the entire file (in case we have to compress), then
\r
493 // seek back to the beginning of the file and read it into our buffer.
\r
495 Buffer = (INT8 *) malloc (FileSize);
\r
496 if (Buffer == NULL) {
\r
497 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
\r
498 Status = STATUS_ERROR;
\r
502 fseek (InFptr, 0, SEEK_SET);
\r
503 if (fread (Buffer, FileSize, 1, InFptr) != 1) {
\r
504 Error (NULL, 0, 0004, "Error reading file", InFptr);
\r
505 Status = STATUS_ERROR;
\r
509 // Now determine the size of the final output file. It's either the header size
\r
510 // plus the file's size, or the header size plus the compressed file size.
\r
512 if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {
\r
514 // Allocate a buffer into which we can compress the image, compress it,
\r
515 // and use that size as the new size.
\r
517 CompressedBuffer = (INT8 *) malloc (FileSize);
\r
518 if (CompressedBuffer == NULL) {
\r
519 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
\r
520 Status = STATUS_ERROR;
\r
524 CompressedFileSize = FileSize;
\r
525 Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);
\r
526 if (Status != STATUS_SUCCESS) {
\r
527 Error (NULL, 0, 0007, "Error compressing file!");
\r
531 // Now compute the size, then swap buffer pointers.
\r
533 if (mOptions.Verbose) {
\r
534 VerboseMsg(" Comp size = 0x%X\n", CompressedFileSize);
\r
537 TotalSize = CompressedFileSize + HeaderSize;
\r
538 FileSize = CompressedFileSize;
\r
539 TempBufferPtr = Buffer;
\r
540 Buffer = CompressedBuffer;
\r
541 CompressedBuffer = TempBufferPtr;
\r
543 TotalSize = FileSize + HeaderSize;
\r
546 // Total size must be an even multiple of 512 bytes
\r
548 if (TotalSize & 0x1FF) {
\r
549 TotalSize = (TotalSize + 0x200) &~0x1ff;
\r
554 if (TotalSize > MAX_OPTION_ROM_SIZE) {
\r
555 Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);
\r
556 Status = STATUS_ERROR;
\r
560 // Return the size to the caller so they can keep track of the running total.
\r
565 // Now fill in the ROM header. These values come from chapter 18 of the
\r
566 // EFI 1.02 specification.
\r
568 memset (&RomHdr, 0, sizeof (RomHdr));
\r
569 RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
\r
570 RomHdr.InitializationSize = (UINT16) (TotalSize / 512);
\r
571 RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
\r
572 RomHdr.EfiSubsystem = SubSystem;
\r
573 RomHdr.EfiMachineType = MachineType;
\r
574 RomHdr.EfiImageHeaderOffset = (UINT16) HeaderSize;
\r
575 RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);
\r
577 // Set image as compressed or not
\r
579 if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
\r
580 RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;
\r
583 // Fill in the PCI data structure
\r
585 if (mOptions.Pci23 == 1) {
\r
586 memset (&PciDs23, 0, sizeof (PCI_DATA_STRUCTURE));
\r
588 memset (&PciDs30, 0, sizeof (PCI_3_0_DATA_STRUCTURE));
\r
591 if (mOptions.Pci23 == 1) {
\r
592 PciDs23.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
\r
593 PciDs23.VendorId = VendId;
\r
594 PciDs23.DeviceId = DevId;
\r
595 PciDs23.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);
\r
596 PciDs23.Revision = 0;
\r
598 // Class code and code revision from the command line (optional)
\r
600 PciDs23.ClassCode[0] = (UINT8) InFile->ClassCode;
\r
601 PciDs23.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);
\r
602 PciDs23.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);
\r
603 PciDs23.ImageLength = RomHdr.InitializationSize;
\r
604 PciDs23.CodeRevision = InFile->CodeRevision;
\r
605 PciDs23.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
\r
607 PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
\r
608 PciDs30.VendorId = VendId;
\r
609 PciDs30.DeviceId = DevId;
\r
610 PciDs30.DeviceListOffset = 0; // to be fixed
\r
611 PciDs30.Length = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);
\r
612 PciDs30.Revision = 0;
\r
614 // Class code and code revision from the command line (optional)
\r
616 PciDs30.ClassCode[0] = (UINT8) InFile->ClassCode;
\r
617 PciDs30.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);
\r
618 PciDs30.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);
\r
619 PciDs30.ImageLength = RomHdr.InitializationSize;
\r
620 PciDs30.CodeRevision = InFile->CodeRevision;
\r
621 PciDs30.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
\r
622 PciDs30.MaxRuntimeImageLength = 0; // to be fixed
\r
623 PciDs30.ConfigUtilityCodeHeaderOffset = 0; // to be fixed
\r
624 PciDs30.DMTFCLPEntryPointOffset = 0; // to be fixed
\r
627 // If this is the last image, then set the LAST bit unless requested not
\r
628 // to via the command-line -n argument.
\r
630 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
\r
631 if (mOptions.Pci23 == 1) {
\r
632 PciDs23.Indicator = INDICATOR_LAST;
\r
634 PciDs30.Indicator = INDICATOR_LAST;}
\r
636 if (mOptions.Pci23 == 1) {
\r
637 PciDs23.Indicator = 0;
\r
639 PciDs30.Indicator = 0;
\r
643 // Write the ROM header to the output file
\r
645 if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {
\r
646 Error (NULL, 0, 0002, "Failed to write ROM header to output file!");
\r
647 Status = STATUS_ERROR;
\r
652 // Write pad bytes to align the PciDs
\r
654 while (HeaderPadBytes > 0) {
\r
655 if (putc (0, OutFptr) == EOF) {
\r
656 Error (NULL, 0, 0002, "Failed to write ROM header pad bytes to output file!");
\r
657 Status = STATUS_ERROR;
\r
664 // Write the PCI data structure header to the output file
\r
666 if (mOptions.Pci23 == 1) {
\r
667 if (fwrite (&PciDs23, sizeof (PciDs23), 1, OutFptr) != 1) {
\r
668 Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!");
\r
669 Status = STATUS_ERROR;
\r
673 if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {
\r
674 Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!");
\r
675 Status = STATUS_ERROR;
\r
680 // Keep track of how many bytes left to write
\r
682 TotalSize -= HeaderSize;
\r
685 // Now dump the input file's contents to the output file
\r
687 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
\r
688 Error (NULL, 0, 0002, "Failed to write all file bytes to output file!");
\r
689 Status = STATUS_ERROR;
\r
693 TotalSize -= FileSize;
\r
695 // Pad the rest of the image to make it a multiple of 512 bytes
\r
697 while (TotalSize > 0) {
\r
698 if (putc (~0, OutFptr) == EOF) {
\r
699 Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!");
\r
700 Status = STATUS_ERROR;
\r
708 if (InFptr != NULL) {
\r
712 // Free up our buffers
\r
714 if (Buffer != NULL) {
\r
718 if (CompressedBuffer != NULL) {
\r
719 free (CompressedBuffer);
\r
722 // Print the file name if errors occurred
\r
724 if (Status != STATUS_SUCCESS) {
\r
725 Error (NULL, 0, 0003, "Error parsing", "Error parsing file: %s", InFile->FileName);
\r
735 UINT16 *MachineType,
\r
740 Routine Description:
\r
742 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
\r
743 PE32 image file, and then return the machine type in the supplied pointer.
\r
747 Fptr File pointer to the already-opened PE32 file
\r
748 MachineType Location to stuff the machine type of the PE32 file. This is needed
\r
749 because the image may be Itanium-based, IA32, or EBC.
\r
758 EFI_IMAGE_DOS_HEADER DosHeader;
\r
759 EFI_IMAGE_FILE_HEADER FileHdr;
\r
760 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;
\r
764 // Position to the start of the file
\r
766 fseek (Fptr, 0, SEEK_SET);
\r
769 // Read the DOS header
\r
771 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {
\r
772 Error (NULL, 0, 0004, "Failed to read the DOS stub from the input file!");
\r
773 return STATUS_ERROR;
\r
776 // Check the magic number (0x5A4D)
\r
778 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
\r
779 Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");
\r
780 return STATUS_ERROR;
\r
783 // Position into the file and check the PE signature
\r
785 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);
\r
786 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {
\r
787 Error (NULL, 0, 0004, "Failed to read PE signature bytes from input file!");
\r
788 return STATUS_ERROR;
\r
791 // Check the PE signature in the header "PE\0\0"
\r
793 if (PESig != EFI_IMAGE_NT_SIGNATURE) {
\r
794 Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");
\r
795 return STATUS_ERROR;
\r
798 // Read the file header and stuff their MachineType
\r
800 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {
\r
801 Error (NULL, 0, 0004, "Failed to read PE file header from input file!");
\r
802 return STATUS_ERROR;
\r
805 memcpy ((char *) MachineType, &FileHdr.Machine, 2);
\r
808 // Read the optional header so we can get the subsystem
\r
810 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {
\r
811 Error (NULL, 0, 0004, "Failed to read COFF optional header from input file!");
\r
812 return STATUS_ERROR;
\r
815 *SubSystem = OptionalHdr.Subsystem;
\r
816 if (mOptions.Verbose) {
\r
817 VerboseMsg(" Got subsystem = 0x%X from image\n", (int) *SubSystem);
\r
822 return STATUS_SUCCESS;
\r
834 Routine Description:
\r
836 Given the Argc/Argv program arguments, and a pointer to an options structure,
\r
837 parse the command-line options and check their validity.
\r
842 Argc - standard C main() argument count
\r
843 Argv[] - standard C main() argument list
\r
844 Options - pointer to a structure to store the options in
\r
848 STATUS_SUCCESS success
\r
853 FILE_LIST *FileList;
\r
855 FILE_LIST *PrevFileList;
\r
858 UINT32 CodeRevision;
\r
864 // Clear out the options
\r
866 memset ((char *) Options, 0, sizeof (OPTIONS));
\r
869 // To avoid compile warnings
\r
871 FileList = PrevFileList = NULL;
\r
876 // Skip over the program name
\r
882 // If no arguments, assume they want usage info
\r
886 return STATUS_ERROR;
\r
889 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
\r
890 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
\r
892 return STATUS_ERROR;
\r
895 if ((strcmp(Argv[0], "--version") == 0)) {
\r
897 return STATUS_ERROR;
\r
901 // Process until no more arguments
\r
904 if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) {
\r
906 // To simplify string comparisons, replace slashes with dashes
\r
911 // Vendor ID specified with -f
\r
913 if (stricmp (Argv[0], "-f") == 0) {
\r
915 // Make sure there's another parameter
\r
918 Options->VendId = (UINT16) strtol (Argv[1], NULL, 16);
\r
919 Options->VendIdValid = 1;
\r
921 Error (NULL, 0, 2000, "Invalid parameter", "Missing Vendor ID with %s!", Argv[0]);
\r
923 return STATUS_ERROR;
\r
928 } else if (stricmp (Argv[0], "-i") == 0) {
\r
930 // Device ID specified with -i
\r
931 // Make sure there's another parameter
\r
933 //printf("\nDevice id specified!\n");
\r
935 Options->DevId = (UINT16) strtol (Argv[1], NULL, 16);
\r
936 Options->DevIdValid = 1;
\r
938 Error (NULL, 0, 2000, "Invalid parameter", "Missing Device ID with %s!", Argv[0]);
\r
940 return STATUS_ERROR;
\r
945 } else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {
\r
947 // Output filename specified with -o
\r
948 // Make sure there's another parameter
\r
951 strcpy (Options->OutFileName, Argv[1]);
\r
953 Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s!", Argv[0]);
\r
955 return STATUS_ERROR;
\r
960 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {
\r
965 return STATUS_ERROR;
\r
966 } else if (stricmp (Argv[0], "-b") == 0) {
\r
968 // Specify binary files with -b
\r
970 FileFlags = FILE_FLAG_BINARY;
\r
971 } else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) {
\r
973 // Specify EFI files with -e. Specify EFI-compressed with -c.
\r
975 FileFlags = FILE_FLAG_EFI;
\r
976 if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {
\r
977 FileFlags |= FILE_FLAG_COMPRESS;
\r
980 // Specify not to set the LAST bit in the last file with -n
\r
982 } else if (stricmp (Argv[0], "-n") == 0) {
\r
983 Options->NoLast = 1;
\r
984 } else if (((stricmp (Argv[0], "-v") == 0)) || ((stricmp (Argv[0], "--verbose") == 0))) {
\r
988 Options->Verbose = 1;
\r
989 } else if (stricmp (Argv[0], "--debug") == 0) {
\r
991 Status = AsciiStringToUint64(Argv[0], FALSE, &DebugLevel);
\r
992 if (DebugLevel > 9 || DebugLevel < 0) {
\r
993 Error (NULL, 0, 2000, "Invalid parameter", "Unrecognized parameter %s\n", Argv[0]);
\r
996 if (DebugLevel>=5 && DebugLevel<=9) {
\r
997 Options->Debug = TRUE;
\r
999 Options->Debug = FALSE;
\r
1002 } else if ((stricmp (Argv[0], "--quiet") == 0) || (stricmp (Argv[0], "-q") == 0)) {
\r
1003 Options->Quiet = TRUE;
\r
1004 } else if ((stricmp (Argv[0], "--dump") == 0) || (stricmp (Argv[0], "-d") == 0)) {
\r
1006 // -dump for dumping a ROM image. In this case, say that the device id
\r
1007 // and vendor id are valid so we don't have to specify bogus ones on the
\r
1010 Options->DumpOption = 1;
\r
1012 Options->VendIdValid = 1;
\r
1013 Options->DevIdValid = 1;
\r
1014 FileFlags = FILE_FLAG_BINARY;
\r
1015 } else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {
\r
1017 // Class code value for the next file in the list.
\r
1018 // Make sure there's another parameter
\r
1022 // No error checking on the return value. Could check for LONG_MAX,
\r
1023 // LONG_MIN, or 0 class code value if desired. Check range (3 bytes)
\r
1026 ClassCode = (UINT32) strtol (Argv[1], NULL, 16);
\r
1027 if (ClassCode & 0xFF000000) {
\r
1028 Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv[1]);
\r
1029 return STATUS_ERROR;
\r
1032 Error (NULL, 0, 2000, "Invalid parameter", "Missing class code value with %s!", Argv[0]);
\r
1034 return STATUS_ERROR;
\r
1039 } else if ((stricmp (Argv[0], "-r") == 0) || (stricmp (Argv[0], "--Revision") == 0)) {
\r
1041 // Code revision in the PCI data structure. The value is for the next
\r
1042 // file in the list.
\r
1043 // Make sure there's another parameter
\r
1047 // No error checking on the return value. Could check for LONG_MAX,
\r
1048 // LONG_MIN, or 0 value if desired. Check range (2 bytes)
\r
1051 CodeRevision = (UINT32) strtol (Argv[1], NULL, 16);
\r
1052 if (CodeRevision & 0xFFFF0000) {
\r
1053 Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv[1]);
\r
1054 return STATUS_ERROR;
\r
1057 Error (NULL, 0, 2000, "Invalid parameter", "Missing code revision value with %s!", Argv[0]);
\r
1059 return STATUS_ERROR;
\r
1064 } else if ((stricmp (Argv[0], "-p") == 0) || (stricmp (Argv[0], "-pci23") == 0)) {
\r
1066 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
\r
1068 mOptions.Pci23 = 1;
\r
1070 Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);
\r
1072 return STATUS_ERROR;
\r
1076 // Not a slash-option argument. Must be a file name. Make sure they've specified
\r
1077 // -e or -b already.
\r
1079 if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {
\r
1080 Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv[0]);
\r
1081 return STATUS_ERROR;
\r
1084 // Create a new file structure
\r
1086 FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));
\r
1087 if (FileList == NULL) {
\r
1088 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
\r
1089 return STATUS_ERROR;
\r
1093 // set flag and class code for this image.
\r
1095 memset ((char *) FileList, 0, sizeof (FILE_LIST));
\r
1096 FileList->FileName = Argv[0];
\r
1097 FileList->FileFlags = FileFlags;
\r
1098 FileList->ClassCode = ClassCode;
\r
1099 FileList->CodeRevision = (UINT16) CodeRevision;
\r
1103 if (Options->FileList == NULL) {
\r
1104 Options->FileList = FileList;
\r
1106 if (PrevFileList == NULL) {
\r
1107 PrevFileList = FileList;
\r
1109 PrevFileList->Next = FileList;
\r
1113 PrevFileList = FileList;
\r
1123 // Must have specified some files
\r
1125 if (Options->FileList == NULL) {
\r
1126 Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name!");
\r
1128 return STATUS_ERROR;
\r
1132 // Make sure they specified a device ID and vendor ID
\r
1134 if (!Options->VendIdValid) {
\r
1135 Error (NULL, 0, 2000, "Missing Vendor ID in command line", NULL);
\r
1136 return STATUS_ERROR;
\r
1139 if (!Options->DevIdValid) {
\r
1140 Error (NULL, 0, 2000, "Missing Device ID in command line", NULL);
\r
1142 return STATUS_ERROR;
\r
1155 Routine Description:
\r
1157 Print version information for this utility.
\r
1168 fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
\r
1178 Routine Description:
\r
1180 Print usage information for this utility.
\r
1195 fprintf (stdout, "Usage: %s [options] [file name<s>] \n\n", UTILITY_NAME);
\r
1198 // Copyright declaration
\r
1200 fprintf (stdout, "Copyright (c) 2007, Intel Corporation. All rights reserved.\n\n");
\r
1205 fprintf (stdout, "Options:\n");
\r
1206 fprintf (stdout, " -o FileName, --output FileName\n\
\r
1207 File will be created to store the ouput content.\n");
\r
1208 fprintf (stdout, " -e EfiFileName\n\
\r
1209 EFI PE32 image files.\n");
\r
1210 fprintf (stdout, " -ec EfiFileName\n\
\r
1211 EFI PE32 image files and will be compressed.\n");
\r
1212 fprintf (stdout, " -b BinFileName\n\
\r
1213 Legacy binary files.\n");
\r
1214 fprintf (stdout, " -l ClassCode\n\
\r
1215 Hex ClassCode in the PCI data structure header.\n");
\r
1216 fprintf (stdout, " -r Rev\n\
\r
1217 hex Revision in the PCI data structure header.\n");
\r
1218 fprintf (stdout, " -n\n\
\r
1219 not to automatically set the LAST bit in the last file.\n");
\r
1220 fprintf (stdout, " -f VendorId\n\
\r
1221 Hex PCI Vendor ID for the device OpROM.\n");
\r
1222 fprintf (stdout, " -i DeviceId\n\
\r
1223 Hex PCI Device ID for the device OpROM.\n");
\r
1224 fprintf (stdout, " -p, --pci23\n\
\r
1225 Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.\n");
\r
1226 fprintf (stdout, " -d, --dump\n\
\r
1227 Dump the headers of an existing option ROM image.\n");
\r
1228 fprintf (stdout, " -v, --verbose\n\
\r
1229 Turn on verbose output with informational messages.\n");
\r
1230 fprintf (stdout, " --version\n\
\r
1231 Show program's version number and exit.\n");
\r
1232 fprintf (stdout, " -h, --help\n\
\r
1233 Show this help message and exit.\n");
\r
1234 fprintf (stdout, " -q, --quiet\n\
\r
1235 Disable all messages except FATAL ERRORS.\n");
\r
1236 fprintf (stdout, " --debug [#,0-9]\n\
\r
1237 Enable debug messages at level #.\n");
\r
1247 Routine Description:
\r
1249 Dump the headers of an existing option ROM image
\r
1253 InFile - the file name of an existing option ROM image
\r
1261 PCI_EXPANSION_ROM_HEADER PciRomHdr;
\r
1263 UINT32 ImageStart;
\r
1264 UINT32 ImageCount;
\r
1265 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr;
\r
1266 PCI_DATA_STRUCTURE PciDs23;
\r
1267 PCI_3_0_DATA_STRUCTURE PciDs30;
\r
1270 // Open the input file
\r
1272 if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
\r
1273 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
\r
1277 // Go through the image and dump the header stuff for each
\r
1282 // Save our postition in the file, since offsets in the headers
\r
1283 // are relative to the particular image.
\r
1285 ImageStart = ftell (InFptr);
\r
1289 // Read the option ROM header. Have to assume a raw binary image for now.
\r
1291 if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {
\r
1292 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");
\r
1297 // Dump the contents of the header
\r
1299 fprintf (stdout, "Image %d -- Offset 0x%X\n", ImageCount, ImageStart);
\r
1300 fprintf (stdout, " ROM header contents\n");
\r
1301 fprintf (stdout, " Signature 0x%04X\n", (UINT32) PciRomHdr.Signature);
\r
1302 fprintf (stdout, " PCIR offset 0x%04X\n", (UINT32) PciRomHdr.PcirOffset);
\r
1304 // Find PCI data structure
\r
1306 if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {
\r
1307 Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");
\r
1311 // Read and dump the PCI data structure
\r
1313 memset (&PciDs23, 0, sizeof (PciDs23));
\r
1314 memset (&PciDs30, 0, sizeof (PciDs30));
\r
1315 if (mOptions.Pci23 == 1) {
\r
1316 if (fread (&PciDs23, sizeof (PciDs23), 1, InFptr) != 1) {
\r
1317 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);
\r
1321 if (fread (&PciDs30, sizeof (PciDs30), 1, InFptr) != 1) {
\r
1322 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);
\r
1326 if (mOptions.Verbose) {
\r
1327 VerboseMsg("Read PCI data structure from file %s", InFile->FileName);
\r
1330 //fprintf (stdout, " PCI Data Structure\n");
\r
1331 if (mOptions.Pci23 == 1) {
\r
1334 " Signature %c%c%c%c\n",
\r
1335 (char) PciDs23.Signature,
\r
1336 (char) (PciDs23.Signature >> 8),
\r
1337 (char) (PciDs23.Signature >> 16),
\r
1338 (char) (PciDs23.Signature >> 24)
\r
1340 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs23.VendorId);
\r
1341 fprintf (stdout, " Device ID 0x%04X\n", PciDs23.DeviceId);
\r
1342 fprintf (stdout, " Length 0x%04X\n", PciDs23.Length);
\r
1343 fprintf (stdout, " Revision 0x%04X\n", PciDs23.Revision);
\r
1346 " Class Code 0x%06X\n",
\r
1347 (UINT32) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))
\r
1349 fprintf (stdout, " Image size 0x%X\n", PciDs23.ImageLength * 512);
\r
1350 fprintf (stdout, " Code revision: 0x%04X\n", PciDs23.CodeRevision);
\r
1351 fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs23.Indicator);
\r
1355 " Signature %c%c%c%c\n",
\r
1356 (char) PciDs30.Signature,
\r
1357 (char) (PciDs30.Signature >> 8),
\r
1358 (char) (PciDs30.Signature >> 16),
\r
1359 (char) (PciDs30.Signature >> 24)
\r
1361 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs30.VendorId);
\r
1362 fprintf (stdout, " Device ID 0x%04X\n", PciDs30.DeviceId);
\r
1363 fprintf (stdout, " Length 0x%04X\n", PciDs30.Length);
\r
1364 fprintf (stdout, " Revision 0x%04X\n", PciDs30.Revision);
\r
1365 fprintf (stdout, " DeviceListOffset 0x%02X\n", (UINT32) PciDs30.DeviceListOffset);
\r
1368 " Class Code 0x%06X\n",
\r
1369 (UINT32) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))
\r
1371 fprintf (stdout, " Image size 0x%X\n", PciDs30.ImageLength * 512);
\r
1372 fprintf (stdout, " Code revision: 0x%04X\n", PciDs30.CodeRevision);
\r
1373 fprintf (stdout, " MaxRuntimeImageLength 0x%02X\n", (UINT32) PciDs30.MaxRuntimeImageLength);
\r
1374 fprintf (stdout, " ConfigUtilityCodeHeaderOffset 0x%02X\n", (UINT32) PciDs30.ConfigUtilityCodeHeaderOffset);
\r
1375 fprintf (stdout, " DMTFCLPEntryPointOffset 0x%02X\n", (UINT32) PciDs30.DMTFCLPEntryPointOffset);
\r
1376 fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs30.Indicator);
\r
1379 // Print the indicator, used to flag the last image
\r
1381 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
\r
1382 fprintf (stdout, " (last image)\n");
\r
1384 fprintf (stdout, "\n");
\r
1387 // Print the code type. If EFI code, then we can provide more info.
\r
1389 if (mOptions.Pci23 == 1) {
\r
1390 fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs23.CodeType);
\r
1392 fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs30.CodeType);
\r
1394 if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
\r
1395 fprintf (stdout, " (EFI image)\n");
\r
1397 // Re-read the header as an EFI ROM header, then dump more info
\r
1399 fprintf (stdout, " EFI ROM header contents\n");
\r
1400 if (fseek (InFptr, ImageStart, SEEK_SET)) {
\r
1401 Error (NULL, 0, 5001, "Failed to re-seek to ROM header structure!");
\r
1405 if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {
\r
1406 Error (NULL, 0, 5001, "Failed to read EFI PCI ROM header from file!");
\r
1410 // Now dump more info
\r
1412 fprintf (stdout, " EFI Signature 0x%04X\n", EfiRomHdr.EfiSignature);
\r
1415 " Compression Type 0x%04X ",
\r
1416 (UINT32) EfiRomHdr.CompressionType
\r
1418 if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
\r
1419 fprintf (stdout, "(compressed)\n");
\r
1421 fprintf (stdout, "(not compressed)\n");
\r
1426 " Machine type 0x%04X (%s)\n",
\r
1427 EfiRomHdr.EfiMachineType,
\r
1428 GetMachineTypeStr (EfiRomHdr.EfiMachineType)
\r
1432 " Subsystem 0x%04X (%s)\n",
\r
1433 EfiRomHdr.EfiSubsystem,
\r
1434 GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)
\r
1438 " EFI image offset 0x%04X (@0x%X)\n",
\r
1439 (UINT32) EfiRomHdr.EfiImageHeaderOffset,
\r
1440 (UINT32) (EfiRomHdr.EfiImageHeaderOffset + ImageStart)
\r
1445 // Not an EFI image
\r
1447 fprintf (stdout, "\n");
\r
1450 // If code type is EFI image, then dump it as well?
\r
1452 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
\r
1455 // If last image, then we're done
\r
1457 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
\r
1461 // Seek to the start of the next image
\r
1463 if (mOptions.Pci23 == 1) {
\r
1464 if (fseek (InFptr, ImageStart + (PciDs23.ImageLength * 512), SEEK_SET)) {
\r
1465 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");
\r
1469 if (fseek (InFptr, ImageStart + (PciDs30.ImageLength * 512), SEEK_SET)) {
\r
1470 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");
\r
1481 GetMachineTypeStr (
\r
1482 UINT16 MachineType
\r
1486 Routine Description:
\r
1488 GC_TODO: Add function description
\r
1492 MachineType - GC_TODO: add argument description
\r
1496 GC_TODO: add return values
\r
1502 for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {
\r
1503 if (mMachineTypes[Index].Value == MachineType) {
\r
1504 return mMachineTypes[Index].Name;
\r
1513 GetSubsystemTypeStr (
\r
1514 UINT16 SubsystemType
\r
1518 Routine Description:
\r
1520 GC_TODO: Add function description
\r
1524 SubsystemType - GC_TODO: add argument description
\r
1528 GC_TODO: add return values
\r
1534 for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {
\r
1535 if (mSubsystemTypes[Index].Value == SubsystemType) {
\r
1536 return mSubsystemTypes[Index].Name;
\r