/** @file | |
Creates output file that is a properly formed section per the PI spec. | |
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
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 <ctype.h> | |
#include <Common/UefiBaseTypes.h> | |
#include <Common/PiFirmwareFile.h> | |
#include <Protocol/GuidedSectionExtraction.h> | |
#include <IndustryStandard/PeImage.h> | |
#include "CommonLib.h" | |
#include "Compress.h" | |
#include "Crc32.h" | |
#include "EfiUtilityMsgs.h" | |
#include "ParseInf.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" | |
}; | |
// | |
// 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 - 2014, 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 atttributes, 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 1~64K. It is specified in same\n\ | |
order that the section file is input.\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 allcoated"); | |
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~64K). | |
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 allcoated"); | |
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 allcoated"); | |
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 allcoated"); | |
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; | |
} | |
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; | |
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; | |
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], "-r") == 0) || (stricmp (argv[0], "--attributes") == 0)) { | |
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, currnt 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))); | |
} | |
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 allcoated"); | |
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 allcoated"); | |
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; | |
} | |
VerboseMsg ("%s tool start.", UTILITY_NAME); | |
// | |
// 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. | |
// | |
if ((SectType != EFI_SECTION_GUID_DEFINED) && | |
(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 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_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 allcoated"); | |
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 allcoated"); | |
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 allcoated"); | |
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); | |
} | |
VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ()); | |
return GetUtilityStatus (); | |
} |