/*++ Copyright (c) 2004-2007, 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 "Compress.h" #include "EfiCustomizedCompress.h" #include "Crc32.h" #include "GenFfsFile.h" #include "CommonLib.h" #include "EfiUtilityMsgs.h" #include "SimpleFileParsing.h" #define UTILITY_NAME "GenFfsFile" #define UTILITY_MAJOR_VERSION 0 #define UTILITY_MINOR_VERSION 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 Version ( void ); static void Usage ( 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 Version( void ) /*++ Routine Description: Print out version information for this utility. Arguments: None Returns: None --*/ { printf ("%s v%d.%d -EDK utility to generate a Firmware File System files.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION); printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n"); } static void Usage ( void ) /*++ Routine Description: Print Error / Help message. Arguments: void Returns: None --*/ { Version(); printf ("\nUsage:\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) EfiCompress; } else if (strcmpi (Type, "LZH") == 0) { // // EFI stardard compression (LZH) // CompressionType = EFI_STANDARD_COMPRESSION; CompressFunction = (COMPRESS_FUNCTION) EfiCompress; } 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 // Argc--; Argv++; if (Argc < 1) { Usage (); return STATUS_ERROR; } if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) || (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) { Usage(); return STATUS_ERROR; } if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) { Version(); return STATUS_ERROR; } memset (&mGlobals, 0, sizeof (mGlobals)); 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 // Usage (); return STATUS_ERROR; } else if (strcmpi (Argv[0], "-?") == 0) { // // OPTION: -? help // Usage (); return STATUS_ERROR; } else { Error (NULL, 0, 0, Argv[0], "unrecognized option"); Usage (); 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; }