3 Copyright (c) 1999-2007 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
32 Routine Description:
\r
34 Given an EFI image filename, create a ROM-able image by creating an option
\r
35 ROM header and PCI data structure, filling them in, and then writing the
\r
36 option ROM header + PCI data structure + EFI image out to the output file.
\r
40 Argc - standard C main() argument count
\r
42 Argv - standard C main() argument list
\r
58 FILE_LIST *OutFileList;
\r
61 SetUtilityName(UTILITY_NAME);
\r
63 Status = STATUS_SUCCESS;
\r
67 // Create a new out file structure
\r
69 OutFileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));
\r
70 if (OutFileList == NULL) {
\r
71 Error(stdout, 0, 4001, "Resource", "memory cannot be allocated ");
\r
72 return STATUS_ERROR;
\r
74 memset ((char *) OutFileList, 0, sizeof (FILE_LIST));
\r
76 // Parse the command line arguments
\r
78 if (ParseCommandLine (Argc, Argv, &mOptions)) {
\r
79 return STATUS_ERROR;
\r
82 if (mOptions.Quiet) {
\r
84 } else if (mOptions.Verbose) {
\r
86 } else if (mOptions.Debug) {
\r
87 SetPrintLevel(DebugLevel);
\r
90 if (mOptions.Verbose) {
\r
91 fprintf (stdout, "%s tool start.\n", UTILITY_NAME);
\r
94 // If dumping an image, then do that and quit
\r
96 // if (mOptions.DumpOption) {
\r
97 // for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
\r
98 // if ((Ptr0 = strstr ((CONST CHAR8 *)FList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {
\r
99 // DumpImage (mOptions.FileList);
\r
104 // printf("\n *.rom file has not been generated, so -p option should be used //after the *.rom Option Rom binary generated!");
\r
108 // Determine the output filename. Either what they specified on
\r
109 // the command line, or the first input filename with a different extension.
\r
111 if (!mOptions.OutFileName[0]) {
\r
112 strcpy (mOptions.OutFileName, mOptions.FileList->FileName);
\r
114 // Find the last . on the line and replace the filename extension with
\r
117 for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;
\r
118 (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');
\r
123 // If dot here, then insert extension here, otherwise append
\r
126 Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);
\r
129 strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);
\r
132 // Make sure we don't have the same filename for input and output files
\r
134 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
\r
135 if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {
\r
136 Status = STATUS_ERROR;
\r
137 Error(NULL, 0, 1002, "Input and output file names must be different - %s = %s", FList->FileName, mOptions.OutFileName);
\r
142 // Now open our output file
\r
144 if ((FptrOut = fopen (mOptions.OutFileName, "w+b")) == NULL) {
\r
145 Error(stdout, 0, 0001, "Error opening file", mOptions.OutFileName);
\r
149 // Process all our files
\r
152 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
\r
154 if (FList->FileFlags & FILE_FLAG_EFI) {
\r
155 if (mOptions.Verbose) {
\r
156 fprintf (stdout, "Processing EFI file %s\n", FList->FileName);
\r
159 Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);
\r
160 } else if (FList->FileFlags & FILE_FLAG_BINARY) {
\r
161 if (mOptions.Verbose) {
\r
162 fprintf (stdout, "Processing binary file %s\n", FList->FileName);
\r
165 Status = ProcessBinFile (FptrOut, FList, &Size);
\r
167 Error(stdout, 0, 2000, "Invalid parameter", "File not specified as EFI or binary: %s", FList->FileName);
\r
168 Status = STATUS_ERROR;
\r
171 if (mOptions.Verbose) {
\r
172 fprintf (stdout, " Output size = 0x%X\n", Size);
\r
175 if (Status != STATUS_SUCCESS) {
\r
182 // Check total size
\r
184 if (TotalSize > MAX_OPTION_ROM_SIZE) {
\r
185 Error(NULL, 0, 2000, "Option ROM image size exceeds limit 0x%X bytes", MAX_OPTION_ROM_SIZE);
\r
186 Status = STATUS_ERROR;
\r
190 if (Status == STATUS_SUCCESS) {
\r
191 if (mOptions.DumpOption) {
\r
192 OutFileList->FileName = mOptions.OutFileName;
\r
193 DumpImage(OutFileList);
\r
196 if (FptrOut != NULL) {
\r
200 // Clean up our file list
\r
202 while (mOptions.FileList != NULL) {
\r
203 FList = mOptions.FileList->Next;
\r
204 free (mOptions.FileList);
\r
205 mOptions.FileList = FList;
\r
208 if (mOptions.Verbose) {
\r
209 fprintf (stdout, "%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());
\r
212 return GetUtilityStatus ();
\r
224 Routine Description:
\r
226 Process a binary input file.
\r
230 OutFptr - file pointer to output binary ROM image file we're creating
\r
231 InFile - structure contains information on the binary file to process
\r
232 Size - pointer to where to return the size added to the output file
\r
245 PCI_EXPANSION_ROM_HEADER *RomHdr;
\r
246 PCI_DATA_STRUCTURE *PciDs23;
\r
247 PCI_3_0_DATA_STRUCTURE *PciDs30;
\r
249 UINT8 ByteCheckSum;
\r
252 Status = STATUS_SUCCESS;
\r
255 // Try to open the input file
\r
257 if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
\r
258 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
\r
259 return STATUS_ERROR;
\r
262 // Seek to the end of the input file and get the file size. Then allocate
\r
263 // a buffer to read it in to.
\r
265 fseek (InFptr, 0, SEEK_END);
\r
266 FileSize = ftell (InFptr);
\r
267 if (mOptions.Verbose) {
\r
268 fprintf (stdout, " File size = 0x%X\n", FileSize);
\r
271 fseek (InFptr, 0, SEEK_SET);
\r
272 Buffer = (INT8 *) malloc (FileSize);
\r
273 if (Buffer == NULL) {
\r
274 Error (NULL, 0, 4003, "Resource", "Out of memory resources.", NULL);
\r
275 Status = STATUS_ERROR;
\r
279 if (fread (Buffer, FileSize, 1, InFptr) != 1) {
\r
280 Error(NULL, 0, 2000, "Invalid", "Failed to read all bytes from input file");
\r
281 Status = STATUS_ERROR;
\r
285 // Total size must be an even multiple of 512 bytes, and can't exceed
\r
286 // the option ROM image size.
\r
288 TotalSize = FileSize;
\r
289 if (TotalSize & 0x1FF) {
\r
290 TotalSize = (TotalSize + 0x200) &~0x1ff;
\r
293 if (TotalSize > MAX_OPTION_ROM_SIZE) {
\r
294 Error(NULL, 0, 3001, "Option ROM image %s size exceeds limit 0x%X bytes", InFile->FileName, MAX_OPTION_ROM_SIZE);
\r
295 Status = STATUS_ERROR;
\r
299 // Return the size to the caller so they can keep track of the running total.
\r
304 // Crude check to make sure it's a legitimate ROM image
\r
306 RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;
\r
307 if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
\r
308 Error(NULL, 0, 2000, "Invalid parameter", "ROM image file has invalid ROM signature");
\r
309 Status = STATUS_ERROR;
\r
313 // Make sure the pointer to the PCI data structure is within the size of the image.
\r
314 // Then check it for valid signature.
\r
316 if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {
\r
317 Error(NULL, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset");
\r
318 Status = STATUS_ERROR;
\r
323 // Check the header is conform to PCI2.3 or PCI3.0
\r
325 if (mOptions.Pci23 == 1) {
\r
326 PciDs23 = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);
\r
327 if (PciDs23->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
\r
328 Error(NULL, 0, 2000, "Invalid parameter", "PCI data structure has invalid signature");
\r
329 Status = STATUS_ERROR;
\r
334 // Default setting is PCI3.0 header
\r
336 PciDs30 = (PCI_3_0_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);
\r
337 if (PciDs30->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
\r
338 Error(NULL, 0, 2000, "Invalid parameter", "PCI data structure has invalid signature");
\r
339 Status = STATUS_ERROR;
\r
346 // If this is the last image, then set the LAST bit unless requested not
\r
347 // to via the command-line -n argument. Otherwise, make sure you clear it.
\r
349 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
\r
350 if (mOptions.Pci23 == 1) {
\r
351 PciDs23->Indicator = INDICATOR_LAST;
\r
353 PciDs30->Indicator = INDICATOR_LAST;
\r
356 if (mOptions.Pci23 == 1) {
\r
357 PciDs23->Indicator = 0;
\r
359 PciDs30->Indicator = 0;
\r
364 for (Index = 0; Index < FileSize - 1; Index++) {
\r
365 ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);
\r
368 Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);
\r
369 fprintf (stdout, "Checksum = %02x\n", (UINT32) Buffer[FileSize - 1]);
\r
372 // Now copy the input file contents out to the output file
\r
374 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
\r
375 Error(NULL, 0, 0005, "Failed to write all file bytes to output file");
\r
376 Status = STATUS_ERROR;
\r
380 TotalSize -= FileSize;
\r
382 // Pad the rest of the image to make it a multiple of 512 bytes
\r
384 while (TotalSize > 0) {
\r
385 putc (~0, OutFptr);
\r
390 if (InFptr != NULL) {
\r
394 if (Buffer != NULL) {
\r
398 // Print the file name if errors occurred
\r
400 if (Status != STATUS_SUCCESS) {
\r
401 Error(NULL, 0, 0003, "Error parsing file: %s", InFile->FileName);
\r
418 Routine Description:
\r
420 Process a PE32 EFI file.
\r
424 OutFptr - file pointer to output binary ROM image file we're creating
\r
425 InFile - structure contains information on the PE32 file to process
\r
426 VendId - vendor ID as required in the option ROM header
\r
427 DevId - device ID as required in the option ROM header
\r
428 Size - pointer to where to return the size added to the output file
\r
438 EFI_PCI_EXPANSION_ROM_HEADER RomHdr;
\r
439 PCI_DATA_STRUCTURE PciDs23;
\r
440 PCI_3_0_DATA_STRUCTURE PciDs30;
\r
442 UINT32 CompressedFileSize;
\r
444 UINT8 *CompressedBuffer;
\r
445 UINT8 *TempBufferPtr;
\r
448 UINT16 MachineType;
\r
450 UINT32 HeaderPadBytes;
\r
453 // Try to open the input file
\r
455 if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
\r
456 Error(NULL, 0, 0001, "Error opening file: %s", InFile->FileName);
\r
457 return STATUS_ERROR;
\r
460 // Initialize our buffer pointers to null.
\r
463 CompressedBuffer = NULL;
\r
466 // Double-check the file to make sure it's what we expect it to be
\r
468 Status = CheckPE32File (InFptr, &MachineType, &SubSystem);
\r
469 if (Status != STATUS_SUCCESS) {
\r
473 // Seek to the end of the input file and get the file size
\r
475 fseek (InFptr, 0, SEEK_END);
\r
476 FileSize = ftell (InFptr);
\r
479 // Get the size of the headers we're going to put in front of the image. The
\r
480 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.
\r
482 if (sizeof (RomHdr) & 0x03) {
\r
483 HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);
\r
485 HeaderPadBytes = 0;
\r
488 HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
\r
489 if (mOptions.Verbose) {
\r
490 fprintf (stdout, " File size = 0x%X\n", FileSize);
\r
493 // Allocate memory for the entire file (in case we have to compress), then
\r
494 // seek back to the beginning of the file and read it into our buffer.
\r
496 Buffer = (INT8 *) malloc (FileSize);
\r
497 if (Buffer == NULL) {
\r
498 Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated");
\r
499 Status = STATUS_ERROR;
\r
503 fseek (InFptr, 0, SEEK_SET);
\r
504 if (fread (Buffer, FileSize, 1, InFptr) != 1) {
\r
505 Error(NULL, 0, 0004, "Error reading file", InFptr);
\r
506 Status = STATUS_ERROR;
\r
510 // Now determine the size of the final output file. It's either the header size
\r
511 // plus the file's size, or the header size plus the compressed file size.
\r
513 if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
\r
515 // Allocate a buffer into which we can compress the image, compress it,
\r
516 // and use that size as the new size.
\r
518 CompressedBuffer = (INT8 *) malloc (FileSize);
\r
519 if (CompressedBuffer == NULL) {
\r
520 Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated");
\r
521 Status = STATUS_ERROR;
\r
525 CompressedFileSize = FileSize;
\r
526 Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);
\r
527 if (Status != STATUS_SUCCESS) {
\r
528 Error(NULL, 0, 0007, "Error compressing file");
\r
532 // Now compute the size, then swap buffer pointers.
\r
534 if (mOptions.Verbose) {
\r
535 fprintf (stdout, " Comp size = 0x%X\n", CompressedFileSize);
\r
538 TotalSize = CompressedFileSize + HeaderSize;
\r
539 FileSize = CompressedFileSize;
\r
540 TempBufferPtr = Buffer;
\r
541 Buffer = CompressedBuffer;
\r
542 CompressedBuffer = TempBufferPtr;
\r
544 TotalSize = FileSize + HeaderSize;
\r
547 // Total size must be an even multiple of 512 bytes
\r
549 if (TotalSize & 0x1FF) {
\r
550 TotalSize = (TotalSize + 0x200) &~0x1ff;
\r
555 if (TotalSize > MAX_OPTION_ROM_SIZE) {
\r
556 Error(NULL, 0, 2000, "Option ROM image %s size exceeds limit 0x%X bytes", InFile->FileName, MAX_OPTION_ROM_SIZE);
\r
557 Status = STATUS_ERROR;
\r
561 // Return the size to the caller so they can keep track of the running total.
\r
566 // Now fill in the ROM header. These values come from chapter 18 of the
\r
567 // EFI 1.02 specification.
\r
569 memset (&RomHdr, 0, sizeof (RomHdr));
\r
570 RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
\r
571 RomHdr.InitializationSize = (UINT16) (TotalSize / 512);
\r
572 RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
\r
573 RomHdr.EfiSubsystem = SubSystem;
\r
574 RomHdr.EfiMachineType = MachineType;
\r
575 RomHdr.EfiImageHeaderOffset = (UINT16) HeaderSize;
\r
576 RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);
\r
578 // Set image as compressed or not
\r
580 if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
\r
581 RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;
\r
584 // Fill in the PCI data structure
\r
586 if (mOptions.Pci23 == 1) {
\r
587 memset (&PciDs23, 0, sizeof (PCI_DATA_STRUCTURE));
\r
589 memset (&PciDs30, 0, sizeof (PCI_3_0_DATA_STRUCTURE));
\r
592 if (mOptions.Pci23 == 1) {
\r
593 PciDs23.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
\r
594 PciDs23.VendorId = VendId;
\r
595 PciDs23.DeviceId = DevId;
\r
596 PciDs23.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);
\r
597 PciDs23.Revision = 0;
\r
599 // Class code and code revision from the command line (optional)
\r
601 PciDs23.ClassCode[0] = (UINT8) InFile->ClassCode;
\r
602 PciDs23.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);
\r
603 PciDs23.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);
\r
604 PciDs23.ImageLength = RomHdr.InitializationSize;
\r
605 PciDs23.CodeRevision = InFile->CodeRevision;
\r
606 PciDs23.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
\r
608 PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
\r
609 PciDs30.VendorId = VendId;
\r
610 PciDs30.DeviceId = DevId;
\r
611 PciDs30.DeviceListOffset = 0; // to be fixed
\r
612 PciDs30.Length = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);
\r
613 PciDs30.Revision = 0;
\r
615 // Class code and code revision from the command line (optional)
\r
617 PciDs30.ClassCode[0] = (UINT8) InFile->ClassCode;
\r
618 PciDs30.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);
\r
619 PciDs30.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);
\r
620 PciDs30.ImageLength = RomHdr.InitializationSize;
\r
621 PciDs30.CodeRevision = InFile->CodeRevision;
\r
622 PciDs30.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
\r
623 PciDs30.MaxRuntimeImageLength = 0; // to be fixed
\r
624 PciDs30.ConfigUtilityCodeHeaderOffset = 0; // to be fixed
\r
625 PciDs30.DMTFCLPEntryPointOffset = 0; // to be fixed
\r
628 // If this is the last image, then set the LAST bit unless requested not
\r
629 // to via the command-line -n argument.
\r
631 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
\r
632 if (mOptions.Pci23 == 1) {
\r
633 PciDs23.Indicator = INDICATOR_LAST;
\r
635 PciDs30.Indicator = INDICATOR_LAST;}
\r
637 if (mOptions.Pci23 == 1) {
\r
638 PciDs23.Indicator = 0;
\r
640 PciDs30.Indicator = 0;
\r
644 // Write the ROM header to the output file
\r
646 if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {
\r
647 Error(NULL, 0, 0002, "Failed to write ROM header to output file");
\r
648 Status = STATUS_ERROR;
\r
653 // Write pad bytes to align the PciDs
\r
655 while (HeaderPadBytes > 0) {
\r
656 if (putc (0, OutFptr) == EOF) {
\r
657 Error(NULL, 0, 0002, "Failed to write ROM header pad bytes to output file");
\r
658 Status = STATUS_ERROR;
\r
665 // Write the PCI data structure header to the output file
\r
667 if (mOptions.Pci23 == 1) {
\r
668 if (fwrite (&PciDs23, sizeof (PciDs23), 1, OutFptr) != 1) {
\r
669 Error(NULL, 0, 0002, "Failed to write PCI ROM header to output file");
\r
670 Status = STATUS_ERROR;
\r
674 if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {
\r
675 Error(NULL, 0, 0002, "Failed to write PCI ROM header to output file");
\r
676 Status = STATUS_ERROR;
\r
681 // Keep track of how many bytes left to write
\r
683 TotalSize -= HeaderSize;
\r
686 // Now dump the input file's contents to the output file
\r
688 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
\r
689 Error(NULL, 0, 0002, "Failed to write all file bytes to output file");
\r
690 Status = STATUS_ERROR;
\r
694 TotalSize -= FileSize;
\r
696 // Pad the rest of the image to make it a multiple of 512 bytes
\r
698 while (TotalSize > 0) {
\r
699 if (putc (~0, OutFptr) == EOF) {
\r
700 Error(NULL, 0, 2000, "Failed to write trailing pad bytes output file");
\r
701 Status = STATUS_ERROR;
\r
709 if (InFptr != NULL) {
\r
714 // Free up our buffers
\r
716 if (Buffer != NULL) {
\r
720 if (CompressedBuffer != NULL) {
\r
721 free (CompressedBuffer);
\r
724 // Print the file name if errors occurred
\r
726 if (Status != STATUS_SUCCESS) {
\r
727 Error(NULL, 0 , 0003, "Error parsing file: %s", InFile->FileName);
\r
737 UINT16 *MachineType,
\r
742 Routine Description:
\r
744 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
\r
745 PE32 image file, and then return the machine type in the supplied pointer.
\r
749 Fptr File pointer to the already-opened PE32 file
\r
750 MachineType Location to stuff the machine type of the PE32 file. This is needed
\r
751 because the image may be Itanium-based, IA32, or EBC.
\r
760 EFI_IMAGE_DOS_HEADER DosHeader;
\r
761 EFI_IMAGE_FILE_HEADER FileHdr;
\r
762 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;
\r
766 // Position to the start of the file
\r
768 fseek (Fptr, 0, SEEK_SET);
\r
771 // Read the DOS header
\r
773 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {
\r
774 Error(NULL, 0, 0004, "Failed to read the DOS stub from the input file");
\r
775 return STATUS_ERROR;
\r
778 // Check the magic number (0x5A4D)
\r
780 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
\r
781 Error(NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)");
\r
782 return STATUS_ERROR;
\r
785 // Position into the file and check the PE signature
\r
787 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);
\r
788 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {
\r
789 Error(NULL, 0, 0004, "Failed to read PE signature bytes from input file");
\r
790 return STATUS_ERROR;
\r
793 // Check the PE signature in the header "PE\0\0"
\r
795 if (PESig != EFI_IMAGE_NT_SIGNATURE) {
\r
796 Error(NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)");
\r
797 return STATUS_ERROR;
\r
800 // Read the file header and stuff their MachineType
\r
802 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {
\r
803 Error(NULL, 0, 0004, "Failed to read PE file header from input file");
\r
804 return STATUS_ERROR;
\r
807 memcpy ((char *) MachineType, &FileHdr.Machine, 2);
\r
810 // Read the optional header so we can get the subsystem
\r
812 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {
\r
813 Error(NULL, 0, 0004, "Failed to read COFF optional header from input file");
\r
814 return STATUS_ERROR;
\r
817 *SubSystem = OptionalHdr.Subsystem;
\r
818 if (mOptions.Verbose) {
\r
819 fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem);
\r
824 return STATUS_SUCCESS;
\r
836 Routine Description:
\r
838 Given the Argc/Argv program arguments, and a pointer to an options structure,
\r
839 parse the command-line options and check their validity.
\r
844 Argc - standard C main() argument count
\r
845 Argv[] - standard C main() argument list
\r
846 Options - pointer to a structure to store the options in
\r
850 STATUS_SUCCESS success
\r
855 FILE_LIST *FileList;
\r
857 FILE_LIST *PrevFileList;
\r
860 UINT32 CodeRevision;
\r
866 // Clear out the options
\r
868 memset ((char *) Options, 0, sizeof (OPTIONS));
\r
871 // To avoid compile warnings
\r
873 FileList = PrevFileList = NULL;
\r
878 // Skip over the program name
\r
884 // If no arguments, assume they want usage info
\r
888 return STATUS_ERROR;
\r
891 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
\r
892 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
\r
894 return STATUS_ERROR;
\r
897 if ((strcmp(Argv[0], "--version") == 0)) {
\r
899 return STATUS_ERROR;
\r
903 // Process until no more arguments
\r
907 if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) {
\r
909 // To simplify string comparisons, replace slashes with dashes
\r
914 // Vendor ID specified with -f
\r
916 if (stricmp (Argv[0], "-f") == 0) {
\r
918 // Make sure there's another parameter
\r
920 //printf("\nvendor id specified!\n");
\r
922 Options->VendId = (UINT16) strtol (Argv[1], NULL, 16);
\r
923 Options->VendIdValid = 1;
\r
925 Error (NULL, 0, 2000, "Invalid parameter", "Missing Vendor ID with %s", Argv[0]);
\r
927 return STATUS_ERROR;
\r
932 } else if (stricmp (Argv[0], "-i") == 0) {
\r
934 // Device ID specified with -i
\r
935 // Make sure there's another parameter
\r
937 //printf("\nDevice id specified!\n");
\r
939 Options->DevId = (UINT16) strtol (Argv[1], NULL, 16);
\r
940 Options->DevIdValid = 1;
\r
942 Error (NULL, 0, 2000, "Invalid parameter", "Missing Device ID with %s", Argv[0]);
\r
944 return STATUS_ERROR;
\r
949 } else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {
\r
951 // Output filename specified with -o
\r
952 // Make sure there's another parameter
\r
955 strcpy (Options->OutFileName, Argv[1]);
\r
957 Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s", Argv[0]);
\r
959 return STATUS_ERROR;
\r
964 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {
\r
969 return STATUS_ERROR;
\r
970 } else if (stricmp (Argv[0], "-b") == 0) {
\r
972 // Specify binary files with -b
\r
974 FileFlags = (FileFlags &~FILE_FLAG_EFI) | FILE_FLAG_BINARY;
\r
975 } else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) {
\r
977 // Specify EFI files with -e. Specify EFI-compressed with -c.
\r
979 FileFlags = (FileFlags &~FILE_FLAG_BINARY) | FILE_FLAG_EFI;
\r
980 if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {
\r
981 FileFlags |= FILE_FLAG_COMPRESS;
\r
984 // Specify not to set the LAST bit in the last file with -n
\r
986 } else if (stricmp (Argv[0], "-n") == 0) {
\r
987 Options->NoLast = 1;
\r
988 } else if (((stricmp (Argv[0], "-v") == 0)) || ((stricmp (Argv[0], "--verbose") == 0))) {
\r
992 Options->Verbose = 1;
\r
993 } else if (stricmp (Argv[0], "--debug") == 0) {
\r
995 Status = AsciiStringToUint64(Argv[0], FALSE, &DebugLevel);
\r
996 if (DebugLevel > 9 || DebugLevel < 0) {
\r
997 Error(NULL, 0, 2000, "Invalid parameter", "Unrecognized parameter %s\n", Argv[0]);
\r
1000 if (DebugLevel>=5 && DebugLevel<=9) {
\r
1003 DebugMode = FALSE;
\r
1006 } else if ((stricmp (Argv[0], "-quiet") == 0) || (stricmp (Argv[0], "-q") == 0)) {
\r
1010 } else if ((stricmp (Argv[0], "-dump") == 0) || (stricmp (Argv[0], "-d") == 0)) {
\r
1012 // -dump for dumping a ROM image. In this case, say that the device id
\r
1013 // and vendor id are valid so we don't have to specify bogus ones on the
\r
1016 Options->DumpOption = 1;
\r
1018 Options->VendIdValid = 1;
\r
1019 Options->DevIdValid = 1;
\r
1020 FileFlags = FILE_FLAG_BINARY;
\r
1021 } else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {
\r
1023 // Class code value for the next file in the list.
\r
1024 // Make sure there's another parameter
\r
1028 // No error checking on the return value. Could check for LONG_MAX,
\r
1029 // LONG_MIN, or 0 class code value if desired. Check range (3 bytes)
\r
1032 ClassCode = (UINT32) strtol (Argv[1], NULL, 16);
\r
1033 if (ClassCode & 0xFF000000) {
\r
1034 Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range", Argv[1]);
\r
1035 return STATUS_ERROR;
\r
1038 Error (NULL, 0, 2000, "Invalid parameter", "Missing class code value with %s", Argv[0]);
\r
1040 return STATUS_ERROR;
\r
1045 } else if ((stricmp (Argv[0], "-r") == 0) || (stricmp (Argv[0], "--Revision") == 0)) {
\r
1047 // Code revision in the PCI data structure. The value is for the next
\r
1048 // file in the list.
\r
1049 // Make sure there's another parameter
\r
1053 // No error checking on the return value. Could check for LONG_MAX,
\r
1054 // LONG_MIN, or 0 value if desired. Check range (2 bytes)
\r
1057 CodeRevision = (UINT32) strtol (Argv[1], NULL, 16);
\r
1058 if (CodeRevision & 0xFFFF0000) {
\r
1059 Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range", Argv[1]);
\r
1060 return STATUS_ERROR;
\r
1063 Error (NULL, 0, 2000, "Invalid parameter", "Missing code revision value with %s", Argv[0]);
\r
1065 return STATUS_ERROR;
\r
1070 } else if ((stricmp (Argv[0], "-p") == 0) || (stricmp (Argv[0], "-pci23") == 0)) {
\r
1072 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.
\r
1074 mOptions.Pci23 = 1;
\r
1076 Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);
\r
1078 return STATUS_ERROR;
\r
1082 // Not a slash-option argument. Must be a file name. Make sure they've specified
\r
1083 // -e or -b already.
\r
1085 if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {
\r
1086 Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s", Argv[0]);
\r
1087 return STATUS_ERROR;
\r
1090 // Create a new file structure
\r
1092 FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));
\r
1093 if (FileList == NULL) {
\r
1094 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
\r
1095 return STATUS_ERROR;
\r
1098 memset ((char *) FileList, 0, sizeof (FILE_LIST));
\r
1099 FileList->FileName = Argv[0];
\r
1100 FileList->FileFlags = FileFlags;
\r
1101 if (Options->FileList == NULL) {
\r
1102 Options->FileList = FileList;
\r
1104 if (PrevFileList == NULL) {
\r
1105 PrevFileList = FileList;
\r
1107 PrevFileList->Next = FileList;
\r
1111 PrevFileList = FileList;
\r
1121 // Must have specified some files
\r
1123 if (Options->FileList == NULL) {
\r
1124 Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name");
\r
1126 return STATUS_ERROR;
\r
1129 // Set the class code and code revision for this file, then reset the values.
\r
1131 FileList->ClassCode = ClassCode;
\r
1132 FileList->CodeRevision = (UINT16) CodeRevision;
\r
1134 CodeRevision = 0;
\r
1136 // Make sure they specified a device ID and vendor ID
\r
1139 if (!Options->VendIdValid) {
\r
1140 Error(NULL, 0, 2000, "Missing Vendor ID in command line");
\r
1142 return STATUS_ERROR;
\r
1145 if (!Options->DevIdValid) {
\r
1146 Error(NULL, 0, 2000, "Missing Device ID in command line");
\r
1148 return STATUS_ERROR;
\r
1161 Routine Description:
\r
1163 Print version information for this utility.
\r
1174 fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
\r
1184 Routine Description:
\r
1186 Print usage information for this utility.
\r
1201 fprintf (stdout, "Usage: %s [options] <-e input_file>|<-b input_file> \n\n", UTILITY_NAME);
\r
1204 // Copyright declaration
\r
1206 fprintf (stdout, "Copyright (c) 2007, Intel Corporation. All rights reserved.\n\n");
\r
1211 fprintf (stdout, "Options:\n");
\r
1212 fprintf (stdout, " -o FileName, --output FileName\n\
\r
1213 File will be created to store the ouput content.\n");
\r
1214 fprintf (stdout, " -e EfiFileName\n\
\r
1215 EFI PE32 image files.\n");
\r
1216 fprintf (stdout, " -ec EfiFileName\n\
\r
1217 EFI PE32 image files and will be compressed.\n");
\r
1218 fprintf (stdout, " -b BinFileName\n\
\r
1219 Legacy binary files.\n");
\r
1220 fprintf (stdout, " -l ClassCode\n\
\r
1221 Hex ClassCode in the PCI data structure header.\n");
\r
1222 fprintf (stdout, " -r Rev\n\
\r
1223 hex Revision in the PCI data structure header.\n");
\r
1224 fprintf (stdout, " -n\n\
\r
1225 not to automatically set the LAST bit in the last file.\n");
\r
1226 fprintf (stdout, " -f VendorId\n\
\r
1227 Hex PCI Vendor ID for the device OpROM.\n");
\r
1228 fprintf (stdout, " -i DeviceId\n\
\r
1229 Hex PCI Device ID for the device OpROM.\n");
\r
1230 fprintf (stdout, " -p, --pci23\n\
\r
1231 Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.\n");
\r
1232 fprintf (stdout, " -d, --dump\n\
\r
1233 Dump the headers of an existing option ROM image.\n");
\r
1234 fprintf (stdout, " -v, --verbose\n\
\r
1235 Turn on verbose output with informational messages.\n");
\r
1236 fprintf (stdout, " --version\n\
\r
1237 Show program's version number and exit.\n");
\r
1238 fprintf (stdout, " -h, --help\n\
\r
1239 Show this help message and exit.\n");
\r
1240 fprintf (stdout, " -q, --quiet\n\
\r
1241 Disable all messages except FATAL ERRORS.\n");
\r
1242 fprintf (stdout, " --debug [#]\n\
\r
1243 Enable debug messages at level #.\n");
\r
1253 Routine Description:
\r
1255 Dump the headers of an existing option ROM image
\r
1259 InFile - the file name of an existing option ROM image
\r
1267 PCI_EXPANSION_ROM_HEADER PciRomHdr;
\r
1269 UINT32 ImageStart;
\r
1270 UINT32 ImageCount;
\r
1271 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr;
\r
1272 PCI_DATA_STRUCTURE PciDs23;
\r
1273 PCI_3_0_DATA_STRUCTURE PciDs30;
\r
1276 // Open the input file
\r
1278 if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
\r
1279 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);
\r
1283 // Go through the image and dump the header stuff for each
\r
1288 // Save our postition in the file, since offsets in the headers
\r
1289 // are relative to the particular image.
\r
1291 ImageStart = ftell (InFptr);
\r
1295 // Read the option ROM header. Have to assume a raw binary image for now.
\r
1297 if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {
\r
1298 if (ImageStart == 0) {
\r
1299 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI ROM header from file");
\r
1307 // Dump the contents of the header
\r
1309 fprintf (stdout, "Image %d -- Offset 0x%X\n", ImageCount, ImageStart);
\r
1310 fprintf (stdout, " ROM header contents\n");
\r
1311 fprintf (stdout, " Signature 0x%04X\n", (UINT32) PciRomHdr.Signature);
\r
1312 fprintf (stdout, " PCIR offset 0x%04X\n", (UINT32) PciRomHdr.PcirOffset);
\r
1314 // Find PCI data structure
\r
1316 if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {
\r
1317 Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI data structure");
\r
1321 // Read and dump the PCI data structure
\r
1323 if (mOptions.Pci23 == 1) {
\r
1324 if (fread (&PciDs23, sizeof (PciDs23), 1, InFptr) != 1) {
\r
1325 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file");
\r
1329 if (fread (&PciDs30, sizeof (PciDs30), 1, InFptr) != 1) {
\r
1330 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file");
\r
1335 fprintf (stdout, " PCI Data Structure\n");
\r
1336 if (mOptions.Pci23 == 1) {
\r
1339 " Signature %c%c%c%c\n",
\r
1340 (char) PciDs23.Signature,
\r
1341 (char) (PciDs23.Signature >> 8),
\r
1342 (char) (PciDs23.Signature >> 16),
\r
1343 (char) (PciDs23.Signature >> 24)
\r
1345 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs23.VendorId);
\r
1346 fprintf (stdout, " Device ID 0x%04X\n", PciDs23.DeviceId);
\r
1347 fprintf (stdout, " Length 0x%04X\n", PciDs23.Length);
\r
1348 fprintf (stdout, " Revision 0x%04X\n", PciDs23.Revision);
\r
1351 " Class Code 0x%06X\n",
\r
1352 (UINT32) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))
\r
1354 fprintf (stdout, " Image size 0x%X\n", PciDs23.ImageLength * 512);
\r
1355 fprintf (stdout, " Code revision: 0x%04X\n", PciDs23.CodeRevision);
\r
1356 fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs23.Indicator);
\r
1360 " Signature %c%c%c%c\n",
\r
1361 (char) PciDs30.Signature,
\r
1362 (char) (PciDs30.Signature >> 8),
\r
1363 (char) (PciDs30.Signature >> 16),
\r
1364 (char) (PciDs30.Signature >> 24)
\r
1366 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs30.VendorId);
\r
1367 fprintf (stdout, " Device ID 0x%04X\n", PciDs30.DeviceId);
\r
1368 fprintf (stdout, " Length 0x%04X\n", PciDs30.Length);
\r
1369 fprintf (stdout, " Revision 0x%04X\n", PciDs30.Revision);
\r
1370 fprintf (stdout, " DeviceListOffset 0x%02X\n", (UINT32) PciDs30.DeviceListOffset);
\r
1373 " Class Code 0x%06X\n",
\r
1374 (UINT32) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))
\r
1376 fprintf (stdout, " Image size 0x%X\n", PciDs30.ImageLength * 512);
\r
1377 fprintf (stdout, " Code revision: 0x%04X\n", PciDs30.CodeRevision);
\r
1378 fprintf (stdout, " MaxRuntimeImageLength 0x%02X\n", (UINT32) PciDs30.MaxRuntimeImageLength);
\r
1379 fprintf (stdout, " ConfigUtilityCodeHeaderOffset 0x%02X\n", (UINT32) PciDs30.ConfigUtilityCodeHeaderOffset);
\r
1380 fprintf (stdout, " DMTFCLPEntryPointOffset 0x%02X\n", (UINT32) PciDs30.DMTFCLPEntryPointOffset);
\r
1381 fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs30.Indicator);
\r
1384 // Print the indicator, used to flag the last image
\r
1386 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
\r
1387 fprintf (stdout, " (last image)\n");
\r
1389 fprintf (stdout, "\n");
\r
1392 // Print the code type. If EFI code, then we can provide more info.
\r
1394 if (mOptions.Pci23 == 1) {
\r
1395 fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs23.CodeType);
\r
1397 fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs30.CodeType);
\r
1399 if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
\r
1400 fprintf (stdout, " (EFI image)\n");
\r
1402 // Re-read the header as an EFI ROM header, then dump more info
\r
1404 fprintf (stdout, " EFI ROM header contents\n");
\r
1405 if (fseek (InFptr, ImageStart, SEEK_SET)) {
\r
1406 Error(NULL, 0, 5001, "Failed to re-seek to ROM header structure");
\r
1410 if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {
\r
1411 Error(NULL, 0, 5001, "Failed to read EFI PCI ROM header from file");
\r
1415 // Now dump more info
\r
1417 fprintf (stdout, " EFI Signature 0x%04X\n", EfiRomHdr.EfiSignature);
\r
1420 " Compression Type 0x%04X ",
\r
1421 (UINT32) EfiRomHdr.CompressionType
\r
1423 if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
\r
1424 fprintf (stdout, "(compressed)\n");
\r
1426 fprintf (stdout, "(not compressed)\n");
\r
1431 " Machine type 0x%04X (%s)\n",
\r
1432 EfiRomHdr.EfiMachineType,
\r
1433 GetMachineTypeStr (EfiRomHdr.EfiMachineType)
\r
1437 " Subsystem 0x%04X (%s)\n",
\r
1438 EfiRomHdr.EfiSubsystem,
\r
1439 GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)
\r
1443 " EFI image offset 0x%04X (@0x%X)\n",
\r
1444 (UINT32) EfiRomHdr.EfiImageHeaderOffset,
\r
1445 (UINT32) (EfiRomHdr.EfiImageHeaderOffset + ImageStart)
\r
1450 // Not an EFI image
\r
1452 fprintf (stdout, "\n");
\r
1455 // If code type is EFI image, then dump it as well?
\r
1457 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
\r
1460 // If last image, then we're done
\r
1462 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {
\r
1466 // Seek to the start of the next image
\r
1468 if (mOptions.Pci23 == 1) {
\r
1469 if (fseek (InFptr, ImageStart + (PciDs23.ImageLength * 512), SEEK_SET)) {
\r
1470 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image");
\r
1474 if (fseek (InFptr, ImageStart + (PciDs30.ImageLength * 512), SEEK_SET)) {
\r
1475 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image");
\r
1486 GetMachineTypeStr (
\r
1487 UINT16 MachineType
\r
1491 Routine Description:
\r
1493 GC_TODO: Add function description
\r
1497 MachineType - GC_TODO: add argument description
\r
1501 GC_TODO: add return values
\r
1507 for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {
\r
1508 if (mMachineTypes[Index].Value == MachineType) {
\r
1509 return mMachineTypes[Index].Name;
\r
1518 GetSubsystemTypeStr (
\r
1519 UINT16 SubsystemType
\r
1523 Routine Description:
\r
1525 GC_TODO: Add function description
\r
1529 SubsystemType - GC_TODO: add argument description
\r
1533 GC_TODO: add return values
\r
1539 for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {
\r
1540 if (mSubsystemTypes[Index].Value == SubsystemType) {
\r
1541 return mSubsystemTypes[Index].Name;
\r