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 - 2014, 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 0
55 #define UTILITY_MINOR_VERSION 1
56 
57 void
Version(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 %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
78   printf ("Copyright (c) 1999-2014 Intel Corporation. All rights reserved.\n");
79   printf ("\n  The EfiLdrImage tool is used to combine PE files into EFILDR image with Efi loader header.\n");
80 }
81 
82 VOID
Usage(VOID)83 Usage (
84   VOID
85   )
86 {
87   printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
88   exit (1);
89 }
90 
91 EFI_STATUS
CountVerboseLevel(IN CONST CHAR8 * VerboseLevelString,IN CONST UINT64 Length,OUT UINT64 * ReturnValue)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
FCopyFile(FILE * in,FILE * out)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
main(int argc,char * argv[])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     Usage();
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