/** @file
Copyright (c) 2004 - 2011, 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
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Abstract:
Creates output file that is a properly formed section per the PI spec.
**/
#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_MAJOR_VERSION 0
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
};
"1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
"1K", "2K", "4K", "8K", "16K", "32K", "64K"
};
//
// Crc32 GUID section related definitions.
//
typedef struct {
Version (
)
/*++
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);
}
Usage (
)
/*++
Routine Description:
Print Help message.
Arguments:
VOID
Returns:
None
--*/
{
//
// Summary usage
//
//
// Copyright declaration
//
//
// Details Option
//
File is the SectionFile to be created.\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");
Compress method type can be PI_NONE or PI_STD.\n\
if -c option is not given, PI_STD is default type.\n");
GuidValue is one specific vendor guid value.\n\
Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
GuidHeaderLength is the size of header of guided data\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");
String is a NULL terminated string used in Ui section.\n");
Number is an integer value between 0000 and 9999\n\
used in Ver section.\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");
}
)
/*++
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') {
}
//
// End the UniString with a NULL.
//
*UniString = '\0';
}
)
/*++
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
--*/
{
if (InputFileNum > 1) {
return STATUS_ERROR;
} else if (InputFileNum < 1) {
return STATUS_ERROR;
}
//
// Open the input file
//
return STATUS_ERROR;
}
//
// Seek to the end of the input file so we can determine its size
//
DebugMsg (NULL, 0, 9, "Input file", "File name is %s and File size is %u bytes", InputFileName[0], (unsigned) InputFileLength);
//
// Size must fit in 3 bytes
//
if (TotalLength >= MAX_SECTION_SIZE) {
Error (NULL, 0, 2000, "Invalid paramter", "%s file size (0x%X) exceeds section size limit(%uM).", InputFileName[0], (unsigned) TotalLength, MAX_SECTION_SIZE>>20);
goto Done;
}
//
// Fill in the fields in the local section header structure
//
goto Done;
}
//
// read data from the input file.
//
if (InputFileLength != 0) {
if (fread (Buffer + sizeof (EFI_COMMON_SECTION_HEADER), (size_t) InputFileLength, 1, InFile) != 1) {
goto Done;
}
}
//
// Set OutFileBuffer
//
*OutFileBuffer = Buffer;
Done:
return Status;
}
)
/*++
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.
--*/
{
//
// Check AlignBuffer
//
if (AlignBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
}
return EFI_INVALID_PARAMETER;
}
)
/*++
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.
--*/
{
if (InputFileNum < 1) {
return EFI_INVALID_PARAMETER;
}
if (BufferLength == 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.
//
//
// make sure section ends on a DWORD boundary
//
while ((Size & 0x03) != 0) {
FileBuffer[Size] = 0;
}
Size++;
}
//
// Open file and read contents
//
return EFI_ABORTED;
}
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) {
//
//
TeOffset = 0;
HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
}
}
}
//
// Revert TeOffset to the converse value relative to Alignment
// This is to assure the original PeImage Header at Alignment.
//
if (TeOffset != 0) {
}
//
// 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);
}
DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", "Pad Raw section size is %u", (unsigned) Offset);
}
}
//
// Now read the contents of the file into the buffer
// Buffer must be enough to contain the file content.
//
return EFI_ABORTED;
}
}
}
//
// Set the real required buffer size.
//
if (Size > *BufferLength) {
*BufferLength = Size;
return EFI_BUFFER_TOO_SMALL;
} else {
*BufferLength = Size;
return EFI_SUCCESS;
}
}
)
/*++
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.
--*/
{
InputLength = 0;
FileBuffer = NULL;
OutputBuffer = NULL;
CompressedLength = 0;
//
// read all input file contents into a buffer
// first get the size of all file contents
//
);
if (Status == EFI_BUFFER_TOO_SMALL) {
if (FileBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// read all input file contents into a buffer
//
);
}
if (FileBuffer != NULL) {
free (FileBuffer);
}
return Status;
}
//
// Now data is in FileBuffer, compress the data
//
switch (SectCompSubType) {
case EFI_NOT_COMPRESSED:
//
// Copy file buffer to the none compressed data.
//
if (OutputBuffer == NULL) {
free (FileBuffer);
return EFI_OUT_OF_RESOURCES;
}
break;
case EFI_STANDARD_COMPRESSION:
break;
default:
free (FileBuffer);
return EFI_ABORTED;
}
if (CompressFunction != NULL) {
if (Status == EFI_BUFFER_TOO_SMALL) {
if (!OutputBuffer) {
free (FileBuffer);
return EFI_OUT_OF_RESOURCES;
}
Status = CompressFunction (FileBuffer, InputLength, OutputBuffer + sizeof (EFI_COMPRESSION_SECTION), &CompressedLength);
}
free (FileBuffer);
if (FileBuffer != NULL) {
free (FileBuffer);
}
return Status;
}
}
"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 paramter", "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;
}
//
// Add the section header for the compressed data
//
//
// Set OutFileBuffer
//
return EFI_SUCCESS;
}
)
/*++
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.
--*/
{
InputLength = 0;
Offset = 0;
FileBuffer = NULL;
Offset = sizeof (CRC32_SECTION_HEADER);
} else {
Offset = sizeof (EFI_GUID_DEFINED_SECTION);
}
//
// read all input file contents into a buffer
// first get the size of all file contents
//
);
if (Status == EFI_BUFFER_TOO_SMALL) {
if (FileBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// read all input file contents into a buffer
//
FileBuffer + Offset,
);
}
if (FileBuffer != NULL) {
free (FileBuffer);
}
return Status;
}
if (InputLength == 0) {
Error (NULL, 0, 2000, "Invalid parameter", "the size of input file %s can't be zero", InputFileName);
return EFI_NOT_FOUND;
}
//
// Now data is in FileBuffer + Offset
//
//
// Default Guid section is CRC32.
//
Crc32Checksum = 0;
if (TotalLength >= MAX_SECTION_SIZE) {
Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
free (FileBuffer);
return STATUS_ERROR;
}
memcpy (&(Crc32GuidSect->GuidSectionHeader.SectionDefinitionGuid), &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", Crc32GuidSect->GuidSectionHeader.DataOffset);
} else {
if (TotalLength >= MAX_SECTION_SIZE) {
Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
free (FileBuffer);
return STATUS_ERROR;
}
}
//
// Set OutFileBuffer
//
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.
--*/
{
int VersionNumber;
InputFileAlignNum = 0;
SectionName = NULL;
StringBuffer = "";
VersionNumber = 0;
InputFileNum = 0;
SectCompSubType = 0;
InputLength = 0;
LogLevel = 0;
SectGuidHeaderLength = 0;
VersionSect = NULL;
if (argc == 1) {
Usage ();
return STATUS_ERROR;
}
//
// Parse command line
//
argc --;
argv ++;
Version ();
Usage ();
return STATUS_SUCCESS;
}
Version ();
return STATUS_SUCCESS;
}
while (argc > 0) {
if (SectionName == NULL) {
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if (OutputFileName == NULL) {
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if (CompressionName == NULL) {
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
//
// NONE attribute
//
} else {
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
if (StringBuffer == NULL) {
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
goto Finish;
}
//
// Verify string is a integrator number
//
goto Finish;
}
}
argc -= 2;
argv += 2;
continue;
}
VerboseMsg ("Verbose output Mode Set!");
argc --;
argv ++;
continue;
}
KeyMsg ("Quiet output Mode Set!");
argc --;
argv ++;
continue;
}
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;
}
argc -= 2;
argv += 2;
continue;
}
//
// Section File alignment requirement
//
if (InputFileAlignNum == 0) {
if (InputFileAlign == NULL) {
return 1;
}
} else if (InputFileAlignNum % MAXIMUM_INPUT_FILE_NUM == 0) {
);
if (InputFileAlign == NULL) {
return 1;
}
}
goto Finish;
}
argc -= 2;
argv += 2;
continue;
}
//
// Get Input file name
//
if (InputFileName == NULL) {
return 1;
}
} else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
//
// InputFileName buffer too small, need to realloc
//
);
if (InputFileName == NULL) {
return 1;
}
}
argc --;
argv ++;
}
goto Finish;
}
//
// Parse all command line parameters to get the corresponding section type.
//
if (SectionName == NULL) {
//
// No specified Section type, default is SECTION_ALL.
//
if (CompressionName == NULL) {
//
// Default is PI_STD compression algorithm.
//
} else {
goto Finish;
}
if ((SectGuidAttribute & EFI_GUIDED_SECTION_NONE) != 0) {
//
// NONE attribute, clear attribute value.
//
}
VerboseMsg ("Vendor Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
(unsigned) VendorGuid.Data1,
VendorGuid.Data4[0],
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) {
}
if (SectGuidHeaderLength != 0) {
}
goto Finish;
}
if (StringBuffer[0] == '\0') {
goto Finish;
}
} else {
goto Finish;
}
//
// GuidValue is only required by Guided section.
//
fprintf (stdout, "Warning: the input guid value is not required for this section type %s\n", SectionName);
}
//
// Check whether there is input file
//
//
// The input file are required for other section type.
//
if (InputFileNum == 0) {
goto Finish;
}
}
//
// Check whether there is output file
//
}
if (OutputFileName == NULL) {
goto Finish;
// OutFile = stdout;
}
//
// 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) {
}
);
break;
case EFI_SECTION_GUID_DEFINED:
//
// 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.
//
}
);
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.
//
if (OutFileBuffer == NULL) {
goto Finish;
}
break;
Index = sizeof (EFI_COMMON_SECTION_HEADER);
//
// StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
//
if (OutFileBuffer == NULL) {
goto Finish;
}
break;
case EFI_SECTION_ALL:
//
// read all input file contents into a buffer
// first get the size of all file contents
//
);
if (Status == EFI_BUFFER_TOO_SMALL) {
if (OutFileBuffer == NULL) {
goto Finish;
}
//
// read all input file contents into a buffer
//
);
}
break;
default:
//
// All other section types are caught by default (they're all the same)
//
);
break;
}
goto Finish;
}
//
// Get output file length
//
if (SectType != EFI_SECTION_ALL) {
}
//
// Write the output file
//
goto Finish;
}
if (InputFileName != NULL) {
}
if (InputFileAlign != NULL) {
}
if (OutFileBuffer != NULL) {
}
}
return GetUtilityStatus ();
}