| /*++ | |
| 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 <stdio.h> | |
| #include <ctype.h> // for isalpha() | |
| // | |
| // include file for _spawnv | |
| // | |
| #ifndef __GNUC__ | |
| #include <process.h> | |
| #endif | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <Common/UefiBaseTypes.h> | |
| #include <Common/FirmwareVolumeImageFormat.h> | |
| #include <Common/FirmwareFileSystem.h> | |
| #include <Common/FirmwareVolumeHeader.h> | |
| #include <Common/FirmwareVolumeImageFormat.h> | |
| #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; | |
| } |