From feccee87a78e68d575dbdf44b34ca0cb5a21ea8d Mon Sep 17 00:00:00 2001 From: lhauch Date: Thu, 5 Oct 2006 23:12:07 +0000 Subject: Restructuring for better separation of Tool packages. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1674 6f19259b-4bc3-4df7-8a09-765794883524 --- Tools/CodeTools/TianoTools/GenFfsFile/GenFfsFile.c | 2646 ++++++++++++++++++++ 1 file changed, 2646 insertions(+) create mode 100644 Tools/CodeTools/TianoTools/GenFfsFile/GenFfsFile.c (limited to 'Tools/CodeTools/TianoTools/GenFfsFile/GenFfsFile.c') diff --git a/Tools/CodeTools/TianoTools/GenFfsFile/GenFfsFile.c b/Tools/CodeTools/TianoTools/GenFfsFile/GenFfsFile.c new file mode 100644 index 0000000000..1eea09f5fb --- /dev/null +++ b/Tools/CodeTools/TianoTools/GenFfsFile/GenFfsFile.c @@ -0,0 +1,2646 @@ +/*++ + +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: + + GenFfsFile.c + +Abstract: + + This file contains functions required to generate a Firmware File System + file. + +--*/ + +#include +#include // for isalpha() +// +// include file for _spawnv +// +#ifndef __GNUC__ +#include +#endif +#include +#include + +#include +#include +#include +#include +#include + +#include "ParseInf.h" +#include "EfiCompress.h" +#include "EfiCustomizedCompress.h" +#include "Crc32.h" +#include "GenFfsFile.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "SimpleFileParsing.h" + +#define UTILITY_NAME "GenFfsFile" +#define TOOLVERSION "0.32" +#define MAX_ARRAY_SIZE 100 + +static +INT32 +GetNextLine ( + OUT CHAR8 *Destination, + IN FILE *Package, + IN OUT UINT32 *LineNumber + ); + +static +void +CheckSlash ( + IN OUT CHAR8 *String, + IN FILE *In, + IN OUT UINT32 *LineNumber + ); + +static +INT32 +FindSectionInPackage ( + IN CHAR8 *BuildDirectory, + IN FILE *OverridePackage, + IN OUT UINT32 *LineNumber + ); + +static +STATUS +ProcessCommandLineArgs ( + int Argc, + char *Argv[] + ); + +static +void +PrintUsage ( + void + ); + +// +// Keep globals in this structure +// +static struct { + UINT8 BuildDirectory[_MAX_PATH]; + UINT8 PrimaryPackagePath[_MAX_PATH]; + UINT8 OverridePackagePath[_MAX_PATH]; + BOOLEAN Verbose; +} mGlobals; + +static EFI_GUID mZeroGuid = { 0 }; + +static +void +StripQuotes ( + IN OUT CHAR8 *String + ) +/*++ + +Routine Description: + + Removes quotes and/or whitespace from around a string + +Arguments: + + String - String to remove quotes from + +Returns: + + None + +--*/ +{ + UINTN Index; + UINTN Index2; + UINTN StrLen; + + Index2 = strspn (String, "\" \t\n"); + StrLen = strlen (String); + + for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) { + String[Index - Index2] = String[Index]; + } + + String[Index - Index2] = 0; +} + +static +void +PrintUsage ( + void + ) +/*++ + +Routine Description: + + Print Error / Help message. + +Arguments: + + void + +Returns: + + None + +--*/ +{ + printf ("Usage:\n"); + printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\" -v\n"); + printf (" -b \"build directory\":\n "); + printf (" specifies the full path to the component build directory.\n"); + printf (" -p1 \"P1_path\":\n"); + printf (" specifies fully qualified file name to the primary package file.\n"); + printf (" This file will normally exist in the same directory as the makefile\n"); + printf (" for the component. Required.\n"); + printf (" -p2 \"P2_path\":\n"); + printf (" specifies fully qualified file name to the override package file.\n"); + printf (" This file will normally exist in the build tip. Optional.\n"); +} + +static +INT32 +TestComment ( + IN CHAR8 *String, + IN FILE *In + ) +/*++ + +Routine Description: + + Tests input string to see if it is a comment, and if so goes to the next line in the file that is not a comment + +Arguments: + + String - String to test + + In - Open file to move pointer within + +Returns: + + -1 - End of file reached + 0 - Not a comment + 1 - Comment bypassed + +--*/ +{ + CHAR8 CharBuffer; + + CharBuffer = 0; + if ((String[0] == '/') && (String[1] == '/')) { + while (CharBuffer != '\n') { + fscanf (In, "%c", &CharBuffer); + if (feof (In)) { + return -1; + } + } + } else { + return 0; + } + + return 1; +} + +static +void +BreakString ( + IN CONST CHAR8 *Source, + OUT CHAR8 *Destination, + IN INTN Direction + ) +/*++ + +Routine Description: + + Takes an input string and returns either the part before the =, or the part after the =, depending on direction + +Arguments: + + Source - String to break + + Destination - Buffer to place new string in + + Direction - 0 to return all of source string before = + 1 to return all of source string after = + +Returns: + + None + +--*/ +{ + UINTN Index; + UINTN Index2; + + Index = 0; + Index2 = 0; + + if (strchr (Source, '=') == NULL) { + strcpy (Destination, Source); + + return ; + } + + if (Direction == 0) { + // + // return part of string before = + // + while (Source[Index] != '=') { + Destination[Index] = Source[Index++]; + } + + Destination[Index] = 0; + } else { + // + // return part of string after = + // + strcpy (Destination, strchr (Source, '=') + 1); + } +} + +static +INT32 +GetNextLine ( + OUT CHAR8 *Destination, + IN FILE *Package, + IN OUT UINT32 *LineNumber + ) +/*++ + +Routine Description: + + Gets the next non-commented line from the file + +Arguments: + + Destination - Where to put string + + Package - Package to get string from + + LineNumber - The actual line number. + +Returns: + + -1 - End of file reached + 0 - Success + +--*/ +{ + CHAR8 String[_MAX_PATH]; + fscanf (Package, "%s", &String); + if (feof (Package)) { + return -1; + } + + while (TestComment (String, Package) == 1) { + fscanf (Package, "%s", &String); + if (feof (Package)) { + return -1; + } + } + + strcpy (Destination, String); + return 0; +} + +static +VOID +CheckSlash ( + IN OUT CHAR8 *String, + IN FILE *In, + IN OUT UINT32 *LineNumber + ) +/*++ + +Routine Description: + + Checks to see if string is line continuation character, if so goes to next valid line + +Arguments: + + String - String to test + + In - Open file to move pointer within + + LineNumber - The line number. + +Returns: + + None + +--*/ +{ + CHAR8 ByteBuffer; + ByteBuffer = 0; + + switch (String[0]) { + + case '\\': + while (String[0] == '\\') { + while (ByteBuffer != '\n') { + fscanf (In, "%c", &ByteBuffer); + } + (*LineNumber)++; + if (GetNextLine (String, In, LineNumber) == -1) { + return ; + } + } + break; + + case '\n': + (*LineNumber)++; + while (String[0] == '\n') { + if (GetNextLine (String, In, LineNumber) == -1) { + return ; + } + } + break; + + default: + break; + + } + +} + +static +INT32 +FindSectionInPackage ( + IN CHAR8 *BuildDirectory, + IN FILE *OverridePackage, + IN OUT UINT32 *LineNumber + ) +/*++ + +Routine Description: + + Finds the matching section within the package + +Arguments: + + BuildDirectory - name of section to find + + OverridePackage - Package file to search within + + LineNumber - The line number. + +Returns: + + -1 - End of file reached + 0 - Success + +--*/ +{ + CHAR8 String[_MAX_PATH]; + CHAR8 NewString[_MAX_PATH]; + String[0] = 0; + + while (strcmp (BuildDirectory, String) != 0) { + if (GetNextLine (NewString, OverridePackage, LineNumber) != 0) { + return -1; + } + + if (NewString[0] == '[') { + if (NewString[strlen (NewString) - 1] != ']') { + // + // have to construct string. + // + strcpy (String, NewString + 1); + + while (1) { + fscanf (OverridePackage, "%s", &NewString); + if (feof (OverridePackage)) { + return -1; + } + + if (NewString[0] != ']') { + if (strlen (String) != 0) { + strcat (String, " "); + } + + strcat (String, NewString); + if (String[strlen (String) - 1] == ']') { + String[strlen (String) - 1] = 0; + break; + } + } else { + break; + } + } + } else { + NewString[strlen (NewString) - 1] = 0; + strcpy (String, NewString + 1); + } + } + } + + return 0; +} + +static +EFI_STATUS +GenSimpleGuidSection ( + IN OUT UINT8 *FileBuffer, + IN OUT UINT32 *BufferSize, + IN UINT32 DataSize, + IN EFI_GUID SignGuid, + IN UINT16 GuidedSectionAttributes + ) +/*++ + +Routine Description: + + add GUIDed section header for the data buffer. + data stays in same location (overwrites source data). + +Arguments: + + FileBuffer - Buffer containing data to sign + + BufferSize - On input, the size of FileBuffer. On output, the size of + actual section data (including added section header). + + DataSize - Length of data to Sign + + SignGuid - Guid to be add. + + GuidedSectionAttributes - The section attribute. + +Returns: + + EFI_SUCCESS - Successful + EFI_OUT_OF_RESOURCES - Not enough resource. + +--*/ +{ + UINT32 TotalSize; + + EFI_GUID_DEFINED_SECTION GuidSectionHeader; + UINT8 *SwapBuffer; + + SwapBuffer = NULL; + + if (DataSize == 0) { + *BufferSize = 0; + + return EFI_SUCCESS; + } + + TotalSize = DataSize + sizeof (EFI_GUID_DEFINED_SECTION); + GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED; + GuidSectionHeader.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff); + GuidSectionHeader.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8); + GuidSectionHeader.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16); + memcpy (&(GuidSectionHeader.SectionDefinitionGuid), &SignGuid, sizeof (EFI_GUID)); + GuidSectionHeader.Attributes = GuidedSectionAttributes; + GuidSectionHeader.DataOffset = sizeof (EFI_GUID_DEFINED_SECTION); + + SwapBuffer = (UINT8 *) malloc (DataSize); + if (SwapBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + memcpy (SwapBuffer, FileBuffer, DataSize); + memcpy (FileBuffer, &GuidSectionHeader, sizeof (EFI_GUID_DEFINED_SECTION)); + memcpy (FileBuffer + sizeof (EFI_GUID_DEFINED_SECTION), SwapBuffer, DataSize); + + // + // Make sure section ends on a DWORD boundary + // + while ((TotalSize & 0x03) != 0) { + FileBuffer[TotalSize] = 0; + TotalSize++; + } + + *BufferSize = TotalSize; + + if (SwapBuffer != NULL) { + free (SwapBuffer); + } + + return EFI_SUCCESS; +} + +static +EFI_STATUS +CompressSection ( + UINT8 *FileBuffer, + UINT32 *BufferSize, + UINT32 DataSize, + CHAR8 *Type + ) +/*++ + +Routine Description: + + Compress the data and add section header for the compressed data. + Compressed data (with section header) stays in same location as the source + (overwrites source data). + +Arguments: + + FileBuffer - Buffer containing data to Compress + + BufferSize - On input, the size of FileBuffer. On output, the size of + actual compressed data (including added section header). + When buffer is too small, this value indicates the size needed. + + DataSize - The size of data to compress + + Type - The compression type (not used currently). + Assume EFI_HEAVY_COMPRESSION. + +Returns: + + EFI_BUFFER_TOO_SMALL - Buffer size is too small. + EFI_UNSUPPORTED - Compress type can not be supported. + EFI_SUCCESS - Successful + EFI_OUT_OF_RESOURCES - Not enough resource. + +--*/ +{ + EFI_STATUS Status; + UINT8 *CompData; + UINT32 CompSize; + UINT32 TotalSize; + EFI_COMPRESSION_SECTION CompressionSet; + UINT8 CompressionType; + COMPRESS_FUNCTION CompressFunction; + + Status = EFI_SUCCESS; + CompData = NULL; + CompSize = 0; + TotalSize = 0; + CompressFunction = NULL; + + // + // Get the compress type + // + if (strcmpi (Type, "Dummy") == 0) { + // + // Added "Dummy" to keep backward compatibility. + // + CompressionType = EFI_STANDARD_COMPRESSION; + CompressFunction = (COMPRESS_FUNCTION) Compress; + + } else if (strcmpi (Type, "LZH") == 0) { + // + // EFI stardard compression (LZH) + // + CompressionType = EFI_STANDARD_COMPRESSION; + CompressFunction = (COMPRESS_FUNCTION) Compress; + + } else { + // + // Customized compression + // + Status = SetCustomizedCompressionType (Type); + if (EFI_ERROR (Status)) { + return Status; + } + + CompressionType = EFI_CUSTOMIZED_COMPRESSION; + CompressFunction = (COMPRESS_FUNCTION) CustomizedCompress; + } + // + // Compress the raw data + // + Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + CompData = malloc (CompSize); + if (!CompData) { + return EFI_OUT_OF_RESOURCES; + } + + Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize); + } + + if (EFI_ERROR (Status)) { + if (CompData != NULL) { + free (CompData); + } + + return Status; + } + + TotalSize = CompSize + sizeof (EFI_COMPRESSION_SECTION); + + // + // Buffer too small? + // + if (TotalSize > *BufferSize) { + *BufferSize = TotalSize; + if (CompData != NULL) { + free (CompData); + } + + return EFI_BUFFER_TOO_SMALL; + } + // + // Add the section header for the compressed data + // + CompressionSet.CommonHeader.Type = EFI_SECTION_COMPRESSION; + CompressionSet.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff); + CompressionSet.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8); + CompressionSet.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16); + CompressionSet.CompressionType = CompressionType; + CompressionSet.UncompressedLength = DataSize; + + // + // Copy header and data to the buffer + // + memcpy (FileBuffer, &CompressionSet, sizeof (EFI_COMPRESSION_SECTION)); + memcpy (FileBuffer + sizeof (CompressionSet), CompData, CompSize); + + // + // Make sure section ends on a DWORD boundary + // + while ((TotalSize & 0x03) != 0) { + FileBuffer[TotalSize] = 0; + TotalSize++; + } + + *BufferSize = TotalSize; + + if (CompData != NULL) { + free (CompData); + } + + return EFI_SUCCESS; +} + +static +void +StripParens ( + IN OUT CHAR8 *String + ) +/*++ + +Routine Description: + + Removes Parenthesis from around a string + +Arguments: + + String - String to remove parens from + +Returns: + + None + +--*/ +{ + INT32 Index; + + if (String[0] != '(') { + return ; + } + + for (Index = 1; String[Index] != ')'; Index++) { + String[Index - 1] = String[Index]; + if (String[Index] == 0) { + return ; + } + } + + String[Index - 1] = 0; + + return ; +} + +static +void +StripEqualMark ( + IN OUT CHAR8 *String + ) +/*++ + +Routine Description: + + Removes Equal Mark from around a string + +Arguments: + + String - String to remove equal mark from + +Returns: + + None + +--*/ +{ + INT32 Index; + + if (String[0] != '=' && String[strlen (String) - 1] != '=') { + return ; + } + + if (String[0] == '=') { + + for (Index = 1; String[Index] != 0; Index++) { + String[Index - 1] = String[Index]; + } + + String[Index - 1] = 0; + } + + if (String[strlen (String) - 1] == '=') { + String[strlen (String) - 1] = 0; + } + + return ; +} + +static +INT32 +ProcessEnvironmentVariable ( + IN CHAR8 *Buffer, + OUT CHAR8 *NewBuffer + ) +/*++ + +Routine Description: + + Converts environment variables to values + +Arguments: + + Buffer - Buffer containing Environment Variable String + + NewBuffer - Buffer containing value of environment variable + + +Returns: + + Number of characters from Buffer used + +--*/ +{ + INT32 Index; + INT32 Index2; + CHAR8 VariableBuffer[_MAX_PATH]; + + Index = 2; + Index2 = 0; + + while (Buffer[Index] != ')') { + VariableBuffer[Index - 2] = Buffer[Index++]; + } + + VariableBuffer[Index - 2] = 0; + Index++; + + if (getenv (VariableBuffer) != NULL) { + strcpy (NewBuffer, getenv (VariableBuffer)); + } else { + printf ("Environment variable %s not found!\n", VariableBuffer); + } + + return Index; +} + +static +void +SplitAttributesField ( + IN CHAR8 *Buffer, + IN CHAR8 *AttributesArray[], + IN OUT UINT32 *NumberOfAttributes + ) +/* + NumberOfAttributes: on input, it specifies the current number of attributes + stored in AttributeArray. + on output, it is updated to the latest number of attributes + stored in AttributesArray. +*/ +{ + UINT32 Index; + UINT32 Index2; + UINT32 z; + CHAR8 *CharBuffer; + + CharBuffer = NULL; + CharBuffer = (CHAR8 *) malloc (_MAX_PATH); + ZeroMem (CharBuffer, _MAX_PATH); + + for (Index = 0, z = 0, Index2 = 0; Index < strlen (Buffer); Index++) { + + if (Buffer[Index] != '|') { + CharBuffer[z] = Buffer[Index]; + z++; + } else { + + CharBuffer[z] = 0; + AttributesArray[*NumberOfAttributes + Index2] = CharBuffer; + Index2++; + + // + // allocate new char buffer for the next attributes string + // + CharBuffer = (CHAR8 *) malloc (_MAX_PATH); + ZeroMem (CharBuffer, _MAX_PATH); + z = 0; + } + } + + CharBuffer[z] = 0; + // + // record the last attributes string in the Buffer + // + AttributesArray[*NumberOfAttributes + Index2] = CharBuffer; + Index2++; + + *NumberOfAttributes += Index2; + + return ; +} + +static +INT32 +GetToolArguments ( + CHAR8 *ToolArgumentsArray[], + FILE *Package, + CHAR8 **PtrInputFileName, + CHAR8 **PtrOutputFileName, + EFI_GUID *Guid, + UINT16 *GuidedSectionAttributes + ) +{ + CHAR8 Buffer[_MAX_PATH]; + BOOLEAN ArgumentsFlag; + BOOLEAN InputFlag; + BOOLEAN OutputFlag; + BOOLEAN GuidFlag; + BOOLEAN AttributesFlag; + UINT32 argc; + UINT32 Index2; + UINT32 z; + CHAR8 *CharBuffer; + INT32 Index; + INT32 ReturnValue; + EFI_STATUS Status; + + CHAR8 *AttributesArray[MAX_ARRAY_SIZE]; + UINT32 NumberOfAttributes; + CHAR8 *InputFileName; + CHAR8 *OutputFileName; + UINT32 LineNumber; + Buffer[_MAX_PATH]; + + ArgumentsFlag = FALSE; + InputFlag = FALSE; + OutputFlag = FALSE; + GuidFlag = FALSE; + AttributesFlag = FALSE; + // + // Start at 1, since ToolArgumentsArray[0] + // is the program name. + // + argc = 1; + Index2 = 0; + + z = 0; + ReturnValue = 0; + NumberOfAttributes = 0; + InputFileName = NULL; + OutputFileName = NULL; + + ZeroMem (Buffer, _MAX_PATH); + ZeroMem (AttributesArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE); + LineNumber = 0; + while (Buffer[0] != ')') { + + if (GetNextLine (Buffer, Package, &LineNumber) != -1) { + CheckSlash (Buffer, Package, &LineNumber); + StripEqualMark (Buffer); + } else { + Error (NULL, 0, 0, "failed to get next line from package file", NULL); + return -1; + } + + if (Buffer[0] == ')') { + break; + } else if (strcmpi (Buffer, "ARGS") == 0) { + + ArgumentsFlag = TRUE; + AttributesFlag = FALSE; + continue; + + } else if (strcmpi (Buffer, "INPUT") == 0) { + + InputFlag = TRUE; + ArgumentsFlag = FALSE; + AttributesFlag = FALSE; + continue; + + } else if (strcmpi (Buffer, "OUTPUT") == 0) { + + OutputFlag = TRUE; + ArgumentsFlag = FALSE; + AttributesFlag = FALSE; + continue; + + } else if (strcmpi (Buffer, "GUID") == 0) { + + GuidFlag = TRUE; + ArgumentsFlag = FALSE; + AttributesFlag = FALSE; + // + // fetch the GUID for the section + // + continue; + + } else if (strcmpi (Buffer, "ATTRIBUTES") == 0) { + + AttributesFlag = TRUE; + ArgumentsFlag = FALSE; + // + // fetch the GUIDed Section's Attributes + // + continue; + + } else if (strcmpi (Buffer, "") == 0) { + continue; + } + // + // get all command arguments into ToolArgumentsArray + // + if (ArgumentsFlag) { + + StripEqualMark (Buffer); + + CharBuffer = (CHAR8 *) malloc (_MAX_PATH); + if (CharBuffer == NULL) { + goto ErrorExit; + } + + ZeroMem (CharBuffer, sizeof (_MAX_PATH)); + + ToolArgumentsArray[argc] = CharBuffer; + + if (Buffer[0] == '$') { + Index = ProcessEnvironmentVariable (&Buffer[0], ToolArgumentsArray[argc]); + // + // if there is string after the environment variable, cat it. + // + if ((UINT32) Index < strlen (Buffer)) { + strcat (ToolArgumentsArray[argc], &Buffer[Index]); + } + } else { + strcpy (ToolArgumentsArray[argc], Buffer); + } + + argc += 1; + ToolArgumentsArray[argc] = NULL; + continue; + } + + if (InputFlag) { + + StripEqualMark (Buffer); + + InputFileName = (CHAR8 *) malloc (_MAX_PATH); + if (InputFileName == NULL) { + goto ErrorExit; + } + + ZeroMem (InputFileName, sizeof (_MAX_PATH)); + + if (Buffer[0] == '$') { + Index = ProcessEnvironmentVariable (&Buffer[0], InputFileName); + // + // if there is string after the environment variable, cat it. + // + if ((UINT32) Index < strlen (Buffer)) { + strcat (InputFileName, &Buffer[Index]); + } + } else { + strcpy (InputFileName, Buffer); + } + + InputFlag = FALSE; + continue; + } + + if (OutputFlag) { + + StripEqualMark (Buffer); + + OutputFileName = (CHAR8 *) malloc (_MAX_PATH); + if (OutputFileName == NULL) { + goto ErrorExit; + } + + ZeroMem (OutputFileName, sizeof (_MAX_PATH)); + + if (Buffer[0] == '$') { + Index = ProcessEnvironmentVariable (&Buffer[0], OutputFileName); + // + // if there is string after the environment variable, cat it. + // + if ((UINT32) Index < strlen (Buffer)) { + strcat (OutputFileName, &Buffer[Index]); + } + } else { + strcpy (OutputFileName, Buffer); + } + + OutputFlag = FALSE; + continue; + } + + if (GuidFlag) { + + StripEqualMark (Buffer); + + Status = StringToGuid (Buffer, Guid); + if (EFI_ERROR (Status)) { + ReturnValue = -1; + goto ErrorExit; + } + + GuidFlag = FALSE; + } + + if (AttributesFlag) { + + StripEqualMark (Buffer); + + // + // there might be no space between each attribute in the statement, + // split them aside and return each attribute string + // in the AttributesArray + // + SplitAttributesField (Buffer, AttributesArray, &NumberOfAttributes); + } + } + // + // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"INPUT",InputVariable,j); + // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"OUTPUT",&TargetFileName,1); + // + for (z = 0; z < NumberOfAttributes; z++) { + if (strcmpi (AttributesArray[z], "PROCESSING_REQUIRED") == 0) { + *GuidedSectionAttributes |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED; + } else if (strcmpi (AttributesArray[z], "AUTH_STATUS_VALID") == 0) { + *GuidedSectionAttributes |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID; + } + } + +ErrorExit: + + for (Index2 = 0; Index2 < MAX_ARRAY_SIZE; Index2++) { + if (AttributesArray[Index2] == NULL) { + break; + } + + free (AttributesArray[Index2]); + } + + *PtrInputFileName = InputFileName; + *PtrOutputFileName = OutputFileName; + + return ReturnValue; +} + +static +INT32 +ProcessScript ( + IN OUT UINT8 *FileBuffer, + IN FILE *Package, + IN CHAR8 *BuildDirectory, + IN BOOLEAN ForceUncompress + ) +/*++ + +Routine Description: + + Signs the section, data stays in same location + +Arguments: + + FileBuffer - Data Buffer + + Package - Points to curly brace in Image Script + + BuildDirectory - Name of the source directory parameter + + ForceUncompress - Whether to force uncompress. + +Returns: + + Number of bytes added to file buffer + -1 on error + +--*/ +{ + EFI_STATUS Status; + UINT32 Size; + CHAR8 Buffer[_MAX_PATH]; + CHAR8 Type[_MAX_PATH]; + CHAR8 FileName[_MAX_PATH]; + CHAR8 NewBuffer[_MAX_PATH]; + INT32 Index3; + INT32 Index2; + UINT32 ReturnValue; + UINT8 ByteBuffer; + FILE *InFile; + UINT32 SourceDataSize; + CHAR8 *ToolArgumentsArray[MAX_ARRAY_SIZE]; + CHAR8 *OutputFileName; + CHAR8 *InputFileName; + CHAR8 ToolName[_MAX_PATH]; + FILE *OutputFile; + FILE *InputFile; + UINT8 Temp; + int returnint; + INT32 Index; + UINT32 LineNumber; + BOOLEAN IsError; + EFI_GUID SignGuid; + UINT16 GuidedSectionAttributes; + UINT8 *TargetFileBuffer; + + OutputFileName = NULL; + InputFileName = NULL; + OutputFile = NULL; + InputFile = NULL; + IsError = FALSE; + GuidedSectionAttributes = 0; + TargetFileBuffer = NULL; + + Size = 0; + LineNumber = 0; + Buffer[0] = 0; + for (Index3 = 0; Index3 < MAX_ARRAY_SIZE; ++Index3) { + ToolArgumentsArray[Index3] = NULL; + } + + while (Buffer[0] != '}') { + if (GetNextLine (Buffer, Package, &LineNumber) != -1) { + CheckSlash (Buffer, Package, &LineNumber); + } else { + printf ("ERROR in IMAGE SCRIPT!\n"); + IsError = TRUE; + goto Done; + } + + if (strcmpi (Buffer, "Compress") == 0) { + // + // Handle compress + // + // + // read compression type + // + if (GetNextLine (Buffer, Package, &LineNumber) != -1) { + CheckSlash (Buffer, Package, &LineNumber); + } + + StripParens (Buffer); + if (Buffer[0] == '$') { + ProcessEnvironmentVariable (&Buffer[0], Type); + } else { + strcpy (Type, Buffer); + } + // + // build buffer + // + while (Buffer[0] != '{') { + if (GetNextLine (Buffer, Package, &LineNumber) != -1) { + CheckSlash (Buffer, Package, &LineNumber); + } + } + + ReturnValue = ProcessScript (&FileBuffer[Size], Package, BuildDirectory, ForceUncompress); + if (ReturnValue == -1) { + IsError = TRUE; + goto Done; + } + // + // Call compress routine on buffer. + // Occasionally, compressed data + section header would + // be largere than the source and EFI_BUFFER_TOO_SMALL is + // returned from CompressSection() + // + SourceDataSize = ReturnValue; + + if (!ForceUncompress) { + + Status = CompressSection ( + &FileBuffer[Size], + &ReturnValue, + SourceDataSize, + Type + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = CompressSection ( + &FileBuffer[Size], + &ReturnValue, + SourceDataSize, + Type + ); + } + + if (EFI_ERROR (Status)) { + IsError = TRUE; + goto Done; + } + } + + Size += ReturnValue; + + } else if (strcmpi (Buffer, "Tool") == 0) { + + ZeroMem (ToolName, _MAX_PATH); + ZeroMem (ToolArgumentsArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE); + ZeroMem (&SignGuid, sizeof (EFI_GUID)); + + // + // handle signing Tool + // + while (Buffer[0] != '(') { + if (GetNextLine (Buffer, Package, &LineNumber) != -1) { + CheckSlash (Buffer, Package, &LineNumber); + } + } + + if (strcmpi (Buffer, "(") == 0) { + if (GetNextLine (Buffer, Package, &LineNumber) != -1) { + CheckSlash (Buffer, Package, &LineNumber); + } + } + + StripParens (Buffer); + + if (Buffer[0] == '$') { + Index = ProcessEnvironmentVariable (&Buffer[0], ToolName); + // + // if there is string after the environment variable, cat it. + // + if ((UINT32) Index < strlen (Buffer)) { + strcat (ToolName, &Buffer[Index]); + } + } else { + strcpy (ToolName, Buffer); + } + + ToolArgumentsArray[0] = ToolName; + + // + // read ARGS + // + if (GetToolArguments ( + ToolArgumentsArray, + Package, + &InputFileName, + &OutputFileName, + &SignGuid, + &GuidedSectionAttributes + ) == -1) { + IsError = TRUE; + goto Done; + } + // + // if the tool need input file, + // dump the file buffer to the specified input file. + // + if (InputFileName != NULL) { + InputFile = fopen (InputFileName, "wb"); + if (InputFile == NULL) { + Error (NULL, 0, 0, InputFileName, "failed to open output file for writing"); + IsError = TRUE; + goto Done; + } + + fwrite (FileBuffer, sizeof (UINT8), Size, InputFile); + fclose (InputFile); + InputFile = NULL; + free (InputFileName); + InputFileName = NULL; + } + // + // dispatch signing tool + // +#ifdef __GNUC__ + { + char CommandLine[1000]; + sprintf(CommandLine, "%s %s", ToolName, ToolArgumentsArray); + returnint = system(CommandLine); + } +#else + returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray); +#endif + if (returnint != 0) { + Error (NULL, 0, 0, ToolName, "external tool failed"); + IsError = TRUE; + goto Done; + } + // + // if the tool has output file, + // dump the output file to the file buffer + // + if (OutputFileName != NULL) { + + OutputFile = fopen (OutputFileName, "rb"); + if (OutputFile == NULL) { + Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); + IsError = TRUE; + goto Done; + } + + TargetFileBuffer = &FileBuffer[Size]; + SourceDataSize = Size; + + fread (&Temp, sizeof (UINT8), 1, OutputFile); + while (!feof (OutputFile)) { + FileBuffer[Size++] = Temp; + fread (&Temp, sizeof (UINT8), 1, OutputFile); + } + + while ((Size & 0x03) != 0) { + FileBuffer[Size] = 0; + Size++; + } + + SourceDataSize = Size - SourceDataSize; + + fclose (OutputFile); + OutputFile = NULL; + free (OutputFileName); + OutputFileName = NULL; + + if (CompareGuid (&SignGuid, &mZeroGuid) != 0) { + ReturnValue = SourceDataSize; + Status = GenSimpleGuidSection ( + TargetFileBuffer, + &ReturnValue, + SourceDataSize, + SignGuid, + GuidedSectionAttributes + ); + if (EFI_ERROR (Status)) { + IsError = TRUE; + goto Done; + } + + Size = ReturnValue; + } + } + + } else if (Buffer[0] != '}') { + // + // if we are here, we should see either a file name, + // or a }. + // + Index3 = 0; + FileName[0] = 0; + // + // Prepend the build directory to the file name if the + // file name does not already contain a full path. + // + if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) { + sprintf (FileName, "%s\\", BuildDirectory); + } + + while (Buffer[Index3] != '\n') { + if (Buffer[Index3] == '$') { + Index3 += ProcessEnvironmentVariable (&Buffer[Index3], NewBuffer); + strcat (FileName, NewBuffer); + } + + if (Buffer[Index3] == 0) { + break; + } else { + Index2 = strlen (FileName); + FileName[Index2++] = Buffer[Index3++]; + FileName[Index2] = 0; + } + } + + InFile = fopen (FileName, "rb"); + if (InFile == NULL) { + Error (NULL, 0, 0, FileName, "failed to open file for reading"); + IsError = TRUE; + goto Done; + } + + fread (&ByteBuffer, sizeof (UINT8), 1, InFile); + while (!feof (InFile)) { + FileBuffer[Size++] = ByteBuffer; + fread (&ByteBuffer, sizeof (UINT8), 1, InFile); + } + + fclose (InFile); + InFile = NULL; + + // + // Make sure section ends on a DWORD boundary + // + while ((Size & 0x03) != 0) { + FileBuffer[Size] = 0; + Size++; + } + + } + } + +Done: + for (Index3 = 1; Index3 < MAX_ARRAY_SIZE; Index3++) { + if (ToolArgumentsArray[Index3] == NULL) { + break; + } + + free (ToolArgumentsArray[Index3]); + } + + if (IsError) { + return -1; + } + + return Size; + +} + +static +UINT8 +StringToType ( + IN CHAR8 *String + ) +/*++ + +Routine Description: + + Converts File Type String to value. EFI_FV_FILETYPE_ALL indicates that an + unrecognized file type was specified. + +Arguments: + + String - File type string + +Returns: + + File Type Value + +--*/ +{ + if (strcmpi (String, "EFI_FV_FILETYPE_RAW") == 0) { + return EFI_FV_FILETYPE_RAW; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_FREEFORM") == 0) { + return EFI_FV_FILETYPE_FREEFORM; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_SECURITY_CORE") == 0) { + return EFI_FV_FILETYPE_SECURITY_CORE; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_PEI_CORE") == 0) { + return EFI_FV_FILETYPE_PEI_CORE; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_DXE_CORE") == 0) { + return EFI_FV_FILETYPE_DXE_CORE; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_PEIM") == 0) { + return EFI_FV_FILETYPE_PEIM; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_DRIVER") == 0) { + return EFI_FV_FILETYPE_DRIVER; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER") == 0) { + return EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_APPLICATION") == 0) { + return EFI_FV_FILETYPE_APPLICATION; + } + + if (strcmpi (String, "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE") == 0) { + return EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE; + } + + return EFI_FV_FILETYPE_ALL; +} + +static +UINT32 +AdjustFileSize ( + IN UINT8 *FileBuffer, + IN UINT32 FileSize + ) +/*++ + +Routine Description: + Adjusts file size to insure sectioned file is exactly the right length such + that it ends on exactly the last byte of the last section. ProcessScript() + may have padded beyond the end of the last section out to a 4 byte boundary. + This padding is stripped. + +Arguments: + FileBuffer - Data Buffer - contains a section stream + FileSize - Size of FileBuffer as returned from ProcessScript() + +Returns: + Corrected size of file. + +--*/ +{ + UINT32 TotalLength; + UINT32 CurrentLength; + UINT32 SectionLength; + UINT32 SectionStreamLength; + EFI_COMMON_SECTION_HEADER *SectionHeader; + EFI_COMMON_SECTION_HEADER *NextSectionHeader; + + TotalLength = 0; + CurrentLength = 0; + SectionStreamLength = FileSize; + + SectionHeader = (EFI_COMMON_SECTION_HEADER *) FileBuffer; + + while (TotalLength < SectionStreamLength) { + SectionLength = *((UINT32 *) SectionHeader->Size) & 0x00ffffff; + TotalLength += SectionLength; + + if (TotalLength == SectionStreamLength) { + return TotalLength; + } + // + // Move to the next byte following the section... + // + SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength); + CurrentLength = (UINTN) SectionHeader - (UINTN) FileBuffer; + + // + // Figure out where the next section begins + // + NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + 3); + NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader &~ (UINTN) 3); + TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader; + SectionHeader = NextSectionHeader; + } + + return CurrentLength; +} + +static +INT32 +MainEntry ( + INT32 argc, + CHAR8 *argv[], + BOOLEAN ForceUncompress + ) +/*++ + +Routine Description: + + MainEntry function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to command line parameter strings. + ForceUncompress - If TRUE, force to do not compress the sections even if compression + is specified in the script. Otherwise, FALSE. + +Returns: + STATUS_SUCCESS - Function exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + FILE *PrimaryPackage; + FILE *OverridePackage; + FILE *Out; + CHAR8 BaseName[_MAX_PATH]; + EFI_GUID FfsGuid; + CHAR8 GuidString[_MAX_PATH]; + EFI_FFS_FILE_HEADER FileHeader; + CHAR8 FileType[_MAX_PATH]; + EFI_FFS_FILE_ATTRIBUTES FfsAttrib; + EFI_FFS_FILE_ATTRIBUTES FfsAttribDefined; + UINT64 FfsAlignment; + UINT32 FfsAlignment32; + CHAR8 InputString[_MAX_PATH]; + BOOLEAN ImageScriptInOveride; + UINT32 FileSize; + UINT8 *FileBuffer; + EFI_STATUS Status; + UINT32 LineNumber; + EFI_FFS_FILE_TAIL TailValue; + + BaseName[0] = 0; + FileType[0] = 0; + FfsAttrib = 0; + FfsAttribDefined = 0; + FfsAlignment = 0; + FfsAlignment32 = 0; + PrimaryPackage = NULL; + Out = NULL; + OverridePackage = NULL; + FileBuffer = NULL; + + strcpy (GuidString, "00000000-0000-0000-0000-000000000000"); + Status = StringToGuid (GuidString, &FfsGuid); + if (Status != 0) { + Error (NULL, 0, 0, GuidString, "error parsing GUID string"); + return STATUS_ERROR; + } + + GuidString[0] = 0; + ImageScriptInOveride = FALSE; + // + // Initialize the simple file parsing routines. Then open + // the primary package file for parsing. + // + SFPInit (); + if (SFPOpenFile (mGlobals.PrimaryPackagePath) != STATUS_SUCCESS) { + Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file"); + goto Done; + } + // + // First token in the file must be "PACKAGE.INF" + // + if (!SFPIsToken ("PACKAGE.INF")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'PACKAGE.INF'", NULL); + goto Done; + } + // + // Find the [.] section + // + if (!SFPSkipToToken ("[.]")) { + Error (mGlobals.PrimaryPackagePath, 1, 0, "could not locate [.] section in package file", NULL); + goto Done; + } + // + // Start parsing the data. The algorithm is essentially the same for each keyword: + // 1. Identify the keyword + // 2. Verify that the keyword/value pair has not already been defined + // 3. Set some flag indicating that the keyword/value pair has been defined + // 4. Skip over the "=" + // 5. Get the value, which may be a number, TRUE, FALSE, or a string. + // + while (1) { + if (SFPIsToken ("BASE_NAME")) { + // + // Found BASE_NAME, format: + // BASE_NAME = MyBaseName + // + if (BaseName[0] != 0) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "BASE_NAME already defined", NULL); + goto Done; + } + + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (!SFPGetNextToken (BaseName, sizeof (BaseName))) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid base name", NULL); + goto Done; + } + } else if (SFPIsToken ("IMAGE_SCRIPT")) { + // + // Found IMAGE_SCRIPT. Break out and process below. + // + break; + } else if (SFPIsToken ("FFS_FILEGUID")) { + // + // found FILEGUID, format: + // FFS_FILEGUID = F7845C4F-EDF5-42C5-BD8F-A02AF63DD93A + // + if (GuidString[0] != 0) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILEGUID already defined", NULL); + goto Done; + } + + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (SFPGetGuidToken (GuidString, sizeof (GuidString)) != TRUE) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected file GUID", NULL); + goto Done; + } + + Status = StringToGuid (GuidString, &FfsGuid); + if (Status != 0) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid file GUID", NULL); + goto Done; + } + } else if (SFPIsToken ("FFS_FILETYPE")) { + // + // *********************************************************************** + // + // Found FFS_FILETYPE, format: + // FFS_FILETYPE = EFI_FV_FILETYPE_APPLICATION + // + if (FileType[0] != 0) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILETYPE previously defined", NULL); + goto Done; + } + + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (!SFPGetNextToken (FileType, sizeof (FileType))) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid FFS_FILETYPE", NULL); + goto Done; + } + } else if (SFPIsToken ("FFS_ATTRIB_HEADER_EXTENSION")) { + // + // *********************************************************************** + // + // Found: FFS_ATTRIB_HEADER_EXTENSION = FALSE + // Spec says the bit is for future expansion, and must be false. + // + if (FfsAttribDefined & FFS_ATTRIB_HEADER_EXTENSION) { + Error ( + mGlobals.PrimaryPackagePath, + SFPGetLineNumber (), + 0, + "FFS_ATTRIB_HEADER_EXTENSION previously defined", + NULL + ); + goto Done; + } + + FfsAttribDefined |= FFS_ATTRIB_HEADER_EXTENSION; + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (SFPIsToken ("TRUE")) { + Error ( + mGlobals.PrimaryPackagePath, + SFPGetLineNumber (), + 0, + "only FFS_ATTRIB_HEADER_EXTENSION = FALSE is supported", + NULL + ); + goto Done; + } else if (SFPIsToken ("FALSE")) { + // + // Default is FALSE + // + } else { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'FALSE'", NULL); + goto Done; + } + } else if (SFPIsToken ("FFS_ATTRIB_TAIL_PRESENT")) { + // + // *********************************************************************** + // + // Found: FFS_ATTRIB_TAIL_PRESENT = TRUE | FALSE + // + if (FfsAttribDefined & FFS_ATTRIB_TAIL_PRESENT) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_TAIL_PRESENT previously defined", NULL); + goto Done; + } + + FfsAttribDefined |= FFS_ATTRIB_TAIL_PRESENT; + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (SFPIsToken ("TRUE")) { + FfsAttrib |= FFS_ATTRIB_TAIL_PRESENT; + } else if (SFPIsToken ("FALSE")) { + // + // Default is FALSE + // + } else { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); + goto Done; + } + } else if (SFPIsToken ("FFS_ATTRIB_RECOVERY")) { + // + // *********************************************************************** + // + // Found: FFS_ATTRIB_RECOVERY = TRUE | FALSE + // + if (FfsAttribDefined & FFS_ATTRIB_RECOVERY) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_RECOVERY previously defined", NULL); + goto Done; + } + + FfsAttribDefined |= FFS_ATTRIB_RECOVERY; + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (SFPIsToken ("TRUE")) { + FfsAttrib |= FFS_ATTRIB_RECOVERY; + } else if (SFPIsToken ("FALSE")) { + // + // Default is FALSE + // + } else { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); + goto Done; + } + } else if (SFPIsToken ("FFS_ATTRIB_CHECKSUM")) { + // + // *********************************************************************** + // + // Found: FFS_ATTRIB_CHECKSUM = TRUE | FALSE + // + if (FfsAttribDefined & FFS_ATTRIB_CHECKSUM) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_CHECKSUM previously defined", NULL); + goto Done; + } + + FfsAttribDefined |= FFS_ATTRIB_CHECKSUM; + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (SFPIsToken ("TRUE")) { + FfsAttrib |= FFS_ATTRIB_CHECKSUM; + } else if (SFPIsToken ("FALSE")) { + // + // Default is FALSE + // + } else { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); + goto Done; + } + } else if (SFPIsToken ("FFS_ALIGNMENT") || SFPIsToken ("FFS_ATTRIB_DATA_ALIGNMENT")) { + // + // *********************************************************************** + // + // Found FFS_ALIGNMENT, formats: + // FFS_ALIGNMENT = 0-7 + // FFS_ATTRIB_DATA_ALIGNMENT = 0-7 + // + if (FfsAttribDefined & FFS_ATTRIB_DATA_ALIGNMENT) { + Error ( + mGlobals.PrimaryPackagePath, + SFPGetLineNumber (), + 0, + "FFS_ALIGNMENT/FFS_ATTRIB_DATA_ALIGNMENT previously defined", + NULL + ); + goto Done; + } + + FfsAttribDefined |= FFS_ATTRIB_DATA_ALIGNMENT; + if (!SFPIsToken ("=")) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); + goto Done; + } + + if (!SFPGetNumber (&FfsAlignment32)) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected numeric value for alignment", NULL); + goto Done; + } + + if (FfsAlignment32 > 7) { + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 0 <= alignment <= 7", NULL); + goto Done; + } + + FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment32) << 3); + } else { + SFPGetNextToken (InputString, sizeof (InputString)); + Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, InputString, "unrecognized/unexpected token"); + goto Done; + } + } + // + // Close the primary package file + // + SFPCloseFile (); + // + // TODO: replace code below with basically a copy of the code above. Don't + // forget to reset the FfsAttribDefined variable first. Also, you'll need + // to somehow keep track of whether or not the basename is defined multiple + // times in the override package. Ditto on the file GUID. + // + if (mGlobals.OverridePackagePath[0] != 0) { + OverridePackage = fopen (mGlobals.OverridePackagePath, "r"); + // + // NOTE: For package override to work correctly, the code below must be modified to + // SET or CLEAR bits properly. For example, if the primary package set + // FFS_ATTRIB_CHECKSUM = TRUE, and the override set FFS_ATTRIB_CHECKSUM = FALSE, then + // we'd need to clear the bit below. Since this is not happening, I'm guessing that + // the override functionality is not being used, so should be made obsolete. If I'm + // wrong, and it is being used, then it needs to be fixed. Thus emit an error if it is + // used, and we'll address it then. 4/10/2003 + // + Error (__FILE__, __LINE__, 0, "package override functionality is not implemented correctly", NULL); + goto Done; + } else { + OverridePackage = NULL; + } + +#ifdef OVERRIDE_SUPPORTED + if (OverridePackage != NULL) { + // + // Parse override package file + // + fscanf (OverridePackage, "%s", &InputString); + if (strcmpi (InputString, "PACKAGE.INF") != 0) { + Error (mGlobals.OverridePackagePath, 1, 0, "invalid package file", "expected 'PACKAGE.INF'"); + goto Done; + } + // + // Match [dir] to Build Directory + // + if (FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber) != 0) { + Error (mGlobals.OverridePackagePath, 1, 0, mGlobals.BuildDirectory, "section not found in package file"); + goto Done; + } + + InputString[0] = 0; + while ((InputString[0] != '[') && (!feof (OverridePackage))) { + if (GetNextLine (InputString, OverridePackage, &LineNumber) != -1) { + if (InputString[0] != '[') { +here: + if (strcmpi (InputString, "BASE_NAME") == 0) { + // + // found BASE_NAME, next is = and string. + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strlen (InputString) == 1) { + // + // string is just = + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + strcpy (BaseName, InputString); + } else { + BreakString (InputString, InputString, 1); + strcpy (BaseName, InputString); + } + } else if (strcmpi (InputString, "IMAGE_SCRIPT") == 0) { + // + // found IMAGE_SCRIPT, come back later to process it + // + ImageScriptInOveride = TRUE; + fscanf (OverridePackage, "%s", &InputString); + } else if (strcmpi (InputString, "FFS_FILEGUID") == 0) { + // + // found FILEGUID, next is = and string. + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strlen (InputString) == 1) { + // + // string is just = + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + Status = StringToGuid (InputString, &FfsGuid); + if (Status != 0) { + Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format"); + goto Done; + } + } else { + BreakString (InputString, InputString, 1); + Status = StringToGuid (InputString, &FfsGuid); + if (Status != 0) { + Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format"); + goto Done; + } + } + } else if (strcmpi (InputString, "FFS_FILETYPE") == 0) { + // + // found FILETYPE, next is = and string. + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strlen (InputString) == 1) { + // + // string is just = + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + strcpy (FileType, InputString); + } else { + BreakString (InputString, InputString, 1); + strcpy (FileType, InputString); + } + + } else if (strcmpi (InputString, "FFS_ATTRIB_RECOVERY") == 0) { + // + // found FFS_ATTRIB_RECOVERY, next is = and string. + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strlen (InputString) == 1) { + // + // string is just = + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strcmpi (InputString, "TRUE") == 0) { + FfsAttrib |= FFS_ATTRIB_RECOVERY; + } + } else { + BreakString (InputString, InputString, 1); + if (strcmpi (InputString, "TRUE") == 0) { + FfsAttrib |= FFS_ATTRIB_RECOVERY; + } + } + } else if (strcmpi (InputString, "FFS_ATTRIB_CHECKSUM") == 0) { + // + // found FFS_ATTRIB_CHECKSUM, next is = and string. + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strlen (InputString) == 1) { + // + // string is just = + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strcmpi (InputString, "TRUE") == 0) { + FfsAttrib |= FFS_ATTRIB_CHECKSUM; + } + } else { + BreakString (InputString, InputString, 1); + if (strcmpi (InputString, "TRUE") == 0) { + FfsAttrib |= FFS_ATTRIB_CHECKSUM; + } + } + } else if (strcmpi (InputString, "FFS_ALIGNMENT") == 0) { + // + // found FFS_ALIGNMENT, next is = and string. + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strlen (InputString) == 1) { + // + // string is just = + // + fscanf (OverridePackage, "%s", &InputString); + CheckSlash (InputString, OverridePackage, &LineNumber); + } else { + BreakString (InputString, InputString, 1); + } + + AsciiStringToUint64 (InputString, FALSE, &FfsAlignment); + if (FfsAlignment > 7) { + Error (mGlobals.OverridePackagePath, 1, 0, InputString, "invalid FFS_ALIGNMENT value"); + goto Done; + } + + FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment) << 3); + } else if (strchr (InputString, '=') != NULL) { + BreakString (InputString, String, 1); + fseek (OverridePackage, (-1 * (strlen (String) + 1)), SEEK_CUR); + BreakString (InputString, InputString, 0); + goto here; + } + } + } + } + } +#endif // #ifdef OVERRIDE_SUPPORTED + // + // Require that they specified a file GUID at least, since that's how we're + // naming the file. + // + if (GuidString[0] == 0) { + Error (mGlobals.PrimaryPackagePath, 1, 0, "FFS_FILEGUID must be specified", NULL); + return STATUS_ERROR; + } + // + // Build Header and process image script + // + FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 16) * sizeof (UINT8)); + if (FileBuffer == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL); + goto Done; + } + + FileSize = 0; + if (ImageScriptInOveride) { +#ifdef OVERRIDE_SUPORTED + rewind (OverridePackage); + LineNumber = 0; + FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber); + while (strcmpi (InputString, "IMAGE_SCRIPT") != 0) { + GetNextLine (InputString, OverridePackage, &LineNumber); + CheckSlash (InputString, OverridePackage, &LineNumber); + if (strchr (InputString, '=') != NULL) { + BreakString (InputString, InputString, 0); + } + } + + while (InputString[0] != '{') { + GetNextLine (InputString, OverridePackage, &LineNumber); + CheckSlash (InputString, OverridePackage, &LineNumber); + } + // + // Found start of image script, process it + // + FileSize += ProcessScript (FileBuffer, OverridePackage, mGlobals.BuildDirectory, ForceUncompress); + if (FileSize == -1) { + return -1; + } + + if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) { + FileSize = AdjustFileSize (FileBuffer, FileSize); + } + + if (BaseName[0] == '\"') { + StripQuotes (BaseName); + } + + if (BaseName[0] != 0) { + sprintf (InputString, "%s-%s", GuidString, BaseName); + } else { + strcpy (InputString, GuidString); + } + + switch (StringToType (FileType)) { + + case EFI_FV_FILETYPE_SECURITY_CORE: + strcat (InputString, ".SEC"); + break; + + case EFI_FV_FILETYPE_PEIM: + case EFI_FV_FILETYPE_PEI_CORE: + case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: + strcat (InputString, ".PEI"); + break; + + case EFI_FV_FILETYPE_DRIVER: + case EFI_FV_FILETYPE_DXE_CORE: + strcat (InputString, ".DXE"); + break; + + case EFI_FV_FILETYPE_APPLICATION: + strcat (InputString, ".APP"); + break; + + case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: + strcat (InputString, ".FVI"); + break; + + case EFI_FV_FILETYPE_ALL: + Error (mGlobals.OverridePackagePath, 1, 0, "invalid FFS file type for this utility", NULL); + goto Done; + + default: + strcat (InputString, ".FFS"); + break; + } + + if (ForceUncompress) { + strcat (InputString, ".ORG"); + } + + Out = fopen (InputString, "wb"); + if (Out == NULL) { + Error (NULL, 0, 0, InputString, "could not open output file for writing"); + goto Done; + } + // + // create ffs header + // + memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER)); + memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID)); + FileHeader.Type = StringToType (FileType); + FileHeader.Attributes = FfsAttrib; + // + // Now FileSize includes the EFI_FFS_FILE_HEADER + // + FileSize += sizeof (EFI_FFS_FILE_HEADER); + FileHeader.Size[0] = (UINT8) (FileSize & 0xFF); + FileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8); + FileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16); + // + // Fill in checksums and state, these must be zero for checksumming + // + // FileHeader.IntegrityCheck.Checksum.Header = 0; + // FileHeader.IntegrityCheck.Checksum.File = 0; + // FileHeader.State = 0; + // + FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 ( + (UINT8 *) &FileHeader, + sizeof (EFI_FFS_FILE_HEADER) + ); + if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) { + FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize); + } else { + FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; + // + // write header + // + if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) { + Error (NULL, 0, 0, "failed to write file header to output file", NULL); + goto Done; + } + // + // write data + // + if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) { + Error (NULL, 0, 0, "failed to write all bytes to output file", NULL); + goto Done; + } + + fclose (Out); + Out = NULL; +#endif // #ifdef OVERRIDE_SUPPORTED + } else { + // + // Open primary package file and process the IMAGE_SCRIPT section + // + PrimaryPackage = fopen (mGlobals.PrimaryPackagePath, "r"); + if (PrimaryPackage == NULL) { + Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file"); + goto Done; + } + + LineNumber = 1; + FindSectionInPackage (".", PrimaryPackage, &LineNumber); + while (strcmpi (InputString, "IMAGE_SCRIPT") != 0) { + GetNextLine (InputString, PrimaryPackage, &LineNumber); + CheckSlash (InputString, PrimaryPackage, &LineNumber); + if (strchr (InputString, '=') != NULL) { + BreakString (InputString, InputString, 0); + } + } + + while (InputString[0] != '{') { + GetNextLine (InputString, PrimaryPackage, &LineNumber); + CheckSlash (InputString, PrimaryPackage, &LineNumber); + } + // + // Found start of image script, process it + // + FileSize += ProcessScript (FileBuffer, PrimaryPackage, mGlobals.BuildDirectory, ForceUncompress); + if (FileSize == -1) { + goto Done; + } + + if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) { + FileSize = AdjustFileSize (FileBuffer, FileSize); + } + + if (BaseName[0] == '\"') { + StripQuotes (BaseName); + } + + if (BaseName[0] != 0) { + sprintf (InputString, "%s-%s", GuidString, BaseName); + } else { + strcpy (InputString, GuidString); + } + + switch (StringToType (FileType)) { + + case EFI_FV_FILETYPE_SECURITY_CORE: + strcat (InputString, ".SEC"); + break; + + case EFI_FV_FILETYPE_PEIM: + case EFI_FV_FILETYPE_PEI_CORE: + case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: + strcat (InputString, ".PEI"); + break; + + case EFI_FV_FILETYPE_DRIVER: + case EFI_FV_FILETYPE_DXE_CORE: + strcat (InputString, ".DXE"); + break; + + case EFI_FV_FILETYPE_APPLICATION: + strcat (InputString, ".APP"); + break; + + case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: + strcat (InputString, ".FVI"); + break; + + case EFI_FV_FILETYPE_ALL: + Error (mGlobals.PrimaryPackagePath, 1, 0, "invalid FFS file type for this utility", NULL); + goto Done; + + default: + strcat (InputString, ".FFS"); + break; + } + + if (ForceUncompress) { + strcat (InputString, ".ORG"); + } + + Out = fopen (InputString, "wb"); + if (Out == NULL) { + Error (NULL, 0, 0, InputString, "failed to open output file for writing"); + goto Done; + } + // + // Initialize the FFS file header + // + memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER)); + memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID)); + FileHeader.Type = StringToType (FileType); + FileHeader.Attributes = FfsAttrib; + // + // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER + // + FileSize += sizeof (EFI_FFS_FILE_HEADER); + // + // If using a tail, then it adds two bytes + // + if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) { + // + // Tail is not allowed for pad and 0-length files + // + if ((FileHeader.Type == EFI_FV_FILETYPE_FFS_PAD) || (FileSize == sizeof (EFI_FFS_FILE_HEADER))) { + Error ( + mGlobals.PrimaryPackagePath, + 1, + 0, + "FFS_ATTRIB_TAIL_PRESENT=TRUE is invalid for PAD or 0-length files", + NULL + ); + goto Done; + } + + FileSize += sizeof (EFI_FFS_FILE_TAIL); + } + + FileHeader.Size[0] = (UINT8) (FileSize & 0xFF); + FileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8); + FileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16); + // + // Fill in checksums and state, they must be 0 for checksumming. + // + // FileHeader.IntegrityCheck.Checksum.Header = 0; + // FileHeader.IntegrityCheck.Checksum.File = 0; + // FileHeader.State = 0; + // + FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 ( + (UINT8 *) &FileHeader, + sizeof (EFI_FFS_FILE_HEADER) + ); + if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Cheating here. Since the header checksums, just calculate the checksum of the body. + // Checksum does not include the tail + // + if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) { + FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ( + FileBuffer, + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL) + ); + } else { + FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ( + FileBuffer, + FileSize - sizeof (EFI_FFS_FILE_HEADER) + ); + } + } else { + FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + // + // Set the state now. Spec says the checksum assumes the state is 0 + // + FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; + // + // If there is a tail, then set it + // + if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) { + TailValue = FileHeader.IntegrityCheck.TailReference; + TailValue = (UINT16) (~TailValue); + memcpy ( + (UINT8 *) FileBuffer + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL), + &TailValue, + sizeof (TailValue) + ); + } + // + // Write the FFS file header + // + if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) { + Error (NULL, 0, 0, "failed to write file header contents", NULL); + goto Done; + } + // + // Write data + // + if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) { + Error (NULL, 0, 0, "failed to write file contents", NULL); + goto Done; + } + } + +Done: + SFPCloseFile (); + if (Out != NULL) { + fclose (Out); + } + + if (PrimaryPackage != NULL) { + fclose (PrimaryPackage); + } + + if (FileBuffer != NULL) { + free (FileBuffer); + } + + if (OverridePackage != NULL) { + fclose (OverridePackage); + } + + return GetUtilityStatus (); +} + +int +main ( + INT32 argc, + CHAR8 *argv[] + ) +/*++ + +Routine Description: + + Main function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + STATUS Status; + // + // Set the name of our utility for error reporting purposes. + // + SetUtilityName (UTILITY_NAME); + Status = ProcessCommandLineArgs (argc, argv); + if (Status != STATUS_SUCCESS) { + return Status; + } + + Status = MainEntry (argc, argv, TRUE); + if (Status == STATUS_SUCCESS) { + MainEntry (argc, argv, FALSE); + } + // + // If any errors were reported via the standard error reporting + // routines, then the status has been saved. Get the value and + // return it to the caller. + // + return GetUtilityStatus (); +} + +static +STATUS +ProcessCommandLineArgs ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + Process the command line arguments. + +Arguments: + Argc - as passed in to main() + Argv - as passed in to main() + +Returns: + STATUS_SUCCESS - arguments all ok + STATUS_ERROR - problem with args, so caller should exit + +--*/ +{ + // + // If no args, then print usage instructions and return an error + // + if (Argc == 1) { + PrintUsage (); + return STATUS_ERROR; + } + + memset (&mGlobals, 0, sizeof (mGlobals)); + Argc--; + Argv++; + while (Argc > 0) { + if (strcmpi (Argv[0], "-b") == 0) { + // + // OPTION: -b BuildDirectory + // Make sure there is another argument, then save it to our globals. + // + if (Argc < 2) { + Error (NULL, 0, 0, "-b option requires the build directory name", NULL); + return STATUS_ERROR; + } + + if (mGlobals.BuildDirectory[0]) { + Error (NULL, 0, 0, Argv[0], "option can only be specified once"); + return STATUS_ERROR; + } + + strcpy (mGlobals.BuildDirectory, Argv[1]); + Argc--; + Argv++; + } else if (strcmpi (Argv[0], "-p1") == 0) { + // + // OPTION: -p1 PrimaryPackageFile + // Make sure there is another argument, then save it to our globals. + // + if (Argc < 2) { + Error (NULL, 0, 0, Argv[0], "option requires the primary package file name"); + return STATUS_ERROR; + } + + if (mGlobals.PrimaryPackagePath[0]) { + Error (NULL, 0, 0, Argv[0], "option can only be specified once"); + return STATUS_ERROR; + } + + strcpy (mGlobals.PrimaryPackagePath, Argv[1]); + Argc--; + Argv++; + } else if (strcmpi (Argv[0], "-p2") == 0) { + // + // OPTION: -p2 OverridePackageFile + // Make sure there is another argument, then save it to our globals. + // + if (Argc < 2) { + Error (NULL, 0, 0, Argv[0], "option requires the override package file name"); + return STATUS_ERROR; + } + + if (mGlobals.OverridePackagePath[0]) { + Error (NULL, 0, 0, Argv[0], "option can only be specified once"); + return STATUS_ERROR; + } + + strcpy (mGlobals.OverridePackagePath, Argv[1]); + Argc--; + Argv++; + } else if (strcmpi (Argv[0], "-v") == 0) { + // + // OPTION: -v verbose + // + mGlobals.Verbose = TRUE; + } else if (strcmpi (Argv[0], "-h") == 0) { + // + // OPTION: -h help + // + PrintUsage (); + return STATUS_ERROR; + } else if (strcmpi (Argv[0], "-?") == 0) { + // + // OPTION: -? help + // + PrintUsage (); + return STATUS_ERROR; + } else { + Error (NULL, 0, 0, Argv[0], "unrecognized option"); + PrintUsage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } + // + // Must have at least specified the package file name + // + if (mGlobals.PrimaryPackagePath[0] == 0) { + Error (NULL, 0, 0, "must specify primary package file", NULL); + return STATUS_ERROR; + } + + return STATUS_SUCCESS; +} -- cgit v1.2.3