Home | History | Annotate | Download | only in EfiLdrImage
      1 /** @file
      2 Creates and EFILDR image.
      3 This tool combines several PE Image files together using following format denoted as EBNF:
      4 FILE := EFILDR_HEADER
      5         EFILDR_IMAGE +
      6         <PeImageFileContent> +
      7 The order of EFILDR_IMAGE is same as the order of placing PeImageFileContent.
      8 
      9 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
     10 This program and the accompanying materials
     11 are licensed and made available under the terms and conditions of the BSD License
     12 which accompanies this distribution.  The full text of the license may be found at
     13 http://opensource.org/licenses/bsd-license.php
     14 
     15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     17 
     18 **/
     19 
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include "ParseInf.h"
     25 #include "CommonLib.h"
     26 #include "EfiUtilityMsgs.h"
     27 
     28 #define MAX_PE_IMAGES                  63
     29 #define FILE_TYPE_FIXED_LOADER         0
     30 #define FILE_TYPE_RELOCATABLE_PE_IMAGE 1
     31 
     32 typedef struct {
     33   UINT32 CheckSum;
     34   UINT32 Offset;
     35   UINT32 Length;
     36   UINT8  FileName[52];
     37 } EFILDR_IMAGE;
     38 
     39 typedef struct {
     40   UINT32       Signature;
     41   UINT32       HeaderCheckSum;
     42   UINT32       FileLength;
     43   UINT32       NumberOfImages;
     44 } EFILDR_HEADER;
     45 
     46 //
     47 // Utility Name
     48 //
     49 #define UTILITY_NAME  "EfiLdrImage"
     50 
     51 //
     52 // Utility version information
     53 //
     54 #define UTILITY_MAJOR_VERSION 1
     55 #define UTILITY_MINOR_VERSION 0
     56 
     57 void
     58 Version (
     59   void
     60   )
     61 /*++
     62 
     63 Routine Description:
     64 
     65   Displays the standard utility information to SDTOUT
     66 
     67 Arguments:
     68 
     69   None
     70 
     71 Returns:
     72 
     73   None
     74 
     75 --*/
     76 {
     77   printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
     78 }
     79 
     80 VOID
     81 Usage (
     82   VOID
     83   )
     84 {
     85   printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
     86   printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
     87   printf ("Copyright (c) 1999-2016 Intel Corporation. All rights reserved.\n");
     88   printf ("\n  The EfiLdrImage tool is used to combine PE files into EFILDR image with Efi loader header.\n");
     89 }
     90 
     91 EFI_STATUS
     92 CountVerboseLevel (
     93   IN CONST CHAR8* VerboseLevelString,
     94   IN CONST UINT64 Length,
     95   OUT UINT64 *ReturnValue
     96 )
     97 {
     98   UINT64 i = 0;
     99   for (;i < Length; ++i) {
    100     if (VerboseLevelString[i] != 'v' && VerboseLevelString[i] != 'V') {
    101       return EFI_ABORTED;
    102     }
    103     ++(*ReturnValue);
    104   }
    105 
    106   return EFI_SUCCESS;
    107 }
    108 
    109 UINT64
    110 FCopyFile (
    111   FILE    *in,
    112   FILE    *out
    113   )
    114 /*++
    115 Routine Description:
    116   Write all the content of input file to output file.
    117 
    118 Arguments:
    119   in  - input file pointer
    120   out - output file pointer
    121 
    122 Return:
    123   UINT64 : file size of input file
    124 --*/
    125 {
    126   UINT32          filesize, offset, length;
    127   CHAR8           Buffer[8*1024];
    128 
    129   fseek (in, 0, SEEK_END);
    130   filesize = ftell(in);
    131 
    132   fseek (in, 0, SEEK_SET);
    133 
    134   offset = 0;
    135   while (offset < filesize)  {
    136     length = sizeof(Buffer);
    137     if (filesize-offset < length) {
    138       length = filesize-offset;
    139     }
    140 
    141     fread (Buffer, length, 1, in);
    142     fwrite (Buffer, length, 1, out);
    143     offset += length;
    144   }
    145 
    146   return filesize;
    147 }
    148 
    149 
    150 int
    151 main (
    152   int argc,
    153   char *argv[]
    154   )
    155 /*++
    156 
    157 Routine Description:
    158 
    159 
    160 Arguments:
    161 
    162 
    163 Returns:
    164 
    165 
    166 --*/
    167 {
    168   UINT64         i;
    169   UINT64         filesize;
    170   FILE          *fpIn, *fpOut;
    171   EFILDR_HEADER EfiLdrHeader;
    172   EFILDR_IMAGE  EfiLdrImage[MAX_PE_IMAGES];
    173   CHAR8* OutputFileName = NULL;
    174   CHAR8* InputFileNames[MAX_PE_IMAGES + 1];
    175   UINT8 InputFileCount = 0;
    176   UINT64        DebugLevel = 0;
    177   UINT64        VerboseLevel = 0;
    178   EFI_STATUS Status = EFI_SUCCESS;
    179 
    180   SetUtilityName (UTILITY_NAME);
    181 
    182   if (argc == 1) {
    183     printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
    184     return STATUS_ERROR;
    185   }
    186 
    187   argc --;
    188   argv ++;
    189 
    190   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
    191     Usage();
    192     return STATUS_SUCCESS;
    193   }
    194 
    195   if (stricmp (argv[0], "--version") == 0) {
    196     Version();
    197     return STATUS_SUCCESS;
    198   }
    199 
    200   while (argc > 0) {
    201 
    202     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
    203       OutputFileName = argv[1];
    204       if (OutputFileName == NULL) {
    205         Error (NULL, 0, 1003, "Invalid option value", "Output file can't be null");
    206         return STATUS_ERROR;
    207       }
    208       argc -= 2;
    209       argv += 2;
    210       continue;
    211     }
    212 
    213     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
    214       argc --;
    215       argv ++;
    216       continue;
    217     }
    218 
    219     if ((strlen(argv[0]) >= 2 && argv[0][0] == '-' && (argv[0][1] == 'v' || argv[0][1] == 'V')) || (stricmp (argv[0], "--verbose") == 0)) {
    220       VerboseLevel = 1;
    221       if (strlen(argv[0]) > 2) {
    222         Status = CountVerboseLevel (&argv[0][2], strlen(argv[0]) - 2, &VerboseLevel);
    223         if (EFI_ERROR (Status)) {
    224           Error (NULL, 0, 1003, "Invalid option value", argv[0]);
    225           return STATUS_ERROR;
    226         }
    227       }
    228 
    229       argc --;
    230       argv ++;
    231       continue;
    232     }
    233 
    234     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
    235       Status = AsciiStringToUint64 (argv[1], FALSE, &DebugLevel);
    236       if (EFI_ERROR (Status)) {
    237         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
    238         return STATUS_ERROR;
    239       }
    240       argc -= 2;
    241       argv += 2;
    242       continue;
    243     }
    244     //
    245     // Don't recognize the parameter, should be regarded as the input file name.
    246     //
    247     InputFileNames[InputFileCount] = argv[0];
    248     InputFileCount++;
    249     argc--;
    250     argv++;
    251   }
    252 
    253   if (InputFileCount == 0) {
    254     Error (NULL, 0, 1001, "Missing option", "No input file");
    255     return STATUS_ERROR;
    256   }
    257   //
    258   // Open output file for write
    259   //
    260   if (OutputFileName == NULL) {
    261     Error (NULL, 0, 1001, "Missing option", "No output file");
    262     return STATUS_ERROR;
    263   }
    264 
    265   fpOut = fopen (LongFilePath (OutputFileName), "w+b");
    266   if (!fpOut) {
    267     Error (NULL, 0, 0001, "Could not open output file", OutputFileName);
    268     return STATUS_ERROR;
    269   }
    270 
    271   memset (&EfiLdrHeader, 0, sizeof (EfiLdrHeader));
    272   memset (&EfiLdrImage, 0, sizeof (EFILDR_IMAGE) * (InputFileCount));
    273 
    274   memcpy (&EfiLdrHeader.Signature, "EFIL", 4);
    275   EfiLdrHeader.FileLength = sizeof(EFILDR_HEADER) + sizeof(EFILDR_IMAGE)*(InputFileCount);
    276 
    277   //
    278   // Skip the file header first
    279   //
    280   fseek (fpOut, EfiLdrHeader.FileLength, SEEK_SET);
    281 
    282   //
    283   // copy all the input files to the output file
    284   //
    285   for(i=0;i<InputFileCount;i++) {
    286     //
    287     // Copy the content of PeImage file to output file
    288     //
    289     fpIn = fopen (LongFilePath (InputFileNames[i]), "rb");
    290     if (!fpIn) {
    291       Error (NULL, 0, 0001, "Could not open input file", InputFileNames[i]);
    292       fclose (fpOut);
    293       return STATUS_ERROR;
    294     }
    295     filesize = FCopyFile (fpIn, fpOut);
    296     fclose(fpIn);
    297 
    298     //
    299     //  And in the same time update the EfiLdrHeader and EfiLdrImage array
    300     //
    301     EfiLdrImage[i].Offset = EfiLdrHeader.FileLength;
    302     EfiLdrImage[i].Length = (UINT32) filesize;
    303     strncpy ((CHAR8*) EfiLdrImage[i].FileName, InputFileNames[i], sizeof (EfiLdrImage[i].FileName) - 1);
    304     EfiLdrHeader.FileLength += (UINT32) filesize;
    305     EfiLdrHeader.NumberOfImages++;
    306   }
    307 
    308   //
    309   // Write the image header to the output file finally
    310   //
    311   fseek (fpOut, 0, SEEK_SET);
    312   fwrite (&EfiLdrHeader, sizeof(EFILDR_HEADER)        , 1, fpOut);
    313   fwrite (&EfiLdrImage , sizeof(EFILDR_IMAGE)*(InputFileCount), 1, fpOut);
    314 
    315   fclose (fpOut);
    316   printf ("Created %s\n", OutputFileName);
    317   return 0;
    318 }
    319 
    320