/** @file
Creates output file that is a properly formed section per the PI spec.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __GNUC__
#include
#include
#include
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include "CommonLib.h"
#include "Compress.h"
#include "Crc32.h"
#include "EfiUtilityMsgs.h"
#include "ParseInf.h"
#include "FvLib.h"
#include "PeCoffLib.h"
//
// GenSec Tool Information
//
#define UTILITY_NAME "GenSec"
#define UTILITY_MAJOR_VERSION 0
#define UTILITY_MINOR_VERSION 1
STATIC CHAR8 *mSectionTypeName[] = {
NULL, // 0x00 - reserved
"EFI_SECTION_COMPRESSION", // 0x01
"EFI_SECTION_GUID_DEFINED", // 0x02
NULL, // 0x03 - reserved
NULL, // 0x04 - reserved
NULL, // 0x05 - reserved
NULL, // 0x06 - reserved
NULL, // 0x07 - reserved
NULL, // 0x08 - reserved
NULL, // 0x09 - reserved
NULL, // 0x0A - reserved
NULL, // 0x0B - reserved
NULL, // 0x0C - reserved
NULL, // 0x0D - reserved
NULL, // 0x0E - reserved
NULL, // 0x0F - reserved
"EFI_SECTION_PE32", // 0x10
"EFI_SECTION_PIC", // 0x11
"EFI_SECTION_TE", // 0x12
"EFI_SECTION_DXE_DEPEX", // 0x13
"EFI_SECTION_VERSION", // 0x14
"EFI_SECTION_USER_INTERFACE", // 0x15
"EFI_SECTION_COMPATIBILITY16", // 0x16
"EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
"EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
"EFI_SECTION_RAW", // 0x19
NULL, // 0x1A
"EFI_SECTION_PEI_DEPEX", // 0x1B
"EFI_SECTION_SMM_DEPEX" // 0x1C
};
STATIC CHAR8 *mCompressionTypeName[] = { "PI_NONE", "PI_STD" };
#define EFI_GUIDED_SECTION_NONE 0x80
STATIC CHAR8 *mGUIDedSectionAttribue[] = { "NONE", "PROCESSING_REQUIRED", "AUTH_STATUS_VALID"};
STATIC CHAR8 *mAlignName[] = {
"1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
"1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",
"512K", "1M", "2M", "4M", "8M", "16M"
};
//
// Crc32 GUID section related definitions.
//
typedef struct {
EFI_GUID_DEFINED_SECTION GuidSectionHeader;
UINT32 CRC32Checksum;
} CRC32_SECTION_HEADER;
typedef struct {
EFI_GUID_DEFINED_SECTION2 GuidSectionHeader;
UINT32 CRC32Checksum;
} CRC32_SECTION_HEADER2;
STATIC EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
STATIC EFI_GUID mEfiCrc32SectionGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
STATIC
VOID
Version (
VOID
)
/*++
Routine Description:
Print out version information for this utility.
Arguments:
None
Returns:
None
--*/
{
fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
}
STATIC
VOID
Usage (
VOID
)
/*++
Routine Description:
Print Help message.
Arguments:
VOID
Returns:
None
--*/
{
//
// Summary usage
//
fprintf (stdout, "\nUsage: %s [options] [input_file]\n\n", UTILITY_NAME);
//
// Copyright declaration
//
fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
//
// Details Option
//
fprintf (stdout, "Options:\n");
fprintf (stdout, " -o FileName, --outputfile FileName\n\
File is the SectionFile to be created.\n");
fprintf (stdout, " -s [SectionType], --sectiontype [SectionType]\n\
SectionType defined in PI spec is one type of\n\
EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED,\n\
EFI_SECTION_PE32, EFI_SECTION_PIC, EFI_SECTION_TE,\n\
EFI_SECTION_DXE_DEPEX, EFI_SECTION_COMPATIBILITY16,\n\
EFI_SECTION_USER_INTERFACE, EFI_SECTION_VERSION,\n\
EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW,\n\
EFI_SECTION_FREEFORM_SUBTYPE_GUID,\n\
EFI_SECTION_PEI_DEPEX, EFI_SECTION_SMM_DEPEX.\n\
if -s option is not given, \n\
EFI_SECTION_ALL is default section type.\n");
fprintf (stdout, " -c [Type], --compress [Type]\n\
Compress method type can be PI_NONE or PI_STD.\n\
if -c option is not given, PI_STD is default type.\n");
fprintf (stdout, " -g GuidValue, --vendor GuidValue\n\
GuidValue is one specific vendor guid value.\n\
Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
fprintf (stdout, " -l GuidHeaderLength, --HeaderLength GuidHeaderLength\n\
GuidHeaderLength is the size of header of guided data\n");
fprintf (stdout, " -r GuidAttr, --attributes GuidAttr\n\
GuidAttr is guid section attributes, which may be\n\
PROCESSING_REQUIRED, AUTH_STATUS_VALID and NONE. \n\
if -r option is not given, default PROCESSING_REQUIRED\n");
fprintf (stdout, " -n String, --name String\n\
String is a NULL terminated string used in Ui section.\n");
fprintf (stdout, " -j Number, --buildnumber Number\n\
Number is an integer value between 0 and 65535\n\
used in Ver section.\n");
fprintf (stdout, " --sectionalign SectionAlign\n\
SectionAlign points to section alignment, which support\n\
the alignment scope 0~16M. If SectionAlign is specified\n\
as 0, tool get alignment value from SectionFile. It is\n\
specified in same order that the section file is input.\n");
fprintf (stdout, " --dummy dummyfile\n\
compare dummyfile with input_file to decide whether\n\
need to set PROCESSING_REQUIRED attribute.\n");
fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
fprintf (stdout, " --version Show program's version number and exit.\n");
fprintf (stdout, " -h, --help Show this help message and exit.\n");
}
VOID
Ascii2UnicodeString (
CHAR8 *String,
CHAR16 *UniString
)
/*++
Routine Description:
Write ascii string as unicode string format to FILE
Arguments:
String - Pointer to string that is written to FILE.
UniString - Pointer to unicode string
Returns:
NULL
--*/
{
while (*String != '\0') {
*(UniString++) = (CHAR16) *(String++);
}
//
// End the UniString with a NULL.
//
*UniString = '\0';
}
STATUS
GenSectionCommonLeafSection (
CHAR8 **InputFileName,
UINT32 InputFileNum,
UINT8 SectionType,
UINT8 **OutFileBuffer
)
/*++
Routine Description:
Generate a leaf section of type other than EFI_SECTION_VERSION
and EFI_SECTION_USER_INTERFACE. Input file must be well formed.
The function won't validate the input file's contents. For
common leaf sections, the input file may be a binary file.
The utility will add section header to the file.
Arguments:
InputFileName - Name of the input file.
InputFileNum - Number of input files. Should be 1 for leaf section.
SectionType - A valid section type string
OutFileBuffer - Buffer pointer to Output file contents
Returns:
STATUS_ERROR - can't continue
STATUS_SUCCESS - successful return
--*/
{
UINT32 InputFileLength;
FILE *InFile;
UINT8 *Buffer;
UINT32 TotalLength;
UINT32 HeaderLength;
EFI_COMMON_SECTION_HEADER *CommonSect;
STATUS Status;
if (InputFileNum > 1) {
Error (NULL, 0, 2000, "Invalid parameter", "more than one input file specified");
return STATUS_ERROR;
} else if (InputFileNum < 1) {
Error (NULL, 0, 2000, "Invalid parameter", "no input file specified");
return STATUS_ERROR;
}
//
// Open the input file
//
InFile = fopen (LongFilePath (InputFileName[0]), "rb");
if (InFile == NULL) {
Error (NULL, 0, 0001, "Error opening file", InputFileName[0]);
return STATUS_ERROR;
}
Status = STATUS_ERROR;
Buffer = NULL;
//
// Seek to the end of the input file so we can determine its size
//
fseek (InFile, 0, SEEK_END);
InputFileLength = ftell (InFile);
fseek (InFile, 0, SEEK_SET);
DebugMsg (NULL, 0, 9, "Input file", "File name is %s and File size is %u bytes", InputFileName[0], (unsigned) InputFileLength);
TotalLength = sizeof (EFI_COMMON_SECTION_HEADER) + InputFileLength;
//
// Size must fit in 3 bytes
//
//if (TotalLength >= MAX_SECTION_SIZE) {
// Error (NULL, 0, 2000, "Invalid parameter", "%s file size (0x%X) exceeds section size limit(%uM).", InputFileName[0], (unsigned) TotalLength, MAX_SECTION_SIZE>>20);
// goto Done;
//}
HeaderLength = sizeof (EFI_COMMON_SECTION_HEADER);
if (TotalLength >= MAX_SECTION_SIZE) {
TotalLength = sizeof (EFI_COMMON_SECTION_HEADER2) + InputFileLength;
HeaderLength = sizeof (EFI_COMMON_SECTION_HEADER2);
}
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
//
// Fill in the fields in the local section header structure
//
Buffer = (UINT8 *) malloc ((size_t) TotalLength);
if (Buffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Done;
}
CommonSect = (EFI_COMMON_SECTION_HEADER *) Buffer;
CommonSect->Type = SectionType;
if (TotalLength < MAX_SECTION_SIZE) {
CommonSect->Size[0] = (UINT8) (TotalLength & 0xff);
CommonSect->Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
CommonSect->Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
} else {
memset(CommonSect->Size, 0xff, sizeof(UINT8) * 3);
((EFI_COMMON_SECTION_HEADER2 *)CommonSect)->ExtendedSize = TotalLength;
}
//
// read data from the input file.
//
if (InputFileLength != 0) {
if (fread (Buffer + HeaderLength, (size_t) InputFileLength, 1, InFile) != 1) {
Error (NULL, 0, 0004, "Error reading file", InputFileName[0]);
goto Done;
}
}
//
// Set OutFileBuffer
//
*OutFileBuffer = Buffer;
Status = STATUS_SUCCESS;
Done:
fclose (InFile);
return Status;
}
STATIC
EFI_STATUS
StringtoAlignment (
IN CHAR8 *AlignBuffer,
OUT UINT32 *AlignNumber
)
/*++
Routine Description:
Converts Align String to align value (1~16M).
Arguments:
AlignBuffer - Pointer to Align string.
AlignNumber - Pointer to Align value.
Returns:
EFI_SUCCESS Successfully convert align string to align value.
EFI_INVALID_PARAMETER Align string is invalid or align value is not in scope.
--*/
{
UINT32 Index = 0;
//
// Check AlignBuffer
//
if (AlignBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
for (Index = 0; Index < sizeof (mAlignName) / sizeof (CHAR8 *); Index ++) {
if (stricmp (AlignBuffer, mAlignName [Index]) == 0) {
*AlignNumber = 1 << Index;
return EFI_SUCCESS;
}
}
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
GetSectionContents (
CHAR8 **InputFileName,
UINT32 *InputFileAlign,
UINT32 InputFileNum,
UINT8 *FileBuffer,
UINT32 *BufferLength
)
/*++
Routine Description:
Get the contents of all section files specified in InputFileName
into FileBuffer.
Arguments:
InputFileName - Name of the input file.
InputFileAlign - Alignment required by the input file data.
InputFileNum - Number of input files. Should be at least 1.
FileBuffer - Output buffer to contain data
BufferLength - On input, this is size of the FileBuffer.
On output, this is the actual length of the data.
Returns:
EFI_SUCCESS on successful return
EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
EFI_ABORTED if unable to open input file.
EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
--*/
{
UINT32 Size;
UINT32 Offset;
UINT32 FileSize;
UINT32 Index;
FILE *InFile;
EFI_COMMON_SECTION_HEADER *SectHeader;
EFI_COMMON_SECTION_HEADER2 TempSectHeader;
EFI_TE_IMAGE_HEADER TeHeader;
UINT32 TeOffset;
EFI_GUID_DEFINED_SECTION GuidSectHeader;
EFI_GUID_DEFINED_SECTION2 GuidSectHeader2;
UINT32 HeaderSize;
if (InputFileNum < 1) {
Error (NULL, 0, 2000, "Invalid parameter", "must specify at least one input file");
return EFI_INVALID_PARAMETER;
}
if (BufferLength == NULL) {
Error (NULL, 0, 2000, "Invalid parameter", "BufferLength can't be NULL");
return EFI_INVALID_PARAMETER;
}
Size = 0;
Offset = 0;
TeOffset = 0;
//
// Go through our array of file names and copy their contents
// to the output buffer.
//
for (Index = 0; Index < InputFileNum; Index++) {
//
// make sure section ends on a DWORD boundary
//
while ((Size & 0x03) != 0) {
if (FileBuffer != NULL && Size < *BufferLength) {
FileBuffer[Size] = 0;
}
Size++;
}
//
// Open file and read contents
//
InFile = fopen (LongFilePath (InputFileName[Index]), "rb");
if (InFile == NULL) {
Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);
return EFI_ABORTED;
}
fseek (InFile, 0, SEEK_END);
FileSize = ftell (InFile);
fseek (InFile, 0, SEEK_SET);
DebugMsg (NULL, 0, 9, "Input files", "the input file name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);
//
// Adjust section buffer when section alignment is required.
//
if (InputFileAlign != NULL) {
//
// Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
//
TeOffset = 0;
//
// The section might be EFI_COMMON_SECTION_HEADER2
// But only Type needs to be checked
//
if (FileSize >= MAX_SECTION_SIZE) {
HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
} else {
HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
}
fread (&TempSectHeader, 1, HeaderSize, InFile);
if (TempSectHeader.Type == EFI_SECTION_TE) {
fread (&TeHeader, 1, sizeof (TeHeader), InFile);
if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
TeOffset = TeHeader.StrippedSize - sizeof (TeHeader);
}
} else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) {
fseek (InFile, 0, SEEK_SET);
if (FileSize >= MAX_SECTION_SIZE) {
fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile);
if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
HeaderSize = GuidSectHeader2.DataOffset;
}
} else {
fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);
if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
HeaderSize = GuidSectHeader.DataOffset;
}
}
}
fseek (InFile, 0, SEEK_SET);
//
// Revert TeOffset to the converse value relative to Alignment
// This is to assure the original PeImage Header at Alignment.
//
if (TeOffset != 0) {
TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);
TeOffset = TeOffset % InputFileAlign [Index];
}
//
// make sure section data meet its alignment requirement by adding one raw pad section.
//
if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {
Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);
Offset = Offset - Size - HeaderSize - TeOffset;
if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {
//
// The maximal alignment is 64K, the raw section size must be less than 0xffffff
//
memset (FileBuffer + Size, 0, Offset);
SectHeader = (EFI_COMMON_SECTION_HEADER *) (FileBuffer + Size);
SectHeader->Type = EFI_SECTION_RAW;
SectHeader->Size[0] = (UINT8) (Offset & 0xff);
SectHeader->Size[1] = (UINT8) ((Offset & 0xff00) >> 8);
SectHeader->Size[2] = (UINT8) ((Offset & 0xff0000) >> 16);
}
DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", "Pad Raw section size is %u", (unsigned) Offset);
Size = Size + Offset;
}
}
//
// Now read the contents of the file into the buffer
// Buffer must be enough to contain the file content.
//
if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) {
if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {
Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);
fclose (InFile);
return EFI_ABORTED;
}
}
fclose (InFile);
Size += FileSize;
}
//
// Set the real required buffer size.
//
if (Size > *BufferLength) {
*BufferLength = Size;
return EFI_BUFFER_TOO_SMALL;
} else {
*BufferLength = Size;
return EFI_SUCCESS;
}
}
EFI_STATUS
GenSectionCompressionSection (
CHAR8 **InputFileName,
UINT32 *InputFileAlign,
UINT32 InputFileNum,
UINT8 SectCompSubType,
UINT8 **OutFileBuffer
)
/*++
Routine Description:
Generate an encapsulating section of type EFI_SECTION_COMPRESSION
Input file must be already sectioned. The function won't validate
the input files' contents. Caller should hand in files already
with section header.
Arguments:
InputFileName - Name of the input file.
InputFileAlign - Alignment required by the input file data.
InputFileNum - Number of input files. Should be at least 1.
SectCompSubType - Specify the compression algorithm requested.
OutFileBuffer - Buffer pointer to Output file contents
Returns:
EFI_SUCCESS on successful return
EFI_INVALID_PARAMETER if InputFileNum is less than 1
EFI_ABORTED if unable to open input file.
EFI_OUT_OF_RESOURCES No resource to complete the operation.
--*/
{
UINT32 TotalLength;
UINT32 InputLength;
UINT32 CompressedLength;
UINT32 HeaderLength;
UINT8 *FileBuffer;
UINT8 *OutputBuffer;
EFI_STATUS Status;
EFI_COMPRESSION_SECTION *CompressionSect;
EFI_COMPRESSION_SECTION2 *CompressionSect2;
COMPRESS_FUNCTION CompressFunction;
InputLength = 0;
FileBuffer = NULL;
OutputBuffer = NULL;
CompressedLength = 0;
TotalLength = 0;
//
// read all input file contents into a buffer
// first get the size of all file contents
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
FileBuffer,
&InputLength
);
if (Status == EFI_BUFFER_TOO_SMALL) {
FileBuffer = (UINT8 *) malloc (InputLength);
if (FileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
return EFI_OUT_OF_RESOURCES;
}
//
// read all input file contents into a buffer
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
FileBuffer,
&InputLength
);
}
if (EFI_ERROR (Status)) {
if (FileBuffer != NULL) {
free (FileBuffer);
}
return Status;
}
if (FileBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CompressFunction = NULL;
//
// Now data is in FileBuffer, compress the data
//
switch (SectCompSubType) {
case EFI_NOT_COMPRESSED:
CompressedLength = InputLength;
HeaderLength = sizeof (EFI_COMPRESSION_SECTION);
if (CompressedLength + HeaderLength >= MAX_SECTION_SIZE) {
HeaderLength = sizeof (EFI_COMPRESSION_SECTION2);
}
TotalLength = CompressedLength + HeaderLength;
//
// Copy file buffer to the none compressed data.
//
OutputBuffer = malloc (TotalLength);
if (OutputBuffer == NULL) {
free (FileBuffer);
return EFI_OUT_OF_RESOURCES;
}
memcpy (OutputBuffer + HeaderLength, FileBuffer, CompressedLength);
free (FileBuffer);
FileBuffer = OutputBuffer;
break;
case EFI_STANDARD_COMPRESSION:
CompressFunction = (COMPRESS_FUNCTION) EfiCompress;
break;
default:
Error (NULL, 0, 2000, "Invalid parameter", "unknown compression type");
free (FileBuffer);
return EFI_ABORTED;
}
if (CompressFunction != NULL) {
Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength);
if (Status == EFI_BUFFER_TOO_SMALL) {
HeaderLength = sizeof (EFI_COMPRESSION_SECTION);
if (CompressedLength + HeaderLength >= MAX_SECTION_SIZE) {
HeaderLength = sizeof (EFI_COMPRESSION_SECTION2);
}
TotalLength = CompressedLength + HeaderLength;
OutputBuffer = malloc (TotalLength);
if (!OutputBuffer) {
free (FileBuffer);
return EFI_OUT_OF_RESOURCES;
}
Status = CompressFunction (FileBuffer, InputLength, OutputBuffer + HeaderLength, &CompressedLength);
}
free (FileBuffer);
FileBuffer = OutputBuffer;
if (EFI_ERROR (Status)) {
if (FileBuffer != NULL) {
free (FileBuffer);
}
return Status;
}
if (FileBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
}
DebugMsg (NULL, 0, 9, "comprss file size",
"the original section size is %d bytes and the compressed section size is %u bytes", (unsigned) InputLength, (unsigned) CompressedLength);
//if (TotalLength >= MAX_SECTION_SIZE) {
// Error (NULL, 0, 2000, "Invalid parameter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
// if (FileBuffer != NULL) {
// free (FileBuffer);
// }
// if (OutputBuffer != NULL) {
// free (OutputBuffer);
// }
// return STATUS_ERROR;
//}
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
//
// Add the section header for the compressed data
//
if (TotalLength >= MAX_SECTION_SIZE) {
CompressionSect2 = (EFI_COMPRESSION_SECTION2 *)FileBuffer;
memset(CompressionSect2->CommonHeader.Size, 0xff, sizeof(UINT8) * 3);
CompressionSect2->CommonHeader.Type = EFI_SECTION_COMPRESSION;
CompressionSect2->CommonHeader.ExtendedSize = TotalLength;
CompressionSect2->CompressionType = SectCompSubType;
CompressionSect2->UncompressedLength = InputLength;
} else {
CompressionSect = (EFI_COMPRESSION_SECTION *) FileBuffer;
CompressionSect->CommonHeader.Type = EFI_SECTION_COMPRESSION;
CompressionSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
CompressionSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
CompressionSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
CompressionSect->CompressionType = SectCompSubType;
CompressionSect->UncompressedLength = InputLength;
}
//
// Set OutFileBuffer
//
*OutFileBuffer = FileBuffer;
return EFI_SUCCESS;
}
EFI_STATUS
GenSectionGuidDefinedSection (
CHAR8 **InputFileName,
UINT32 *InputFileAlign,
UINT32 InputFileNum,
EFI_GUID *VendorGuid,
UINT16 DataAttribute,
UINT32 DataHeaderSize,
UINT8 **OutFileBuffer
)
/*++
Routine Description:
Generate an encapsulating section of type EFI_SECTION_GUID_DEFINED
Input file must be already sectioned. The function won't validate
the input files' contents. Caller should hand in files already
with section header.
Arguments:
InputFileName - Name of the input file.
InputFileAlign - Alignment required by the input file data.
InputFileNum - Number of input files. Should be at least 1.
VendorGuid - Specify vendor guid value.
DataAttribute - Specify attribute for the vendor guid data.
DataHeaderSize- Guided Data Header Size
OutFileBuffer - Buffer pointer to Output file contents
Returns:
EFI_SUCCESS on successful return
EFI_INVALID_PARAMETER if InputFileNum is less than 1
EFI_ABORTED if unable to open input file.
EFI_OUT_OF_RESOURCES No resource to complete the operation.
--*/
{
UINT32 TotalLength;
UINT32 InputLength;
UINT32 Offset;
UINT8 *FileBuffer;
UINT32 Crc32Checksum;
EFI_STATUS Status;
CRC32_SECTION_HEADER *Crc32GuidSect;
CRC32_SECTION_HEADER2 *Crc32GuidSect2;
EFI_GUID_DEFINED_SECTION *VendorGuidSect;
EFI_GUID_DEFINED_SECTION2 *VendorGuidSect2;
InputLength = 0;
Offset = 0;
FileBuffer = NULL;
TotalLength = 0;
//
// read all input file contents into a buffer
// first get the size of all file contents
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
FileBuffer,
&InputLength
);
if (Status == EFI_BUFFER_TOO_SMALL) {
if (CompareGuid (VendorGuid, &mZeroGuid) == 0) {
Offset = sizeof (CRC32_SECTION_HEADER);
if (InputLength + Offset >= MAX_SECTION_SIZE) {
Offset = sizeof (CRC32_SECTION_HEADER2);
}
} else {
Offset = sizeof (EFI_GUID_DEFINED_SECTION);
if (InputLength + Offset >= MAX_SECTION_SIZE) {
Offset = sizeof (EFI_GUID_DEFINED_SECTION2);
}
}
TotalLength = InputLength + Offset;
FileBuffer = (UINT8 *) malloc (InputLength + Offset);
if (FileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
return EFI_OUT_OF_RESOURCES;
}
//
// read all input file contents into a buffer
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
FileBuffer + Offset,
&InputLength
);
}
if (EFI_ERROR (Status)) {
if (FileBuffer != NULL) {
free (FileBuffer);
}
Error (NULL, 0, 0001, "Error opening file for reading", InputFileName[0]);
return Status;
}
if (InputLength == 0) {
if (FileBuffer != NULL) {
free (FileBuffer);
}
Error (NULL, 0, 2000, "Invalid parameter", "the size of input file %s can't be zero", *InputFileName);
return EFI_NOT_FOUND;
}
//
// InputLength != 0, but FileBuffer == NULL means out of resources.
//
if (FileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
return EFI_OUT_OF_RESOURCES;
}
//
// Now data is in FileBuffer + Offset
//
if (CompareGuid (VendorGuid, &mZeroGuid) == 0) {
//
// Default Guid section is CRC32.
//
Crc32Checksum = 0;
CalculateCrc32 (FileBuffer + Offset, InputLength, &Crc32Checksum);
if (TotalLength >= MAX_SECTION_SIZE) {
Crc32GuidSect2 = (CRC32_SECTION_HEADER2 *) FileBuffer;
Crc32GuidSect2->GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
Crc32GuidSect2->GuidSectionHeader.CommonHeader.Size[0] = (UINT8) 0xff;
Crc32GuidSect2->GuidSectionHeader.CommonHeader.Size[1] = (UINT8) 0xff;
Crc32GuidSect2->GuidSectionHeader.CommonHeader.Size[2] = (UINT8) 0xff;
Crc32GuidSect2->GuidSectionHeader.CommonHeader.ExtendedSize = TotalLength;
memcpy (&(Crc32GuidSect2->GuidSectionHeader.SectionDefinitionGuid), &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
Crc32GuidSect2->GuidSectionHeader.Attributes = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
Crc32GuidSect2->GuidSectionHeader.DataOffset = sizeof (CRC32_SECTION_HEADER2);
Crc32GuidSect2->CRC32Checksum = Crc32Checksum;
DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", Crc32GuidSect2->GuidSectionHeader.DataOffset);
} else {
Crc32GuidSect = (CRC32_SECTION_HEADER *) FileBuffer;
Crc32GuidSect->GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
memcpy (&(Crc32GuidSect->GuidSectionHeader.SectionDefinitionGuid), &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
Crc32GuidSect->GuidSectionHeader.Attributes = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
Crc32GuidSect->GuidSectionHeader.DataOffset = sizeof (CRC32_SECTION_HEADER);
Crc32GuidSect->CRC32Checksum = Crc32Checksum;
DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", Crc32GuidSect->GuidSectionHeader.DataOffset);
}
} else {
if (TotalLength >= MAX_SECTION_SIZE) {
VendorGuidSect2 = (EFI_GUID_DEFINED_SECTION2 *) FileBuffer;
VendorGuidSect2->CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
VendorGuidSect2->CommonHeader.Size[0] = (UINT8) 0xff;
VendorGuidSect2->CommonHeader.Size[1] = (UINT8) 0xff;
VendorGuidSect2->CommonHeader.Size[2] = (UINT8) 0xff;
VendorGuidSect2->CommonHeader.ExtendedSize = InputLength + sizeof (EFI_GUID_DEFINED_SECTION2);
memcpy (&(VendorGuidSect2->SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));
VendorGuidSect2->Attributes = DataAttribute;
VendorGuidSect2->DataOffset = (UINT16) (sizeof (EFI_GUID_DEFINED_SECTION2) + DataHeaderSize);
DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", VendorGuidSect2->DataOffset);
} else {
VendorGuidSect = (EFI_GUID_DEFINED_SECTION *) FileBuffer;
VendorGuidSect->CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
VendorGuidSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
VendorGuidSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
VendorGuidSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
memcpy (&(VendorGuidSect->SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));
VendorGuidSect->Attributes = DataAttribute;
VendorGuidSect->DataOffset = (UINT16) (sizeof (EFI_GUID_DEFINED_SECTION) + DataHeaderSize);
DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", VendorGuidSect->DataOffset);
}
}
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
//
// Set OutFileBuffer
//
*OutFileBuffer = FileBuffer;
return EFI_SUCCESS;
}
EFI_STATUS
GenSectionSubtypeGuidSection (
CHAR8 **InputFileName,
UINT32 *InputFileAlign,
UINT32 InputFileNum,
EFI_GUID *SubTypeGuid,
UINT8 **OutFileBuffer
)
/*++
Routine Description:
Generate a section of type EFI_SECTION_FREEFORM_SUBTYPE_GUID
The function won't validate the input file contents.
The utility will add section header to the file.
Arguments:
InputFileName - Name of the input file.
InputFileAlign - Alignment required by the input file data.
InputFileNum - Number of input files. Should be 1 for this section.
SubTypeGuid - Specify vendor guid value.
OutFileBuffer - Buffer pointer to Output file contents
Returns:
EFI_SUCCESS on successful return
EFI_INVALID_PARAMETER if InputFileNum is less than 1
EFI_ABORTED if unable to open input file.
EFI_OUT_OF_RESOURCES No resource to complete the operation.
--*/
{
UINT32 TotalLength;
UINT32 InputLength;
UINT32 Offset;
UINT8 *FileBuffer;
EFI_STATUS Status;
EFI_FREEFORM_SUBTYPE_GUID_SECTION *SubtypeGuidSect;
EFI_FREEFORM_SUBTYPE_GUID_SECTION2 *SubtypeGuidSect2;
InputLength = 0;
Offset = 0;
FileBuffer = NULL;
TotalLength = 0;
if (InputFileNum > 1) {
Error (NULL, 0, 2000, "Invalid parameter", "more than one input file specified");
return STATUS_ERROR;
} else if (InputFileNum < 1) {
Error (NULL, 0, 2000, "Invalid parameter", "no input file specified");
return STATUS_ERROR;
}
//
// read all input file contents into a buffer
// first get the size of all file contents
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
FileBuffer,
&InputLength
);
if (Status == EFI_BUFFER_TOO_SMALL) {
Offset = sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION);
if (InputLength + Offset >= MAX_SECTION_SIZE) {
Offset = sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION2);
}
TotalLength = InputLength + Offset;
FileBuffer = (UINT8 *) malloc (InputLength + Offset);
if (FileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
return EFI_OUT_OF_RESOURCES;
}
//
// read all input file contents into a buffer
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
FileBuffer + Offset,
&InputLength
);
}
if (EFI_ERROR (Status)) {
if (FileBuffer != NULL) {
free (FileBuffer);
}
Error (NULL, 0, 0001, "Error opening file for reading", InputFileName[0]);
return Status;
}
if (InputLength == 0) {
if (FileBuffer != NULL) {
free (FileBuffer);
}
Error (NULL, 0, 2000, "Invalid parameter", "the size of input file %s can't be zero", *InputFileName);
return EFI_NOT_FOUND;
}
//
// InputLength != 0, but FileBuffer == NULL means out of resources.
//
if (FileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
return EFI_OUT_OF_RESOURCES;
}
//
// Now data is in FileBuffer + Offset
//
if (TotalLength >= MAX_SECTION_SIZE) {
SubtypeGuidSect2 = (EFI_FREEFORM_SUBTYPE_GUID_SECTION2 *) FileBuffer;
SubtypeGuidSect2->CommonHeader.Type = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
SubtypeGuidSect2->CommonHeader.Size[0] = (UINT8) 0xff;
SubtypeGuidSect2->CommonHeader.Size[1] = (UINT8) 0xff;
SubtypeGuidSect2->CommonHeader.Size[2] = (UINT8) 0xff;
SubtypeGuidSect2->CommonHeader.ExtendedSize = InputLength + sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION2);
memcpy (&(SubtypeGuidSect2->SubTypeGuid), SubTypeGuid, sizeof (EFI_GUID));
} else {
SubtypeGuidSect = (EFI_FREEFORM_SUBTYPE_GUID_SECTION *) FileBuffer;
SubtypeGuidSect->CommonHeader.Type = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
SubtypeGuidSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
SubtypeGuidSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
SubtypeGuidSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
memcpy (&(SubtypeGuidSect->SubTypeGuid), SubTypeGuid, sizeof (EFI_GUID));
}
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
//
// Set OutFileBuffer
//
*OutFileBuffer = FileBuffer;
return EFI_SUCCESS;
}
EFI_STATUS
FfsRebaseImageRead (
IN VOID *FileHandle,
IN UINTN FileOffset,
IN OUT UINT32 *ReadSize,
OUT VOID *Buffer
)
/*++
Routine Description:
Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
Arguments:
FileHandle - The handle to the PE/COFF file
FileOffset - The offset, in bytes, into the file to read
ReadSize - The number of bytes to read from the file starting at FileOffset
Buffer - A pointer to the buffer to read the data into.
Returns:
EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
--*/
{
CHAR8 *Destination8;
CHAR8 *Source8;
UINT32 Length;
Destination8 = Buffer;
Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
Length = *ReadSize;
while (Length--) {
*(Destination8++) = *(Source8++);
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
GetAlignmentFromFile(char *InFile, UINT32 *Alignment)
/*
InFile is input file for getting alignment
return the alignment
*/
{
FILE *InFileHandle;
UINT8 *PeFileBuffer;
UINTN PeFileSize;
UINT32 CurSecHdrSize;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
EFI_COMMON_SECTION_HEADER *CommonHeader;
EFI_STATUS Status;
InFileHandle = NULL;
PeFileBuffer = NULL;
*Alignment = 0;
memset (&ImageContext, 0, sizeof (ImageContext));
InFileHandle = fopen(LongFilePath(InFile), "rb");
if (InFileHandle == NULL){
Error (NULL, 0, 0001, "Error opening file", InFile);
return EFI_ABORTED;
}
PeFileSize = _filelength (fileno(InFileHandle));
PeFileBuffer = (UINT8 *) malloc (PeFileSize);
if (PeFileBuffer == NULL) {
fclose (InFileHandle);
Error(NULL, 0, 4001, "Resource", "memory cannot be allocated for %s", InFile);
return EFI_OUT_OF_RESOURCES;
}
fread (PeFileBuffer, sizeof (UINT8), PeFileSize, InFileHandle);
fclose (InFileHandle);
CommonHeader = (EFI_COMMON_SECTION_HEADER *) PeFileBuffer;
CurSecHdrSize = GetSectionHeaderLength(CommonHeader);
ImageContext.Handle = (VOID *) ((UINTN)PeFileBuffer + CurSecHdrSize);
ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
Status = PeCoffLoaderGetImageInfo(&ImageContext);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and return status is %x", InFile, (int) Status);
return Status;
}
*Alignment = ImageContext.SectionAlignment;
// Free the allocated memory resource
if (PeFileBuffer != NULL) {
free (PeFileBuffer);
PeFileBuffer = NULL;
}
return EFI_SUCCESS;
}
int
main (
int argc,
char *argv[]
)
/*++
Routine Description:
Main
Arguments:
command line parameters
Returns:
EFI_SUCCESS Section header successfully generated and section concatenated.
EFI_ABORTED Could not generate the section
EFI_OUT_OF_RESOURCES No resource to complete the operation.
--*/
{
UINT32 Index;
UINT32 InputFileNum;
FILE *OutFile;
CHAR8 **InputFileName;
CHAR8 *OutputFileName;
CHAR8 *SectionName;
CHAR8 *CompressionName;
CHAR8 *StringBuffer;
EFI_GUID VendorGuid = mZeroGuid;
int VersionNumber;
UINT8 SectType;
UINT8 SectCompSubType;
UINT16 SectGuidAttribute;
UINT64 SectGuidHeaderLength;
EFI_VERSION_SECTION *VersionSect;
EFI_USER_INTERFACE_SECTION *UiSect;
UINT32 InputLength;
UINT8 *OutFileBuffer;
EFI_STATUS Status;
UINT64 LogLevel;
UINT32 *InputFileAlign;
UINT32 InputFileAlignNum;
EFI_COMMON_SECTION_HEADER *SectionHeader;
CHAR8 *DummyFileName;
FILE *DummyFile;
UINTN DummyFileSize;
UINT8 *DummyFileBuffer;
FILE *InFile;
UINT8 *InFileBuffer;
UINTN InFileSize;
InputFileAlign = NULL;
InputFileAlignNum = 0;
InputFileName = NULL;
OutputFileName = NULL;
SectionName = NULL;
CompressionName = NULL;
StringBuffer = "";
OutFile = NULL;
VersionNumber = 0;
InputFileNum = 0;
SectType = EFI_SECTION_ALL;
SectCompSubType = 0;
SectGuidAttribute = EFI_GUIDED_SECTION_NONE;
OutFileBuffer = NULL;
InputLength = 0;
Status = STATUS_SUCCESS;
LogLevel = 0;
SectGuidHeaderLength = 0;
VersionSect = NULL;
UiSect = NULL;
DummyFileSize = 0;
DummyFileName = NULL;
DummyFile = NULL;
DummyFileBuffer = NULL;
InFile = NULL;
InFileSize = 0;
InFileBuffer = NULL;
SetUtilityName (UTILITY_NAME);
if (argc == 1) {
Error (NULL, 0, 1001, "Missing options", "No options input");
Usage ();
return STATUS_ERROR;
}
//
// Parse command line
//
argc --;
argv ++;
if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
Version ();
Usage ();
return STATUS_SUCCESS;
}
if (stricmp (argv[0], "--version") == 0) {
Version ();
return STATUS_SUCCESS;
}
while (argc > 0) {
if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--SectionType") == 0)) {
SectionName = argv[1];
if (SectionName == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "Section Type can't be NULL");
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
OutputFileName = argv[1];
if (OutputFileName == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "Output file can't be NULL");
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--compress") == 0)) {
CompressionName = argv[1];
if (CompressionName == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "Compression Type can't be NULL");
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--vendor") == 0)) {
Status = StringToGuid (argv[1], &VendorGuid);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if (stricmp (argv[0], "--dummy") == 0) {
DummyFileName = argv[1];
if (DummyFileName == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "Dummy file can't be NULL");
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--attributes") == 0)) {
if (argv[1] == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "Guid section attributes can't be NULL");
goto Finish;
}
if (stricmp (argv[1], mGUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]) == 0) {
SectGuidAttribute |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
} else if (stricmp (argv[1], mGUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]) == 0) {
SectGuidAttribute |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
} else if (stricmp (argv[1], mGUIDedSectionAttribue[0]) == 0) {
//
// NONE attribute
//
SectGuidAttribute |= EFI_GUIDED_SECTION_NONE;
} else {
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--HeaderLength") == 0)) {
Status = AsciiStringToUint64 (argv[1], FALSE, &SectGuidHeaderLength);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 1003, "Invalid option value for GuidHeaderLength", "%s = %s", argv[0], argv[1]);
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--name") == 0)) {
StringBuffer = argv[1];
if (StringBuffer == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "Name can't be NULL");
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--buildnumber") == 0)) {
if (argv[1] == NULL) {
Error (NULL, 0, 1003, "Invalid option value", "build number can't be NULL");
goto Finish;
}
//
// Verify string is a integrator number
//
for (Index = 0; Index < strlen (argv[1]); Index++) {
if ((argv[1][Index] != '-') && (isdigit ((int)argv[1][Index]) == 0)) {
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
goto Finish;
}
}
sscanf (argv[1], "%d", &VersionNumber);
argc -= 2;
argv += 2;
continue;
}
if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
SetPrintLevel (VERBOSE_LOG_LEVEL);
VerboseMsg ("Verbose output Mode Set!");
argc --;
argv ++;
continue;
}
if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
SetPrintLevel (KEY_LOG_LEVEL);
KeyMsg ("Quiet output Mode Set!");
argc --;
argv ++;
continue;
}
if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
goto Finish;
}
if (LogLevel > 9) {
Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0~9, current input level is %d", (int) LogLevel);
goto Finish;
}
SetPrintLevel (LogLevel);
DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
argc -= 2;
argv += 2;
continue;
}
//
// Section File alignment requirement
//
if (stricmp (argv[0], "--sectionalign") == 0) {
if (InputFileAlignNum == 0) {
InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
if (InputFileAlign == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
goto Finish;
}
memset (InputFileAlign, 1, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
} else if (InputFileAlignNum % MAXIMUM_INPUT_FILE_NUM == 0) {
InputFileAlign = (UINT32 *) realloc (
InputFileAlign,
(InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)
);
if (InputFileAlign == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
goto Finish;
}
memset (&(InputFileAlign[InputFileNum]), 1, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));
}
if (stricmp(argv[1], "0") == 0) {
InputFileAlign[InputFileAlignNum] = 0;
} else {
Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileAlignNum]));
if (EFI_ERROR (Status)) {
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
goto Finish;
}
}
argc -= 2;
argv += 2;
InputFileAlignNum ++;
continue;
}
//
// Get Input file name
//
if ((InputFileNum == 0) && (InputFileName == NULL)) {
InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
if (InputFileName == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
} else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
//
// InputFileName buffer too small, need to realloc
//
InputFileName = (CHAR8 **) realloc (
InputFileName,
(InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
);
if (InputFileName == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
}
InputFileName[InputFileNum++] = argv[0];
argc --;
argv ++;
}
if (InputFileAlignNum > 0 && InputFileAlignNum != InputFileNum) {
Error (NULL, 0, 1003, "Invalid option", "section alignment must be set for each section");
goto Finish;
}
for (Index = 0; Index < InputFileAlignNum; Index++)
{
if (InputFileAlign[Index] == 0) {
Status = GetAlignmentFromFile(InputFileName[Index], &(InputFileAlign[Index]));
if (EFI_ERROR(Status)) {
Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);
goto Finish;
}
}
}
VerboseMsg ("%s tool start.", UTILITY_NAME);
if (DummyFileName != NULL) {
//
// Open file and read contents
//
DummyFile = fopen (LongFilePath (DummyFileName), "rb");
if (DummyFile == NULL) {
Error (NULL, 0, 0001, "Error opening file", DummyFileName);
goto Finish;
}
fseek (DummyFile, 0, SEEK_END);
DummyFileSize = ftell (DummyFile);
fseek (DummyFile, 0, SEEK_SET);
DummyFileBuffer = (UINT8 *) malloc (DummyFileSize);
if (DummyFileBuffer == NULL) {
fclose(DummyFile);
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
fread(DummyFileBuffer, 1, DummyFileSize, DummyFile);
fclose(DummyFile);
DebugMsg (NULL, 0, 9, "Dummy files", "the dummy file name is %s and the size is %u bytes", DummyFileName, (unsigned) DummyFileSize);
if (InputFileName == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
InFile = fopen(LongFilePath(InputFileName[0]), "rb");
if (InFile == NULL) {
Error (NULL, 0, 0001, "Error opening file", InputFileName[0]);
goto Finish;
}
fseek (InFile, 0, SEEK_END);
InFileSize = ftell (InFile);
fseek (InFile, 0, SEEK_SET);
InFileBuffer = (UINT8 *) malloc (InFileSize);
if (InFileBuffer == NULL) {
fclose(InFile);
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
fread(InFileBuffer, 1, InFileSize, InFile);
fclose(InFile);
DebugMsg (NULL, 0, 9, "Input files", "the input file name is %s and the size is %u bytes", InputFileName[0], (unsigned) InFileSize);
if (InFileSize > DummyFileSize){
if (stricmp((CHAR8 *)DummyFileBuffer, (CHAR8 *)(InFileBuffer + (InFileSize - DummyFileSize))) == 0){
SectGuidHeaderLength = InFileSize - DummyFileSize;
}
}
if (SectGuidHeaderLength == 0) {
SectGuidAttribute |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
}
if (DummyFileBuffer != NULL) {
free (DummyFileBuffer);
DummyFileBuffer = NULL;
}
if (InFileBuffer != NULL) {
free (InFileBuffer);
}
}
//
// Parse all command line parameters to get the corresponding section type.
//
VerboseMsg ("Section type is %s", SectionName);
if (SectionName == NULL) {
//
// No specified Section type, default is SECTION_ALL.
//
SectType = EFI_SECTION_ALL;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_COMPRESSION]) == 0) {
SectType = EFI_SECTION_COMPRESSION;
if (CompressionName == NULL) {
//
// Default is PI_STD compression algorithm.
//
SectCompSubType = EFI_STANDARD_COMPRESSION;
} else if (stricmp (CompressionName, mCompressionTypeName[EFI_NOT_COMPRESSED]) == 0) {
SectCompSubType = EFI_NOT_COMPRESSED;
} else if (stricmp (CompressionName, mCompressionTypeName[EFI_STANDARD_COMPRESSION]) == 0) {
SectCompSubType = EFI_STANDARD_COMPRESSION;
} else {
Error (NULL, 0, 1003, "Invalid option value", "--compress = %s", CompressionName);
goto Finish;
}
VerboseMsg ("Compress method is %s", mCompressionTypeName [SectCompSubType]);
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_GUID_DEFINED]) == 0) {
SectType = EFI_SECTION_GUID_DEFINED;
if ((SectGuidAttribute & EFI_GUIDED_SECTION_NONE) != 0) {
//
// NONE attribute, clear attribute value.
//
SectGuidAttribute = SectGuidAttribute & ~EFI_GUIDED_SECTION_NONE;
}
VerboseMsg ("Vendor Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
(unsigned) VendorGuid.Data1,
VendorGuid.Data2,
VendorGuid.Data3,
VendorGuid.Data4[0],
VendorGuid.Data4[1],
VendorGuid.Data4[2],
VendorGuid.Data4[3],
VendorGuid.Data4[4],
VendorGuid.Data4[5],
VendorGuid.Data4[6],
VendorGuid.Data4[7]);
if ((SectGuidAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
VerboseMsg ("Guid Attribute is %s", mGUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]);
}
if ((SectGuidAttribute & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
VerboseMsg ("Guid Attribute is %s", mGUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]);
}
if (SectGuidHeaderLength != 0) {
VerboseMsg ("Guid Data Header size is 0x%llx", (unsigned long long) SectGuidHeaderLength);
}
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PE32]) == 0) {
SectType = EFI_SECTION_PE32;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PIC]) == 0) {
SectType = EFI_SECTION_PIC;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_TE]) == 0) {
SectType = EFI_SECTION_TE;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_DXE_DEPEX]) == 0) {
SectType = EFI_SECTION_DXE_DEPEX;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_SMM_DEPEX]) == 0) {
SectType = EFI_SECTION_SMM_DEPEX;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_VERSION]) == 0) {
SectType = EFI_SECTION_VERSION;
if (VersionNumber < 0 || VersionNumber > 65535) {
Error (NULL, 0, 1003, "Invalid option value", "%d is not in 0~65535", VersionNumber);
goto Finish;
}
VerboseMsg ("Version section number is %d", VersionNumber);
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_USER_INTERFACE]) == 0) {
SectType = EFI_SECTION_USER_INTERFACE;
if (StringBuffer[0] == '\0') {
Error (NULL, 0, 1001, "Missing option", "user interface string");
goto Finish;
}
VerboseMsg ("UI section string name is %s", StringBuffer);
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_COMPATIBILITY16]) == 0) {
SectType = EFI_SECTION_COMPATIBILITY16;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_FIRMWARE_VOLUME_IMAGE]) == 0) {
SectType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_FREEFORM_SUBTYPE_GUID]) == 0) {
SectType = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_RAW]) == 0) {
SectType = EFI_SECTION_RAW;
} else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PEI_DEPEX]) == 0) {
SectType = EFI_SECTION_PEI_DEPEX;
} else {
Error (NULL, 0, 1003, "Invalid option value", "SectionType = %s", SectionName);
goto Finish;
}
//
// GuidValue is only required by Guided section and SubtypeGuid section.
//
if ((SectType != EFI_SECTION_GUID_DEFINED) && (SectType != EFI_SECTION_FREEFORM_SUBTYPE_GUID) &&
(SectionName != NULL) &&
(CompareGuid (&VendorGuid, &mZeroGuid) != 0)) {
fprintf (stdout, "Warning: the input guid value is not required for this section type %s\n", SectionName);
}
//
// Check whether there is GUID for the SubtypeGuid section
//
if ((SectType == EFI_SECTION_FREEFORM_SUBTYPE_GUID) && (CompareGuid (&VendorGuid, &mZeroGuid) == 0)) {
Error (NULL, 0, 1001, "Missing options", "GUID");
goto Finish;
}
//
// Check whether there is input file
//
if ((SectType != EFI_SECTION_VERSION) && (SectType != EFI_SECTION_USER_INTERFACE)) {
//
// The input file are required for other section type.
//
if (InputFileNum == 0) {
Error (NULL, 0, 1001, "Missing options", "Input files");
goto Finish;
}
}
//
// Check whether there is output file
//
for (Index = 0; Index < InputFileNum; Index ++) {
VerboseMsg ("the %uth input file name is %s", (unsigned) Index, InputFileName[Index]);
}
if (OutputFileName == NULL) {
Error (NULL, 0, 1001, "Missing options", "Output file");
goto Finish;
// OutFile = stdout;
}
VerboseMsg ("Output file name is %s", OutputFileName);
//
// At this point, we've fully validated the command line, and opened appropriate
// files, so let's go and do what we've been asked to do...
//
//
// Within this switch, build and write out the section header including any
// section type specific pieces. If there's an input file, it's tacked on later
//
switch (SectType) {
case EFI_SECTION_COMPRESSION:
if (InputFileAlign != NULL) {
free (InputFileAlign);
InputFileAlign = NULL;
}
Status = GenSectionCompressionSection (
InputFileName,
InputFileAlign,
InputFileNum,
SectCompSubType,
&OutFileBuffer
);
break;
case EFI_SECTION_GUID_DEFINED:
if (InputFileAlign != NULL && (CompareGuid (&VendorGuid, &mZeroGuid) != 0)) {
//
// Only process alignment for the default known CRC32 guided section.
// For the unknown guided section, the alignment is processed when the dummy all section (EFI_SECTION_ALL) is generated.
//
free (InputFileAlign);
InputFileAlign = NULL;
}
Status = GenSectionGuidDefinedSection (
InputFileName,
InputFileAlign,
InputFileNum,
&VendorGuid,
SectGuidAttribute,
(UINT32) SectGuidHeaderLength,
&OutFileBuffer
);
break;
case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
Status = GenSectionSubtypeGuidSection (
InputFileName,
InputFileAlign,
InputFileNum,
&VendorGuid,
&OutFileBuffer
);
break;
case EFI_SECTION_VERSION:
Index = sizeof (EFI_COMMON_SECTION_HEADER);
//
// 2 bytes for the build number UINT16
//
Index += 2;
//
// StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
//
Index += (strlen (StringBuffer) * 2) + 2;
OutFileBuffer = (UINT8 *) malloc (Index);
if (OutFileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
VersionSect = (EFI_VERSION_SECTION *) OutFileBuffer;
VersionSect->CommonHeader.Type = SectType;
VersionSect->CommonHeader.Size[0] = (UINT8) (Index & 0xff);
VersionSect->CommonHeader.Size[1] = (UINT8) ((Index & 0xff00) >> 8);
VersionSect->CommonHeader.Size[2] = (UINT8) ((Index & 0xff0000) >> 16);
VersionSect->BuildNumber = (UINT16) VersionNumber;
Ascii2UnicodeString (StringBuffer, VersionSect->VersionString);
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) Index);
break;
case EFI_SECTION_USER_INTERFACE:
Index = sizeof (EFI_COMMON_SECTION_HEADER);
//
// StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
//
Index += (strlen (StringBuffer) * 2) + 2;
OutFileBuffer = (UINT8 *) malloc (Index);
if (OutFileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
UiSect = (EFI_USER_INTERFACE_SECTION *) OutFileBuffer;
UiSect->CommonHeader.Type = SectType;
UiSect->CommonHeader.Size[0] = (UINT8) (Index & 0xff);
UiSect->CommonHeader.Size[1] = (UINT8) ((Index & 0xff00) >> 8);
UiSect->CommonHeader.Size[2] = (UINT8) ((Index & 0xff0000) >> 16);
Ascii2UnicodeString (StringBuffer, UiSect->FileNameString);
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) Index);
break;
case EFI_SECTION_ALL:
//
// read all input file contents into a buffer
// first get the size of all file contents
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
OutFileBuffer,
&InputLength
);
if (Status == EFI_BUFFER_TOO_SMALL) {
OutFileBuffer = (UINT8 *) malloc (InputLength);
if (OutFileBuffer == NULL) {
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
goto Finish;
}
//
// read all input file contents into a buffer
//
Status = GetSectionContents (
InputFileName,
InputFileAlign,
InputFileNum,
OutFileBuffer,
&InputLength
);
}
VerboseMsg ("the size of the created section file is %u bytes", (unsigned) InputLength);
break;
default:
//
// All other section types are caught by default (they're all the same)
//
Status = GenSectionCommonLeafSection (
InputFileName,
InputFileNum,
SectType,
&OutFileBuffer
);
break;
}
if (Status != EFI_SUCCESS || OutFileBuffer == NULL) {
Error (NULL, 0, 2000, "Status is not successful", "Status value is 0x%X", (int) Status);
goto Finish;
}
//
// Get output file length
//
if (SectType != EFI_SECTION_ALL) {
SectionHeader = (EFI_COMMON_SECTION_HEADER *)OutFileBuffer;
InputLength = *(UINT32 *)SectionHeader->Size & 0x00ffffff;
if (InputLength == 0xffffff) {
InputLength = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
}
}
//
// Write the output file
//
OutFile = fopen (LongFilePath (OutputFileName), "wb");
if (OutFile == NULL) {
Error (NULL, 0, 0001, "Error opening file for writing", OutputFileName);
goto Finish;
}
fwrite (OutFileBuffer, InputLength, 1, OutFile);
Finish:
if (InputFileName != NULL) {
free (InputFileName);
}
if (InputFileAlign != NULL) {
free (InputFileAlign);
}
if (OutFileBuffer != NULL) {
free (OutFileBuffer);
}
if (OutFile != NULL) {
fclose (OutFile);
}
if (DummyFileBuffer != NULL) {
free (DummyFileBuffer);
}
VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
return GetUtilityStatus ();
}