2009-07-17 11:10:31 +02:00
|
|
|
/** @file
|
2014-08-28 15:53:34 +02:00
|
|
|
Creates and EFILDR image.
|
|
|
|
This tool combines several PE Image files together using following format denoted as EBNF:
|
|
|
|
FILE := EFILDR_HEADER
|
|
|
|
EFILDR_IMAGE +
|
|
|
|
<PeImageFileContent> +
|
|
|
|
The order of EFILDR_IMAGE is same as the order of placing PeImageFileContent.
|
|
|
|
|
2016-03-09 02:42:06 +01:00
|
|
|
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
|
2010-05-18 07:04:32 +02:00
|
|
|
This program and the accompanying materials
|
2009-07-17 11:10:31 +02:00
|
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "ParseInf.h"
|
|
|
|
#include "CommonLib.h"
|
|
|
|
#include "EfiUtilityMsgs.h"
|
|
|
|
|
|
|
|
#define MAX_PE_IMAGES 63
|
|
|
|
#define FILE_TYPE_FIXED_LOADER 0
|
|
|
|
#define FILE_TYPE_RELOCATABLE_PE_IMAGE 1
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
UINT32 CheckSum;
|
|
|
|
UINT32 Offset;
|
|
|
|
UINT32 Length;
|
|
|
|
UINT8 FileName[52];
|
|
|
|
} EFILDR_IMAGE;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
UINT32 Signature;
|
|
|
|
UINT32 HeaderCheckSum;
|
|
|
|
UINT32 FileLength;
|
|
|
|
UINT32 NumberOfImages;
|
|
|
|
} EFILDR_HEADER;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Utility Name
|
|
|
|
//
|
|
|
|
#define UTILITY_NAME "EfiLdrImage"
|
|
|
|
|
|
|
|
//
|
|
|
|
// Utility version information
|
|
|
|
//
|
2016-03-09 02:42:06 +01:00
|
|
|
#define UTILITY_MAJOR_VERSION 1
|
|
|
|
#define UTILITY_MINOR_VERSION 0
|
2009-07-17 11:10:31 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
Version (
|
|
|
|
void
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Displays the standard utility information to SDTOUT
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
2016-03-09 02:42:06 +01:00
|
|
|
printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
|
2009-07-17 11:10:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
Usage (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
|
2016-03-09 02:42:06 +01:00
|
|
|
printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
|
|
|
|
printf ("Copyright (c) 1999-2016 Intel Corporation. All rights reserved.\n");
|
|
|
|
printf ("\n The EfiLdrImage tool is used to combine PE files into EFILDR image with Efi loader header.\n");
|
2009-07-17 11:10:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
CountVerboseLevel (
|
|
|
|
IN CONST CHAR8* VerboseLevelString,
|
|
|
|
IN CONST UINT64 Length,
|
|
|
|
OUT UINT64 *ReturnValue
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT64 i = 0;
|
|
|
|
for (;i < Length; ++i) {
|
|
|
|
if (VerboseLevelString[i] != 'v' && VerboseLevelString[i] != 'V') {
|
|
|
|
return EFI_ABORTED;
|
|
|
|
}
|
|
|
|
++(*ReturnValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT64
|
|
|
|
FCopyFile (
|
|
|
|
FILE *in,
|
|
|
|
FILE *out
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write all the content of input file to output file.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
in - input file pointer
|
|
|
|
out - output file pointer
|
|
|
|
|
|
|
|
Return:
|
|
|
|
UINT64 : file size of input file
|
|
|
|
--*/
|
|
|
|
{
|
2009-09-11 05:14:43 +02:00
|
|
|
UINT32 filesize, offset, length;
|
2009-07-17 11:10:31 +02:00
|
|
|
CHAR8 Buffer[8*1024];
|
|
|
|
|
|
|
|
fseek (in, 0, SEEK_END);
|
|
|
|
filesize = ftell(in);
|
|
|
|
|
|
|
|
fseek (in, 0, SEEK_SET);
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
while (offset < filesize) {
|
|
|
|
length = sizeof(Buffer);
|
|
|
|
if (filesize-offset < length) {
|
|
|
|
length = filesize-offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
fread (Buffer, length, 1, in);
|
|
|
|
fwrite (Buffer, length, 1, out);
|
|
|
|
offset += length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return filesize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
main (
|
|
|
|
int argc,
|
|
|
|
char *argv[]
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UINT64 i;
|
|
|
|
UINT64 filesize;
|
|
|
|
FILE *fpIn, *fpOut;
|
|
|
|
EFILDR_HEADER EfiLdrHeader;
|
|
|
|
EFILDR_IMAGE EfiLdrImage[MAX_PE_IMAGES];
|
|
|
|
CHAR8* OutputFileName = NULL;
|
|
|
|
CHAR8* InputFileNames[MAX_PE_IMAGES + 1];
|
|
|
|
UINT8 InputFileCount = 0;
|
|
|
|
UINT64 DebugLevel = 0;
|
|
|
|
UINT64 VerboseLevel = 0;
|
|
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
|
|
|
|
SetUtilityName (UTILITY_NAME);
|
|
|
|
|
|
|
|
if (argc == 1) {
|
2016-03-09 02:42:06 +01:00
|
|
|
printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
|
2009-07-17 11:10:31 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
argc --;
|
|
|
|
argv ++;
|
|
|
|
|
|
|
|
if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
|
|
|
|
Usage();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stricmp (argv[0], "--version") == 0) {
|
|
|
|
Version();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (argc > 0) {
|
|
|
|
|
|
|
|
if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
|
|
|
|
OutputFileName = argv[1];
|
|
|
|
if (OutputFileName == NULL) {
|
|
|
|
Error (NULL, 0, 1003, "Invalid option value", "Output file can't be null");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
|
|
|
|
argc --;
|
|
|
|
argv ++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((strlen(argv[0]) >= 2 && argv[0][0] == '-' && (argv[0][1] == 'v' || argv[0][1] == 'V')) || (stricmp (argv[0], "--verbose") == 0)) {
|
|
|
|
VerboseLevel = 1;
|
|
|
|
if (strlen(argv[0]) > 2) {
|
|
|
|
Status = CountVerboseLevel (&argv[0][2], strlen(argv[0]) - 2, &VerboseLevel);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
Error (NULL, 0, 1003, "Invalid option value", argv[0]);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc --;
|
|
|
|
argv ++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
|
|
|
|
Status = AsciiStringToUint64 (argv[1], FALSE, &DebugLevel);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
2009-09-11 05:14:43 +02:00
|
|
|
// Don't recognize the parameter, should be regarded as the input file name.
|
2009-07-17 11:10:31 +02:00
|
|
|
//
|
|
|
|
InputFileNames[InputFileCount] = argv[0];
|
|
|
|
InputFileCount++;
|
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InputFileCount == 0) {
|
|
|
|
Error (NULL, 0, 1001, "Missing option", "No input file");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Open output file for write
|
|
|
|
//
|
|
|
|
if (OutputFileName == NULL) {
|
|
|
|
Error (NULL, 0, 1001, "Missing option", "No output file");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
2014-08-15 05:06:48 +02:00
|
|
|
fpOut = fopen (LongFilePath (OutputFileName), "w+b");
|
2009-07-17 11:10:31 +02:00
|
|
|
if (!fpOut) {
|
|
|
|
Error (NULL, 0, 0001, "Could not open output file", OutputFileName);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset (&EfiLdrHeader, 0, sizeof (EfiLdrHeader));
|
|
|
|
memset (&EfiLdrImage, 0, sizeof (EFILDR_IMAGE) * (InputFileCount));
|
|
|
|
|
|
|
|
memcpy (&EfiLdrHeader.Signature, "EFIL", 4);
|
|
|
|
EfiLdrHeader.FileLength = sizeof(EFILDR_HEADER) + sizeof(EFILDR_IMAGE)*(InputFileCount);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Skip the file header first
|
|
|
|
//
|
|
|
|
fseek (fpOut, EfiLdrHeader.FileLength, SEEK_SET);
|
|
|
|
|
|
|
|
//
|
|
|
|
// copy all the input files to the output file
|
|
|
|
//
|
|
|
|
for(i=0;i<InputFileCount;i++) {
|
|
|
|
//
|
|
|
|
// Copy the content of PeImage file to output file
|
|
|
|
//
|
2014-08-15 05:06:48 +02:00
|
|
|
fpIn = fopen (LongFilePath (InputFileNames[i]), "rb");
|
2009-07-17 11:10:31 +02:00
|
|
|
if (!fpIn) {
|
|
|
|
Error (NULL, 0, 0001, "Could not open input file", InputFileNames[i]);
|
|
|
|
fclose (fpOut);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
filesize = FCopyFile (fpIn, fpOut);
|
|
|
|
fclose(fpIn);
|
|
|
|
|
|
|
|
//
|
|
|
|
// And in the same time update the EfiLdrHeader and EfiLdrImage array
|
|
|
|
//
|
|
|
|
EfiLdrImage[i].Offset = EfiLdrHeader.FileLength;
|
2009-09-11 05:14:43 +02:00
|
|
|
EfiLdrImage[i].Length = (UINT32) filesize;
|
2009-07-17 11:10:31 +02:00
|
|
|
strncpy ((CHAR8*) EfiLdrImage[i].FileName, InputFileNames[i], sizeof (EfiLdrImage[i].FileName) - 1);
|
2009-09-11 05:14:43 +02:00
|
|
|
EfiLdrHeader.FileLength += (UINT32) filesize;
|
2009-07-17 11:10:31 +02:00
|
|
|
EfiLdrHeader.NumberOfImages++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Write the image header to the output file finally
|
|
|
|
//
|
|
|
|
fseek (fpOut, 0, SEEK_SET);
|
|
|
|
fwrite (&EfiLdrHeader, sizeof(EFILDR_HEADER) , 1, fpOut);
|
|
|
|
fwrite (&EfiLdrImage , sizeof(EFILDR_IMAGE)*(InputFileCount), 1, fpOut);
|
|
|
|
|
|
|
|
fclose (fpOut);
|
|
|
|
printf ("Created %s\n", OutputFileName);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|