| /** @file | |
| Creates output file that is a properly formed section per the PI spec. | |
| Copyright (c) 2004 - 2014, 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 paramter", "more than one input file specified"); | |
| return STATUS_ERROR; | |
| } else if (InputFileNum < 1) { | |
| Error (NULL, 0, 2000, "Invalid paramter", "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 paramter", "%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 paramter", "must specify at least one input file"); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (BufferLength == NULL) { | |
| Error (NULL, 0, 2000, "Invalid paramter", "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; | |
| } | |
| 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 paramter", "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; | |
| } | |
| } | |
| 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 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; | |
| //} | |
| 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) { | |
| 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 | |
| // | |
| 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!"); | |
| return 1; | |
| } | |
| 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!"); | |
| return 1; | |
| } | |
| 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"); | |
| return 1; | |
| } | |
| 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"); | |
| return 1; | |
| } | |
| 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) && (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 (); | |
| } |