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