Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Yonghong Zhu <yonghong.zhu@intel.com>
		
			
				
	
	
		
			321 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			321 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Creates and EFILDR image.
 | |
| This tool combines several PE Image files together using following format denoted as EBNF:
 | |
| FILE := EFILDR_HEADER
 | |
|         EFILDR_IMAGE +
 | |
|         <PeImageFileContent> +
 | |
| The order of EFILDR_IMAGE is same as the order of placing PeImageFileContent.
 | |
|   
 | |
| Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include "ParseInf.h"
 | |
| #include "CommonLib.h"
 | |
| #include "EfiUtilityMsgs.h"
 | |
| 
 | |
| #define MAX_PE_IMAGES                  63
 | |
| #define FILE_TYPE_FIXED_LOADER         0
 | |
| #define FILE_TYPE_RELOCATABLE_PE_IMAGE 1
 | |
| 
 | |
| typedef struct {
 | |
|   UINT32 CheckSum;
 | |
|   UINT32 Offset;
 | |
|   UINT32 Length;
 | |
|   UINT8  FileName[52];
 | |
| } EFILDR_IMAGE;
 | |
| 
 | |
| typedef struct {          
 | |
|   UINT32       Signature;     
 | |
|   UINT32       HeaderCheckSum;
 | |
|   UINT32       FileLength;
 | |
|   UINT32       NumberOfImages;
 | |
| } EFILDR_HEADER;
 | |
| 
 | |
| //
 | |
| // Utility Name
 | |
| //
 | |
| #define UTILITY_NAME  "EfiLdrImage"
 | |
| 
 | |
| //
 | |
| // Utility version information
 | |
| //
 | |
| #define UTILITY_MAJOR_VERSION 1
 | |
| #define UTILITY_MINOR_VERSION 0
 | |
| 
 | |
| void
 | |
