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