]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/EfiLdrImage/EfiLdrImage.c
79618677f6569842d23bc4f1a18e5cfc7a601b5a
[mirror_edk2.git] / BaseTools / Source / C / EfiLdrImage / EfiLdrImage.c
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 exit (0);
79 }
80
81 VOID
82 Usage (
83 VOID
84 )
85 {
86 printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
87 printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
88 printf ("Copyright (c) 1999-2016 Intel Corporation. All rights reserved.\n");
89 printf ("\n The EfiLdrImage tool is used to combine PE files into EFILDR image with Efi loader header.\n");
90 }
91
92 EFI_STATUS
93 CountVerboseLevel (
94 IN CONST CHAR8* VerboseLevelString,
95 IN CONST UINT64 Length,
96 OUT UINT64 *ReturnValue
97 )
98 {
99 UINT64 i = 0;
100 for (;i < Length; ++i) {
101 if (VerboseLevelString[i] != 'v' && VerboseLevelString[i] != 'V') {
102 return EFI_ABORTED;
103 }
104 ++(*ReturnValue);
105 }
106
107 return EFI_SUCCESS;
108 }
109
110 UINT64
111 FCopyFile (
112 FILE *in,
113 FILE *out
114 )
115 /*++
116 Routine Description:
117 Write all the content of input file to output file.
118
119 Arguments:
120 in - input file pointer
121 out - output file pointer
122
123 Return:
124 UINT64 : file size of input file
125 --*/
126 {
127 UINT32 filesize, offset, length;
128 CHAR8 Buffer[8*1024];
129
130 fseek (in, 0, SEEK_END);
131 filesize = ftell(in);
132
133 fseek (in, 0, SEEK_SET);
134
135 offset = 0;
136 while (offset < filesize) {
137 length = sizeof(Buffer);
138 if (filesize-offset < length) {
139 length = filesize-offset;
140 }
141
142 fread (Buffer, length, 1, in);
143 fwrite (Buffer, length, 1, out);
144 offset += length;
145 }
146
147 return filesize;
148 }
149
150
151 int
152 main (
153 int argc,
154 char *argv[]
155 )
156 /*++
157
158 Routine Description:
159
160
161 Arguments:
162
163
164 Returns:
165
166
167 --*/
168 {
169 UINT64 i;
170 UINT64 filesize;
171 FILE *fpIn, *fpOut;
172 EFILDR_HEADER EfiLdrHeader;
173 EFILDR_IMAGE EfiLdrImage[MAX_PE_IMAGES];
174 CHAR8* OutputFileName = NULL;
175 CHAR8* InputFileNames[MAX_PE_IMAGES + 1];
176 UINT8 InputFileCount = 0;
177 UINT64 DebugLevel = 0;
178 UINT64 VerboseLevel = 0;
179 EFI_STATUS Status = EFI_SUCCESS;
180
181 SetUtilityName (UTILITY_NAME);
182
183 if (argc == 1) {
184 printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
185 return STATUS_ERROR;
186 }
187
188 argc --;
189 argv ++;
190
191 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
192 Usage();
193 return STATUS_SUCCESS;
194 }
195
196 if (stricmp (argv[0], "--version") == 0) {
197 Version();
198 return STATUS_SUCCESS;
199 }
200
201 while (argc > 0) {
202
203 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
204 OutputFileName = argv[1];
205 if (OutputFileName == NULL) {
206 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be null");
207 return STATUS_ERROR;
208 }
209 argc -= 2;
210 argv += 2;
211 continue;
212 }
213
214 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
215 argc --;
216 argv ++;
217 continue;
218 }
219
220 if ((strlen(argv[0]) >= 2 && argv[0][0] == '-' && (argv[0][1] == 'v' || argv[0][1] == 'V')) || (stricmp (argv[0], "--verbose") == 0)) {
221 VerboseLevel = 1;
222 if (strlen(argv[0]) > 2) {
223 Status = CountVerboseLevel (&argv[0][2], strlen(argv[0]) - 2, &VerboseLevel);
224 if (EFI_ERROR (Status)) {
225 Error (NULL, 0, 1003, "Invalid option value", argv[0]);
226 return STATUS_ERROR;
227 }
228 }
229
230 argc --;
231 argv ++;
232 continue;
233 }
234
235 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
236 Status = AsciiStringToUint64 (argv[1], FALSE, &DebugLevel);
237 if (EFI_ERROR (Status)) {
238 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
239 return STATUS_ERROR;
240 }
241 argc -= 2;
242 argv += 2;
243 continue;
244 }
245 //
246 // Don't recognize the parameter, should be regarded as the input file name.
247 //
248 InputFileNames[InputFileCount] = argv[0];
249 InputFileCount++;
250 argc--;
251 argv++;
252 }
253
254 if (InputFileCount == 0) {
255 Error (NULL, 0, 1001, "Missing option", "No input file");
256 return STATUS_ERROR;
257 }
258 //
259 // Open output file for write
260 //
261 if (OutputFileName == NULL) {
262 Error (NULL, 0, 1001, "Missing option", "No output file");
263 return STATUS_ERROR;
264 }
265
266 fpOut = fopen (LongFilePath (OutputFileName), "w+b");
267 if (!fpOut) {
268 Error (NULL, 0, 0001, "Could not open output file", OutputFileName);
269 return STATUS_ERROR;
270 }
271
272 memset (&EfiLdrHeader, 0, sizeof (EfiLdrHeader));
273 memset (&EfiLdrImage, 0, sizeof (EFILDR_IMAGE) * (InputFileCount));
274
275 memcpy (&EfiLdrHeader.Signature, "EFIL", 4);
276 EfiLdrHeader.FileLength = sizeof(EFILDR_HEADER) + sizeof(EFILDR_IMAGE)*(InputFileCount);
277
278 //
279 // Skip the file header first
280 //
281 fseek (fpOut, EfiLdrHeader.FileLength, SEEK_SET);
282
283 //
284 // copy all the input files to the output file
285 //
286 for(i=0;i<InputFileCount;i++) {
287 //
288 // Copy the content of PeImage file to output file
289 //
290 fpIn = fopen (LongFilePath (InputFileNames[i]), "rb");
291 if (!fpIn) {
292 Error (NULL, 0, 0001, "Could not open input file", InputFileNames[i]);
293 fclose (fpOut);
294 return STATUS_ERROR;
295 }
296 filesize = FCopyFile (fpIn, fpOut);
297 fclose(fpIn);
298
299 //
300 // And in the same time update the EfiLdrHeader and EfiLdrImage array
301 //
302 EfiLdrImage[i].Offset = EfiLdrHeader.FileLength;
303 EfiLdrImage[i].Length = (UINT32) filesize;
304 strncpy ((CHAR8*) EfiLdrImage[i].FileName, InputFileNames[i], sizeof (EfiLdrImage[i].FileName) - 1);
305 EfiLdrHeader.FileLength += (UINT32) filesize;
306 EfiLdrHeader.NumberOfImages++;
307 }
308
309 //
310 // Write the image header to the output file finally
311 //
312 fseek (fpOut, 0, SEEK_SET);
313 fwrite (&EfiLdrHeader, sizeof(EFILDR_HEADER) , 1, fpOut);
314 fwrite (&EfiLdrImage , sizeof(EFILDR_IMAGE)*(InputFileCount), 1, fpOut);
315
316 fclose (fpOut);
317 printf ("Created %s\n", OutputFileName);
318 return 0;
319 }
320