| Version (
 | |
|   void
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Displays the standard utility information to SDTOUT
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   None
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
 | |
|   exit (0);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| Usage (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
 | |
|   printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
 | |
|   printf ("Copyright (c) 1999-2016 Intel Corporation. All rights reserved.\n");
 | |
|   printf ("\n  The EfiLdrImage tool is used to combine PE files into EFILDR image with Efi loader header.\n");
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| CountVerboseLevel (
 | |
|   IN CONST CHAR8* VerboseLevelString,
 | |
|   IN CONST UINT64 Length,
 | |
|   OUT UINT64 *ReturnValue
 | |
| )
 | |
| {
 | |
|   UINT64 i = 0;
 | |
|   for (;i < Length; ++i) {
 | |
|     if (VerboseLevelString[i] != 'v' && VerboseLevelString[i] != 'V') {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
|     ++(*ReturnValue);
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| UINT64
 | |
| FCopyFile (
 | |
|   FILE    *in,
 | |
|   FILE    *out
 | |
|   )
 | |
| /*++
 | |
| Routine Description:
 | |
|   Write all the content of input file to output file.
 | |
| 
 | |
| Arguments:
 | |
|   in  - input file pointer
 | |
|   out - output file pointer
 | |
| 
 | |
| Return:
 | |
|   UINT64 : file size of input file
 | |
| --*/
 | |
| {
 | |
|   UINT32          filesize, offset, length;
 | |
|   CHAR8           Buffer[8*1024];
 | |
| 
 | |
|   fseek (in, 0, SEEK_END);
 | |
|   filesize = ftell(in);
 | |
| 
 | |
|   fseek (in, 0, SEEK_SET);
 | |
| 
 | |
|   offset = 0;
 | |
|   while (offset < filesize)  {
 | |
|     length = sizeof(Buffer);
 | |
|     if (filesize-offset < length) {
 | |
|       length = filesize-offset;
 | |
|     }
 | |
| 
 | |
|     fread (Buffer, length, 1, in);
 | |
|     fwrite (Buffer, length, 1, out);
 | |
|     offset += length;
 | |
|   }
 | |
| 
 | |
|   return filesize;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| main (
 | |
|   int argc,
 | |
|   char *argv[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT64         i;
 | |
|   UINT64         filesize;
 | |
|   FILE          *fpIn, *fpOut;
 | |
|   EFILDR_HEADER EfiLdrHeader;
 | |
|   EFILDR_IMAGE  EfiLdrImage[MAX_PE_IMAGES];
 | |
|   CHAR8* OutputFileName = NULL;
 | |
|   CHAR8* InputFileNames[MAX_PE_IMAGES + 1];
 | |
|   UINT8 InputFileCount = 0;
 | |
|   UINT64        DebugLevel = 0;
 | |
|   UINT64        VerboseLevel = 0;
 | |
|   EFI_STATUS Status = EFI_SUCCESS;
 | |
|   
 | |
|   SetUtilityName (UTILITY_NAME);
 | |
| 
 | |
|   if (argc == 1) {
 | |
|     printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   
 | |
|   argc --;
 | |
|   argv ++;
 | |
| 
 | |
|   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
 | |
|     Usage();
 | |
|     return STATUS_SUCCESS;    
 | |
|   }
 | |
| 
 | |
|   if (stricmp (argv[0], "--version") == 0) {
 | |
|     Version();
 | |
|     return STATUS_SUCCESS;    
 | |
|   }
 | |
| 
 | |
|   while (argc > 0) {
 | |
|    
 | |
|     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
 | |
|       OutputFileName = argv[1];
 | |
|       if (OutputFileName == NULL) {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "Output file can't be null");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue; 
 | |
|     }
 | |
|     
 | |
|     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
 | |
|       argc --;
 | |
|       argv ++;
 | |
|       continue; 
 | |
|     }
 | |
|     
 | |
|     if ((strlen(argv[0]) >= 2 && argv[0][0] == '-' && (argv[0][1] == 'v' || argv[0][1] == 'V')) || (stricmp (argv[0], "--verbose") == 0)) {
 | |
|       VerboseLevel = 1;
 | |
|       if (strlen(argv[0]) > 2) {
 | |
|         Status = CountVerboseLevel (&argv[0][2], strlen(argv[0]) - 2, &VerboseLevel);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           Error (NULL, 0, 1003, "Invalid option value", argv[0]);
 | |
|           return STATUS_ERROR;        
 | |
|         }
 | |
|       }
 | |
|       
 | |
|       argc --;
 | |
|       argv ++;
 | |
|       continue; 
 | |
|     }
 | |
|     
 | |
|     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
 | |
|       Status = AsciiStringToUint64 (argv[1], FALSE, &DebugLevel);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
 | |
|         return STATUS_ERROR;        
 | |
|       }
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue; 
 | |
|     }
 | |
|     //
 | |
|     // Don't recognize the parameter, should be regarded as the input file name.
 | |
|     //
 | |
|     InputFileNames[InputFileCount] = argv[0];
 | |
|     InputFileCount++;
 | |
|     argc--;
 | |
|     argv++;
 | |
|   }
 | |
| 
 | |
|   if (InputFileCount == 0) {
 | |
|     Error (NULL, 0, 1001, "Missing option", "No input file");
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   //
 | |
|   // Open output file for write
 | |
|   //
 | |
|   if (OutputFileName == NULL) {
 | |
|     Error (NULL, 0, 1001, "Missing option", "No output file");
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   fpOut = fopen (LongFilePath (OutputFileName), "w+b");
 | |
|   if (!fpOut) {
 | |
|     Error (NULL, 0, 0001, "Could not open output file", OutputFileName);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   memset (&EfiLdrHeader, 0, sizeof (EfiLdrHeader));
 | |
|   memset (&EfiLdrImage, 0, sizeof (EFILDR_IMAGE) * (InputFileCount));
 | |
| 
 | |
|   memcpy (&EfiLdrHeader.Signature, "EFIL", 4);
 | |
|   EfiLdrHeader.FileLength = sizeof(EFILDR_HEADER) + sizeof(EFILDR_IMAGE)*(InputFileCount);
 | |
| 
 | |
|   //
 | |
|   // Skip the file header first
 | |
|   //
 | |
|   fseek (fpOut, EfiLdrHeader.FileLength, SEEK_SET);
 | |
| 
 | |
|   //
 | |
|   // copy all the input files to the output file
 | |
|   //
 | |
|   for(i=0;i<InputFileCount;i++) {
 | |
|     //
 | |
|     // Copy the content of PeImage file to output file
 | |
|     //
 | |
|     fpIn = fopen (LongFilePath (InputFileNames[i]), "rb");
 | |
|     if (!fpIn) {
 | |
|       Error (NULL, 0, 0001, "Could not open input file", InputFileNames[i]);
 | |
|       fclose (fpOut);
 | |
|       return STATUS_ERROR;
 | |
|     }
 | |
|     filesize = FCopyFile (fpIn, fpOut);
 | |
|     fclose(fpIn);
 | |
| 
 | |
|     //
 | |
|     //  And in the same time update the EfiLdrHeader and EfiLdrImage array
 | |
|     //
 | |
|     EfiLdrImage[i].Offset = EfiLdrHeader.FileLength;
 | |
|     EfiLdrImage[i].Length = (UINT32) filesize;
 | |
|     strncpy ((CHAR8*) EfiLdrImage[i].FileName, InputFileNames[i], sizeof (EfiLdrImage[i].FileName) - 1);
 | |
|     EfiLdrHeader.FileLength += (UINT32) filesize;
 | |
|     EfiLdrHeader.NumberOfImages++;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Write the image header to the output file finally
 | |
|   //
 | |
|   fseek (fpOut, 0, SEEK_SET);
 | |
|   fwrite (&EfiLdrHeader, sizeof(EFILDR_HEADER)        , 1, fpOut);
 | |
|   fwrite (&EfiLdrImage , sizeof(EFILDR_IMAGE)*(InputFileCount), 1, fpOut);
 | |
| 
 | |
|   fclose (fpOut);
 | |
|   printf ("Created %s\n", OutputFileName);
 | |
|   return 0;
 | |
| }
 | |
| 
 |