| /*++ | |
| Copyright (c) 2004, Intel Corporation | |
| All rights reserved. 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. | |
| Module Name: | |
| GenSection.c | |
| Abstract: | |
| Creates output file that is a properly formed section per the FV spec. | |
| --*/ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <Common/UefiBaseTypes.h> | |
| #include <Common/FirmwareVolumeImageFormat.h> | |
| #include <Protocol/GuidedSectionExtraction.h> | |
| #include "CommonLib.h" | |
| #include "Compress.h" | |
| #include "EfiCustomizedCompress.h" | |
| #include "Crc32.h" | |
| #include "EfiUtilityMsgs.h" | |
| #include "GenSection.h" | |
| #define UTILITY_NAME "GenSection" | |
| #define UTILITY_MAJOR_VERSION 0 | |
| #define UTILITY_MINOR_VERSION 1 | |
| #define PARAMETER_NOT_SPECIFIED "Parameter not specified" | |
| #define MAXIMUM_INPUT_FILE_NUM 10 | |
| char *SectionTypeName[] = { | |
| 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 | |
| }; | |
| char *CompressionTypeName[] = { "NONE", "STANDARD" }; | |
| char *GUIDedSectionTypeName[] = { "CRC32" }; | |
| EFI_GUID gEfiCrc32SectionGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID; | |
| static | |
| void | |
| Version( | |
| void | |
| ) | |
| /*++ | |
| Routine Description: | |
| Print out version information for this utility. | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| printf ("%s v%d.%d -Utility to create output file with formed section per the FV spec.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION); | |
| printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n"); | |
| } | |
| static | |
| VOID | |
| Usage ( | |
| VOID | |
| ) | |
| { | |
| UINTN SectionType; | |
| UINTN DisplayCount; | |
| Version(); | |
| printf ("\nUsage: "UTILITY_NAME " -i InputFile -o OutputFile -s SectionType [SectionType params]\n\n"); | |
| printf (" Where SectionType is one of the following section types:\n\n"); | |
| DisplayCount = 0; | |
| for (SectionType = 0; SectionType <= EFI_SECTION_LAST_SECTION_TYPE; SectionType++) { | |
| if (SectionTypeName[SectionType] != NULL) { | |
| printf (" %s\n", SectionTypeName[SectionType]); | |
| } | |
| } | |
| printf ("\n and SectionType dependent parameters are as follows:\n\n"); | |
| printf ( | |
| " %s: -t < %s | %s >\n", | |
| SectionTypeName[EFI_SECTION_COMPRESSION], | |
| CompressionTypeName[EFI_NOT_COMPRESSED], | |
| CompressionTypeName[EFI_STANDARD_COMPRESSION] | |
| ); | |
| printf ( | |
| " %s: -t < %s >\n"" // Currently only CRC32 is supported\n\n", | |
| SectionTypeName[EFI_SECTION_GUID_DEFINED], | |
| GUIDedSectionTypeName[EFI_SECTION_CRC32_GUID_DEFINED] | |
| ); | |
| printf ( | |
| " %s: -v VersionNumber\n"" [-a \"Version string\"]\n\n", | |
| SectionTypeName[EFI_SECTION_VERSION] | |
| ); | |
| printf ( | |
| " %s: -a \"Human readable name\"\n\n", | |
| SectionTypeName[EFI_SECTION_USER_INTERFACE] | |
| ); | |
| } | |
| VOID | |
| Ascii2UnicodeWriteString ( | |
| char *String, | |
| FILE *OutFile, | |
| BOOLEAN WriteLangCode | |
| ) | |
| { | |
| UINTN Index; | |
| UINT8 AsciiNull; | |
| // | |
| // BUGBUG need to get correct language code... | |
| // | |
| char *EnglishLangCode = "eng"; | |
| AsciiNull = 0; | |
| // | |
| // first write the language code (english only) | |
| // | |
| if (WriteLangCode) { | |
| fwrite (EnglishLangCode, 1, 4, OutFile); | |
| } | |
| // | |
| // Next, write out the string... Convert ASCII to Unicode in the process. | |
| // | |
| Index = 0; | |
| do { | |
| fwrite (&String[Index], 1, 1, OutFile); | |
| fwrite (&AsciiNull, 1, 1, OutFile); | |
| } while (String[Index++] != 0); | |
| } | |
| STATUS | |
| GenSectionCommonLeafSection ( | |
| char **InputFileName, | |
| int InputFileNum, | |
| UINTN SectionType, | |
| FILE *OutFile | |
| ) | |
| /*++ | |
| 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 | |
| OutFile - Output file handle | |
| Returns: | |
| STATUS_ERROR - can't continue | |
| STATUS_SUCCESS - successful return | |
| --*/ | |
| { | |
| UINT64 InputFileLength; | |
| FILE *InFile; | |
| UINT8 *Buffer; | |
| INTN TotalLength; | |
| EFI_COMMON_SECTION_HEADER CommonSect; | |
| STATUS Status; | |
| if (InputFileNum > 1) { | |
| Error (NULL, 0, 0, "invalid parameter", "more than one input file specified"); | |
| return STATUS_ERROR; | |
| } else if (InputFileNum < 1) { | |
| Error (NULL, 0, 0, "no input file specified", NULL); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Open the input file | |
| // | |
| InFile = fopen (InputFileName[0], "rb"); | |
| if (InFile == NULL) { | |
| Error (NULL, 0, 0, InputFileName[0], "failed to open input file"); | |
| 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); | |
| fgetpos (InFile, &InputFileLength); | |
| fseek (InFile, 0, SEEK_SET); | |
| // | |
| // Fill in the fields in the local section header structure | |
| // | |
| CommonSect.Type = (EFI_SECTION_TYPE) SectionType; | |
| TotalLength = sizeof (CommonSect) + (INTN) InputFileLength; | |
| // | |
| // Size must fit in 3 bytes | |
| // | |
| if (TotalLength >= 0x1000000) { | |
| Error (NULL, 0, 0, InputFileName[0], "file size (0x%X) exceeds section size limit", TotalLength); | |
| goto Done; | |
| } | |
| // | |
| // Now copy the size into the section header and write out the section header | |
| // | |
| memcpy (&CommonSect.Size, &TotalLength, 3); | |
| fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile); | |
| // | |
| // Allocate a buffer to read in the contents of the input file. Then | |
| // read it in as one block and write it to the output file. | |
| // | |
| if (InputFileLength != 0) { | |
| Buffer = (UINT8 *) malloc ((size_t) InputFileLength); | |
| if (Buffer == NULL) { | |
| Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); | |
| goto Done; | |
| } | |
| if (fread (Buffer, (size_t) InputFileLength, 1, InFile) != 1) { | |
| Error (NULL, 0, 0, InputFileName[0], "failed to read contents of file"); | |
| goto Done; | |
| } | |
| if (fwrite (Buffer, (size_t) InputFileLength, 1, OutFile) != 1) { | |
| Error (NULL, 0, 0, "failed to write to output file", NULL); | |
| goto Done; | |
| } | |
| } | |
| Status = STATUS_SUCCESS; | |
| Done: | |
| fclose (InFile); | |
| if (Buffer != NULL) { | |
| free (Buffer); | |
| } | |
| return Status; | |
| } | |
| EFI_STATUS | |
| GetSectionContents ( | |
| char **InputFileName, | |
| int InputFileNum, | |
| UINT8 *FileBuffer, | |
| UINTN *BufferLength | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get the contents of all section files specified in InputFileName | |
| into FileBuffer. | |
| Arguments: | |
| InputFileName - Name of the input file. | |
| InputFileNum - Number of input files. Should be at least 1. | |
| FileBuffer - Output buffer to contain data | |
| BufferLength - Actual length of the data | |
| Returns: | |
| EFI_SUCCESS on successful return | |
| EFI_INVALID_PARAMETER if InputFileNum is less than 1 | |
| EFI_ABORTED if unable to open input file. | |
| --*/ | |
| { | |
| UINTN Size; | |
| UINTN FileSize; | |
| INTN Index; | |
| FILE *InFile; | |
| if (InputFileNum < 1) { | |
| Error (NULL, 0, 0, "must specify at least one input file", NULL); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Size = 0; | |
| // | |
| // Go through our array of file names and copy their contents | |
| // to the output buffer. | |
| // | |
| for (Index = 0; Index < InputFileNum; Index++) { | |
| InFile = fopen (InputFileName[Index], "rb"); | |
| if (InFile == NULL) { | |
| Error (NULL, 0, 0, InputFileName[Index], "failed to open input file"); | |
| return EFI_ABORTED; | |
| } | |
| fseek (InFile, 0, SEEK_END); | |
| FileSize = ftell (InFile); | |
| fseek (InFile, 0, SEEK_SET); | |
| // | |
| // Now read the contents of the file into the buffer | |
| // | |
| if (FileSize > 0) { | |
| if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) { | |
| Error (NULL, 0, 0, InputFileName[Index], "failed to read contents of input file"); | |
| fclose (InFile); | |
| return EFI_ABORTED; | |
| } | |
| } | |
| fclose (InFile); | |
| Size += (UINTN) FileSize; | |
| // | |
| // make sure section ends on a DWORD boundary | |
| // | |
| while ((Size & 0x03) != 0) { | |
| FileBuffer[Size] = 0; | |
| Size++; | |
| } | |
| } | |
| *BufferLength = Size; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GenSectionCompressionSection ( | |
| char **InputFileName, | |
| int InputFileNum, | |
| UINTN SectionType, | |
| UINTN SectionSubType, | |
| FILE *OutFile | |
| ) | |
| /*++ | |
| 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. | |
| InputFileNum - Number of input files. Should be at least 1. | |
| SectionType - Section type to generate. Should be | |
| EFI_SECTION_COMPRESSION | |
| SectionSubType - Specify the compression algorithm requested. | |
| OutFile - Output file handle | |
| 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. | |
| --*/ | |
| { | |
| UINTN TotalLength; | |
| UINTN InputLength; | |
| UINTN CompressedLength; | |
| UINT8 *FileBuffer; | |
| UINT8 *OutputBuffer; | |
| EFI_STATUS Status; | |
| EFI_COMPRESSION_SECTION CompressionSect; | |
| COMPRESS_FUNCTION CompressFunction; | |
| if (SectionType != EFI_SECTION_COMPRESSION) { | |
| Error (NULL, 0, 0, "parameter must be EFI_SECTION_COMPRESSION", NULL); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| InputLength = 0; | |
| FileBuffer = NULL; | |
| OutputBuffer = NULL; | |
| CompressedLength = 0; | |
| FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 4) * sizeof (UINT8)); | |
| if (FileBuffer == NULL) { | |
| Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // read all input file contents into a buffer | |
| // | |
| Status = GetSectionContents ( | |
| InputFileName, | |
| InputFileNum, | |
| FileBuffer, | |
| &InputLength | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| free (FileBuffer); | |
| return Status; | |
| } | |
| CompressFunction = NULL; | |
| // | |
| // Now data is in FileBuffer, compress the data | |
| // | |
| switch (SectionSubType) { | |
| case EFI_NOT_COMPRESSED: | |
| CompressedLength = InputLength; | |
| break; | |
| case EFI_STANDARD_COMPRESSION: | |
| CompressFunction = (COMPRESS_FUNCTION) EfiCompress; | |
| break; | |
| case EFI_CUSTOMIZED_COMPRESSION: | |
| CompressFunction = (COMPRESS_FUNCTION) CustomizedCompress; | |
| break; | |
| default: | |
| Error (NULL, 0, 0, "unknown compression type", NULL); | |
| free (FileBuffer); | |
| return EFI_ABORTED; | |
| } | |
| if (CompressFunction != NULL) { | |
| Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength); | |
| if (Status == EFI_BUFFER_TOO_SMALL) { | |
| OutputBuffer = malloc (CompressedLength); | |
| if (!OutputBuffer) { | |
| free (FileBuffer); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength); | |
| } | |
| free (FileBuffer); | |
| FileBuffer = OutputBuffer; | |
| if (EFI_ERROR (Status)) { | |
| if (FileBuffer != NULL) { | |
| free (FileBuffer); | |
| } | |
| return Status; | |
| } | |
| } | |
| TotalLength = CompressedLength + sizeof (EFI_COMPRESSION_SECTION); | |
| // | |
| // Add the section header for the compressed data | |
| // | |
| CompressionSect.CommonHeader.Type = (EFI_SECTION_TYPE) SectionType; | |
| 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 = (UINT8) SectionSubType; | |
| CompressionSect.UncompressedLength = InputLength; | |
| fwrite (&CompressionSect, sizeof (CompressionSect), 1, OutFile); | |
| fwrite (FileBuffer, CompressedLength, 1, OutFile); | |
| free (FileBuffer); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GenSectionGuidDefinedSection ( | |
| char **InputFileName, | |
| int InputFileNum, | |
| UINTN SectionType, | |
| UINTN SectionSubType, | |
| FILE *OutFile | |
| ) | |
| /*++ | |
| 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. | |
| InputFileNum - Number of input files. Should be at least 1. | |
| SectionType - Section type to generate. Should be | |
| EFI_SECTION_GUID_DEFINED | |
| SectionSubType - Specify the authentication algorithm requested. | |
| OutFile - Output file handle | |
| 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. | |
| --*/ | |
| { | |
| INTN TotalLength; | |
| INTN InputLength; | |
| UINT8 *FileBuffer; | |
| UINT32 Crc32Checksum; | |
| EFI_STATUS Status; | |
| CRC32_SECTION_HEADER Crc32GuidSect; | |
| if (SectionType != EFI_SECTION_GUID_DEFINED) { | |
| Error (NULL, 0, 0, "parameter must be EFI_SECTION_GUID_DEFINED", NULL); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| InputLength = 0; | |
| FileBuffer = NULL; | |
| FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 4) * sizeof (UINT8)); | |
| if (FileBuffer == NULL) { | |
| Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // read all input file contents into a buffer | |
| // | |
| Status = GetSectionContents ( | |
| InputFileName, | |
| InputFileNum, | |
| FileBuffer, | |
| &InputLength | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| free (FileBuffer); | |
| return Status; | |
| } | |
| // | |
| // Now data is in FileBuffer, compress the data | |
| // | |
| switch (SectionSubType) { | |
| case EFI_SECTION_CRC32_GUID_DEFINED: | |
| Crc32Checksum = 0; | |
| CalculateCrc32 (FileBuffer, InputLength, &Crc32Checksum); | |
| if (EFI_ERROR (Status)) { | |
| free (FileBuffer); | |
| return Status; | |
| } | |
| TotalLength = InputLength + CRC32_SECTION_HEADER_SIZE; | |
| Crc32GuidSect.GuidSectionHeader.CommonHeader.Type = (EFI_SECTION_TYPE) SectionType; | |
| 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), &gEfiCrc32SectionGuid, sizeof (EFI_GUID)); | |
| Crc32GuidSect.GuidSectionHeader.Attributes = EFI_GUIDED_SECTION_AUTH_STATUS_VALID; | |
| Crc32GuidSect.GuidSectionHeader.DataOffset = CRC32_SECTION_HEADER_SIZE; | |
| Crc32GuidSect.CRC32Checksum = Crc32Checksum; | |
| break; | |
| default: | |
| Error (NULL, 0, 0, "invalid parameter", "unknown GUID defined type"); | |
| free (FileBuffer); | |
| return EFI_ABORTED; | |
| } | |
| fwrite (&Crc32GuidSect, sizeof (Crc32GuidSect), 1, OutFile); | |
| fwrite (FileBuffer, InputLength, 1, OutFile); | |
| free (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. | |
| --*/ | |
| { | |
| INTN Index; | |
| INTN VersionNumber; | |
| UINTN SectionType; | |
| UINTN SectionSubType; | |
| BOOLEAN InputFileRequired; | |
| BOOLEAN SubTypeRequired; | |
| FILE *InFile; | |
| FILE *OutFile; | |
| INTN InputFileNum; | |
| char **InputFileName; | |
| char *OutputFileName; | |
| char AuxString[500] = { 0 }; | |
| char *ParamSectionType; | |
| char *ParamSectionSubType; | |
| char *ParamLength; | |
| char *ParamVersion; | |
| char *ParamDigitalSignature; | |
| EFI_STATUS Status; | |
| EFI_COMMON_SECTION_HEADER CommonSect; | |
| InputFileName = NULL; | |
| OutputFileName = PARAMETER_NOT_SPECIFIED; | |
| ParamSectionType = PARAMETER_NOT_SPECIFIED; | |
| ParamSectionSubType = PARAMETER_NOT_SPECIFIED; | |
| ParamLength = PARAMETER_NOT_SPECIFIED; | |
| ParamVersion = PARAMETER_NOT_SPECIFIED; | |
| ParamDigitalSignature = PARAMETER_NOT_SPECIFIED; | |
| Status = EFI_SUCCESS; | |
| VersionNumber = 0; | |
| SectionType = 0; | |
| SectionSubType = 0; | |
| InputFileRequired = TRUE; | |
| SubTypeRequired = FALSE; | |
| InFile = NULL; | |
| OutFile = NULL; | |
| InputFileNum = 0; | |
| Status = EFI_SUCCESS; | |
| SetUtilityName (UTILITY_NAME); | |
| if (argc == 1) { | |
| Usage (); | |
| return STATUS_ERROR; | |
| } | |
| if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) || | |
| (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) { | |
| Usage(); | |
| return STATUS_ERROR; | |
| } | |
| if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) { | |
| Version(); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Parse command line | |
| // | |
| Index = 1; | |
| while (Index < argc) { | |
| if (strcmpi (argv[Index], "-i") == 0) { | |
| // | |
| // Input File found | |
| // | |
| Index++; | |
| InputFileName = (char **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (char *)); | |
| if (InputFileName == NULL) { | |
| Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (char *))); | |
| InputFileName[InputFileNum] = argv[Index]; | |
| InputFileNum++; | |
| Index++; | |
| // | |
| // Parse subsequent parameters until another switch is encountered | |
| // | |
| while ((Index < argc) && (argv[Index][0] != '-')) { | |
| if ((InputFileNum % MAXIMUM_INPUT_FILE_NUM) == 0) { | |
| // | |
| // InputFileName buffer too small, need to realloc | |
| // | |
| InputFileName = (char **) realloc ( | |
| InputFileName, | |
| (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (char *) | |
| ); | |
| if (InputFileName == NULL) { | |
| Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (char *))); | |
| } | |
| InputFileName[InputFileNum] = argv[Index]; | |
| InputFileNum++; | |
| Index++; | |
| } | |
| } | |
| if (strcmpi (argv[Index], "-o") == 0) { | |
| // | |
| // Output file found | |
| // | |
| Index++; | |
| OutputFileName = argv[Index]; | |
| } else if (strcmpi (argv[Index], "-s") == 0) { | |
| // | |
| // Section Type found | |
| // | |
| Index++; | |
| ParamSectionType = argv[Index]; | |
| } else if (strcmpi (argv[Index], "-t") == 0) { | |
| // | |
| // Compression or Authentication type | |
| // | |
| Index++; | |
| ParamSectionSubType = argv[Index]; | |
| } else if (strcmpi (argv[Index], "-l") == 0) { | |
| // | |
| // Length | |
| // | |
| Index++; | |
| ParamLength = argv[Index]; | |
| } else if (strcmpi (argv[Index], "-v") == 0) { | |
| // | |
| // VersionNumber | |
| // | |
| Index++; | |
| ParamVersion = argv[Index]; | |
| } else if (strcmpi (argv[Index], "-a") == 0) { | |
| // | |
| // Aux string | |
| // | |
| Index++; | |
| // | |
| // Note, the MSVC C-Start parses out and consolidates quoted strings from the command | |
| // line. Quote characters are stripped. If this tool is ported to other environments | |
| // this will need to be taken into account | |
| // | |
| strncpy (AuxString, argv[Index], 499); | |
| } else if (strcmpi (argv[Index], "-d") == 0) { | |
| // | |
| // Digital signature for EFI_TEST_AUTHENTICAION (must be 0 or 1) | |
| // | |
| Index++; | |
| ParamDigitalSignature = argv[Index]; | |
| } else if (strcmpi (argv[Index], "-?") == 0) { | |
| Usage (); | |
| return STATUS_ERROR; | |
| } else { | |
| Error (NULL, 0, 0, argv[Index], "unknown option"); | |
| return GetUtilityStatus (); | |
| } | |
| Index++; | |
| } | |
| // | |
| // At this point, all command line parameters are verified as not being totally | |
| // bogus. Next verify the command line parameters are complete and make | |
| // sense... | |
| // | |
| if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_COMPRESSION]) == 0) { | |
| SectionType = EFI_SECTION_COMPRESSION; | |
| SubTypeRequired = TRUE; | |
| if (stricmp (ParamSectionSubType, CompressionTypeName[EFI_NOT_COMPRESSED]) == 0) { | |
| SectionSubType = EFI_NOT_COMPRESSED; | |
| } else if (stricmp (ParamSectionSubType, CompressionTypeName[EFI_STANDARD_COMPRESSION]) == 0) { | |
| SectionSubType = EFI_STANDARD_COMPRESSION; | |
| } else { | |
| Error (NULL, 0, 0, ParamSectionSubType, "unknown compression type"); | |
| Usage (); | |
| return GetUtilityStatus (); | |
| } | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_GUID_DEFINED]) == 0) { | |
| SectionType = EFI_SECTION_GUID_DEFINED; | |
| SubTypeRequired = TRUE; | |
| if (stricmp (ParamSectionSubType, GUIDedSectionTypeName[EFI_SECTION_CRC32_GUID_DEFINED]) == 0) { | |
| SectionSubType = EFI_SECTION_CRC32_GUID_DEFINED; | |
| } else { | |
| Error (NULL, 0, 0, ParamSectionSubType, "unknown GUID defined section type", ParamSectionSubType); | |
| Usage (); | |
| return GetUtilityStatus (); | |
| } | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_PE32]) == 0) { | |
| SectionType = EFI_SECTION_PE32; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_PIC]) == 0) { | |
| SectionType = EFI_SECTION_PIC; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_TE]) == 0) { | |
| SectionType = EFI_SECTION_TE; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_DXE_DEPEX]) == 0) { | |
| SectionType = EFI_SECTION_DXE_DEPEX; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_VERSION]) == 0) { | |
| SectionType = EFI_SECTION_VERSION; | |
| InputFileRequired = FALSE; | |
| Index = sscanf (ParamVersion, "%d", &VersionNumber); | |
| if (Index != 1 || VersionNumber < 0 || VersionNumber > 65565) { | |
| Error (NULL, 0, 0, ParamVersion, "illegal version number"); | |
| Usage (); | |
| return GetUtilityStatus (); | |
| } | |
| if (strcmp (AuxString, PARAMETER_NOT_SPECIFIED) == 0) { | |
| AuxString[0] = 0; | |
| } | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_USER_INTERFACE]) == 0) { | |
| SectionType = EFI_SECTION_USER_INTERFACE; | |
| InputFileRequired = FALSE; | |
| if (strcmp (AuxString, PARAMETER_NOT_SPECIFIED) == 0) { | |
| Error (NULL, 0, 0, "user interface string not specified", NULL); | |
| Usage (); | |
| return GetUtilityStatus (); | |
| } | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_COMPATIBILITY16]) == 0) { | |
| SectionType = EFI_SECTION_COMPATIBILITY16; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_FIRMWARE_VOLUME_IMAGE]) == 0) { | |
| SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_FREEFORM_SUBTYPE_GUID]) == 0) { | |
| SectionType = EFI_SECTION_FREEFORM_SUBTYPE_GUID; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_RAW]) == 0) { | |
| SectionType = EFI_SECTION_RAW; | |
| } else if (stricmp (ParamSectionType, SectionTypeName[EFI_SECTION_PEI_DEPEX]) == 0) { | |
| SectionType = EFI_SECTION_PEI_DEPEX; | |
| } else { | |
| Error (NULL, 0, 0, ParamSectionType, "unknown section type"); | |
| Usage (); | |
| return GetUtilityStatus (); | |
| } | |
| // | |
| // Open output file | |
| // | |
| OutFile = fopen (OutputFileName, "wb"); | |
| if (OutFile == NULL) { | |
| Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); | |
| if (InFile != NULL) { | |
| fclose (InFile); | |
| } | |
| return GetUtilityStatus (); | |
| } | |
| // | |
| // 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 (SectionType) { | |
| case EFI_SECTION_COMPRESSION: | |
| Status = GenSectionCompressionSection ( | |
| InputFileName, | |
| InputFileNum, | |
| SectionType, | |
| SectionSubType, | |
| OutFile | |
| ); | |
| break; | |
| case EFI_SECTION_GUID_DEFINED: | |
| Status = GenSectionGuidDefinedSection ( | |
| InputFileName, | |
| InputFileNum, | |
| SectionType, | |
| SectionSubType, | |
| OutFile | |
| ); | |
| break; | |
| case EFI_SECTION_VERSION: | |
| CommonSect.Type = (EFI_SECTION_TYPE) SectionType; | |
| Index = sizeof (CommonSect); | |
| // | |
| // 2 characters for the build number | |
| // | |
| Index += 2; | |
| // | |
| // Aux string is ascii.. unicode is 2X + 2 bytes for terminating unicode null. | |
| // | |
| Index += (strlen (AuxString) * 2) + 2; | |
| memcpy (&CommonSect.Size, &Index, 3); | |
| fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile); | |
| fwrite (&VersionNumber, 2, 1, OutFile); | |
| Ascii2UnicodeWriteString (AuxString, OutFile, FALSE); | |
| break; | |
| case EFI_SECTION_USER_INTERFACE: | |
| CommonSect.Type = (EFI_SECTION_TYPE) SectionType; | |
| Index = sizeof (CommonSect); | |
| // | |
| // Aux string is ascii.. unicode is 2X + 2 bytes for terminating unicode null. | |
| // | |
| Index += (strlen (AuxString) * 2) + 2; | |
| memcpy (&CommonSect.Size, &Index, 3); | |
| fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile); | |
| Ascii2UnicodeWriteString (AuxString, OutFile, FALSE); | |
| break; | |
| default: | |
| // | |
| // All other section types are caught by default (they're all the same) | |
| // | |
| Status = GenSectionCommonLeafSection ( | |
| InputFileName, | |
| InputFileNum, | |
| SectionType, | |
| OutFile | |
| ); | |
| break; | |
| } | |
| if (InputFileName != NULL) { | |
| free (InputFileName); | |
| } | |
| fclose (OutFile); | |
| // | |
| // If we had errors, then delete the output file | |
| // | |
| if (GetUtilityStatus () == STATUS_ERROR) { | |
| remove (OutputFileName); | |
| } | |
| return GetUtilityStatus (); | |
| } |