#include "EfiFirmwareFileSystem.h"\r
#include "EfiFirmwareVolumeHeader.h"\r
#include "EfiImageFormat.h"\r
+#include "EfiImage.h"\r
#include "ParseInf.h"\r
#include "Compress.h"\r
#include "EfiCustomizedCompress.h"\r
void\r
);\r
\r
+static\r
+void\r
+AddMacro (\r
+ UINT8 *MacroString\r
+ );\r
+\r
+static\r
+UINT8 *\r
+GetMacroValue (\r
+ UINT8 *MacroName\r
+ );\r
+ \r
+static\r
+void\r
+FreeMacros (\r
+ );\r
+\r
+static\r
+STATUS\r
+ReplaceMacros (\r
+ UINT8 *InputFile,\r
+ UINT8 *OutputFile\r
+ );\r
+ \r
+//\r
+// Linked list to keep track of all macros\r
+//\r
+typedef struct _MACRO {\r
+ struct _MACRO *Next;\r
+ UINT8 *Name;\r
+ UINT8 *Value;\r
+} MACRO;\r
+\r
//\r
// Keep globals in this structure\r
//\r
UINT8 PrimaryPackagePath[_MAX_PATH];\r
UINT8 OverridePackagePath[_MAX_PATH];\r
BOOLEAN Verbose;\r
+ MACRO *MacroList;\r
} mGlobals;\r
\r
static EFI_GUID mZeroGuid = { 0 };\r
\r
+static UINT8 MinFfsDataAlignOverride = 0;\r
+\r
static\r
void\r
StripQuotes (\r
--*/\r
{\r
printf ("Usage:\n");\r
- printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\" -v\n");\r
- printf (" -b \"build directory\":\n ");\r
+ printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\"\n");\r
+ printf (" -d \"name=value\" -v\n");\r
+ printf (" -b \"build directory\":\n");\r
printf (" specifies the full path to the component build directory.\n");\r
printf (" -p1 \"P1_path\":\n");\r
printf (" specifies fully qualified file name to the primary package file.\n");\r
printf (" -p2 \"P2_path\":\n");\r
printf (" specifies fully qualified file name to the override package file.\n");\r
printf (" This file will normally exist in the build tip. Optional.\n");\r
+ printf (" -d \"name=value\":\n");\r
+ printf (" add a macro definition for package file. Optional.\n");\r
+ printf (" -v :\n");\r
+ printf (" verbose. Optional.\n");\r
}\r
\r
static\r
return ;\r
}\r
\r
-static\r
-INT32\r
-ProcessEnvironmentVariable (\r
- IN CHAR8 *Buffer,\r
- OUT CHAR8 *NewBuffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Converts environment variables to values\r
-\r
-Arguments:\r
-\r
- Buffer - Buffer containing Environment Variable String\r
-\r
- NewBuffer - Buffer containing value of environment variable\r
-\r
-\r
-Returns:\r
-\r
- Number of characters from Buffer used\r
-\r
---*/\r
-{\r
- INT32 Index;\r
- INT32 Index2;\r
- CHAR8 VariableBuffer[_MAX_PATH];\r
-\r
- Index = 2;\r
- Index2 = 0;\r
-\r
- while (Buffer[Index] != ')') {\r
- VariableBuffer[Index - 2] = Buffer[Index++];\r
- }\r
-\r
- VariableBuffer[Index - 2] = 0;\r
- Index++;\r
-\r
- if (getenv (VariableBuffer) != NULL) {\r
- strcpy (NewBuffer, getenv (VariableBuffer));\r
- } else {\r
- printf ("Environment variable %s not found!\n", VariableBuffer);\r
- }\r
-\r
- return Index;\r
-}\r
-\r
static\r
void\r
SplitAttributesField (\r
UINT32 Index2;\r
UINT32 z;\r
CHAR8 *CharBuffer;\r
- INT32 Index;\r
INT32 ReturnValue;\r
EFI_STATUS Status;\r
\r
\r
ToolArgumentsArray[argc] = CharBuffer;\r
\r
- if (Buffer[0] == '$') {\r
- Index = ProcessEnvironmentVariable (&Buffer[0], ToolArgumentsArray[argc]);\r
- //\r
- // if there is string after the environment variable, cat it.\r
- //\r
- if ((UINT32) Index < strlen (Buffer)) {\r
- strcat (ToolArgumentsArray[argc], &Buffer[Index]);\r
- }\r
- } else {\r
- strcpy (ToolArgumentsArray[argc], Buffer);\r
- }\r
+ strcpy (ToolArgumentsArray[argc], Buffer);\r
\r
argc += 1;\r
ToolArgumentsArray[argc] = NULL;\r
\r
ZeroMem (InputFileName, sizeof (_MAX_PATH));\r
\r
- if (Buffer[0] == '$') {\r
- Index = ProcessEnvironmentVariable (&Buffer[0], InputFileName);\r
- //\r
- // if there is string after the environment variable, cat it.\r
- //\r
- if ((UINT32) Index < strlen (Buffer)) {\r
- strcat (InputFileName, &Buffer[Index]);\r
- }\r
- } else {\r
- strcpy (InputFileName, Buffer);\r
- }\r
+ strcpy (InputFileName, Buffer);\r
\r
InputFlag = FALSE;\r
continue;\r
\r
ZeroMem (OutputFileName, sizeof (_MAX_PATH));\r
\r
- if (Buffer[0] == '$') {\r
- Index = ProcessEnvironmentVariable (&Buffer[0], OutputFileName);\r
- //\r
- // if there is string after the environment variable, cat it.\r
- //\r
- if ((UINT32) Index < strlen (Buffer)) {\r
- strcat (OutputFileName, &Buffer[Index]);\r
- }\r
- } else {\r
- strcpy (OutputFileName, Buffer);\r
- }\r
+ strcpy (OutputFileName, Buffer);\r
\r
OutputFlag = FALSE;\r
continue;\r
{\r
EFI_STATUS Status;\r
UINT32 Size;\r
+ UINT32 OldSize;\r
+ UINT32 Adjust;\r
+ UINT16 TeStrippedSize;\r
CHAR8 Buffer[_MAX_PATH];\r
CHAR8 Type[_MAX_PATH];\r
CHAR8 FileName[_MAX_PATH];\r
- CHAR8 NewBuffer[_MAX_PATH];\r
INT32 Index3;\r
INT32 Index2;\r
UINT32 ReturnValue;\r
FILE *InputFile;\r
UINT8 Temp;\r
int returnint;\r
- INT32 Index;\r
UINT32 LineNumber;\r
BOOLEAN IsError;\r
EFI_GUID SignGuid;\r
}\r
\r
StripParens (Buffer);\r
- if (Buffer[0] == '$') {\r
- ProcessEnvironmentVariable (&Buffer[0], Type);\r
- } else {\r
- strcpy (Type, Buffer);\r
- }\r
+ strcpy (Type, Buffer);\r
//\r
// build buffer\r
//\r
}\r
\r
StripParens (Buffer);\r
-\r
- if (Buffer[0] == '$') {\r
- Index = ProcessEnvironmentVariable (&Buffer[0], ToolName);\r
- //\r
- // if there is string after the environment variable, cat it.\r
- //\r
- if ((UINT32) Index < strlen (Buffer)) {\r
- strcat (ToolName, &Buffer[Index]);\r
- }\r
- } else {\r
- strcpy (ToolName, Buffer);\r
- }\r
-\r
+ strcpy (ToolName, Buffer);\r
ToolArgumentsArray[0] = ToolName;\r
\r
//\r
if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) {\r
sprintf (FileName, "%s\\", BuildDirectory);\r
}\r
-\r
+ \r
while (Buffer[Index3] != '\n') {\r
- if (Buffer[Index3] == '$') {\r
- Index3 += ProcessEnvironmentVariable (&Buffer[Index3], NewBuffer);\r
- strcat (FileName, NewBuffer);\r
- }\r
-\r
if (Buffer[Index3] == 0) {\r
break;\r
} else {\r
goto Done;\r
}\r
\r
+ OldSize = Size;\r
fread (&ByteBuffer, sizeof (UINT8), 1, InFile);\r
while (!feof (InFile)) {\r
FileBuffer[Size++] = ByteBuffer;\r
fclose (InFile);\r
InFile = NULL;\r
\r
+ //\r
+ // Adjust the TE Section for IPF so that the function entries are 16-byte aligned.\r
+ //\r
+ if (Size - OldSize >= sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER) &&\r
+ ((EFI_COMMON_SECTION_HEADER *) &FileBuffer[OldSize])->Type == EFI_SECTION_TE &&\r
+ ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->Machine == EFI_IMAGE_MACHINE_IA64) {\r
+ TeStrippedSize = ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->StrippedSize;\r
+ Adjust = TeStrippedSize - (OldSize + sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER));\r
+ Adjust &= 15;\r
+ if (Adjust > 0) {\r
+ memmove (&FileBuffer[OldSize + Adjust], &FileBuffer[OldSize], Size - OldSize);\r
+ //\r
+ // Pad with RAW Section type\r
+ //\r
+ *(UINT32 *)&FileBuffer[OldSize] = 0x19000000 | Adjust;\r
+ Size += Adjust;\r
+ //\r
+ // Make sure the Data alignment in FFS header is no less than 1 (16-byte aligned)\r
+ //\r
+ MinFfsDataAlignOverride = 1;\r
+ }\r
+ }\r
+\r
//\r
// Make sure section ends on a DWORD boundary\r
//\r
memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));\r
FileHeader.Type = StringToType (FileType);\r
+ if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {\r
+ FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);\r
+ }\r
FileHeader.Attributes = FfsAttrib;\r
//\r
// Now FileSize includes the EFI_FFS_FILE_HEADER\r
memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));\r
FileHeader.Type = StringToType (FileType);\r
+ if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {\r
+ FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);\r
+ }\r
FileHeader.Attributes = FfsAttrib;\r
//\r
// From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER\r
//\r
SetUtilityName (UTILITY_NAME);\r
Status = ProcessCommandLineArgs (argc, argv);\r
+ FreeMacros ();\r
if (Status != STATUS_SUCCESS) {\r
return Status;\r
}\r
\r
--*/\r
{\r
+ STATUS Status;\r
+ UINT8 *OriginalPrimaryPackagePath;\r
+ UINT8 *OriginalOverridePackagePath;\r
+ UINT8 *PackageName;\r
+ \r
//\r
// If no args, then print usage instructions and return an error\r
//\r
PrintUsage ();\r
return STATUS_ERROR;\r
}\r
-\r
+ \r
+ OriginalPrimaryPackagePath = NULL;\r
+ OriginalOverridePackagePath = NULL;\r
memset (&mGlobals, 0, sizeof (mGlobals));\r
Argc--;\r
Argv++;\r
return STATUS_ERROR;\r
}\r
\r
- if (mGlobals.PrimaryPackagePath[0]) {\r
+ if (OriginalPrimaryPackagePath) {\r
Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
return STATUS_ERROR;\r
}\r
-\r
- strcpy (mGlobals.PrimaryPackagePath, Argv[1]);\r
+ \r
+ OriginalPrimaryPackagePath = Argv[1];\r
Argc--;\r
Argv++;\r
} else if (_strcmpi (Argv[0], "-p2") == 0) {\r
return STATUS_ERROR;\r
}\r
\r
- if (mGlobals.OverridePackagePath[0]) {\r
+ if (OriginalOverridePackagePath) {\r
Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
return STATUS_ERROR;\r
}\r
-\r
- strcpy (mGlobals.OverridePackagePath, Argv[1]);\r
+ \r
+ OriginalOverridePackagePath = Argv[1];\r
Argc--;\r
Argv++;\r
} else if (_strcmpi (Argv[0], "-v") == 0) {\r
// OPTION: -v verbose\r
//\r
mGlobals.Verbose = TRUE;\r
+ } else if (_strcmpi (Argv[0], "-d") == 0) {\r
+ //\r
+ // OPTION: -d name=value\r
+ // Make sure there is another argument, then add it to our macro list.\r
+ //\r
+ if (Argc < 2) {\r
+ Error (NULL, 0, 0, Argv[0], "option requires the macro definition");\r
+ return STATUS_ERROR;\r
+ }\r
+ \r
+ AddMacro (Argv[1]);\r
+ Argc--;\r
+ Argv++;\r
} else if (_strcmpi (Argv[0], "-h") == 0) {\r
//\r
// OPTION: -h help\r
Argv++;\r
Argc--;\r
}\r
+\r
+ //\r
+ // Must have at least specified the build directory\r
+ //\r
+ if (!mGlobals.BuildDirectory[0]) {\r
+ Error (NULL, 0, 0, "must specify build directory", NULL);\r
+ return STATUS_ERROR;\r
+ }\r
+ \r
//\r
// Must have at least specified the package file name\r
//\r
- if (mGlobals.PrimaryPackagePath[0] == 0) {\r
+ if (OriginalPrimaryPackagePath == NULL) {\r
Error (NULL, 0, 0, "must specify primary package file", NULL);\r
return STATUS_ERROR;\r
}\r
\r
+ PackageName = OriginalPrimaryPackagePath + strlen (OriginalPrimaryPackagePath);\r
+ while ((*PackageName != '\\') && (*PackageName != '/') && \r
+ (PackageName != OriginalPrimaryPackagePath)) {\r
+ PackageName--;\r
+ }\r
+ //\r
+ // Skip the '\' or '/'\r
+ //\r
+ if (PackageName != OriginalPrimaryPackagePath) {\r
+ PackageName++;\r
+ }\r
+ sprintf (mGlobals.PrimaryPackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);\r
+ Status = ReplaceMacros (OriginalPrimaryPackagePath, mGlobals.PrimaryPackagePath);\r
+ if (Status == STATUS_WARNING) {\r
+ //\r
+ // No macro replacement, use the previous package file\r
+ //\r
+ strcpy (mGlobals.PrimaryPackagePath, OriginalPrimaryPackagePath);\r
+ } else if (Status != STATUS_SUCCESS) {\r
+ return Status;\r
+ }\r
+ \r
+ if (OriginalOverridePackagePath != NULL) {\r
+ PackageName = OriginalOverridePackagePath + strlen (OriginalOverridePackagePath);\r
+ while ((*PackageName != '\\') && (*PackageName != '/') && \r
+ (PackageName != OriginalOverridePackagePath)) {\r
+ PackageName--;\r
+ }\r
+ //\r
+ // Skip the '\' or '/'\r
+ //\r
+ if (PackageName != OriginalOverridePackagePath) {\r
+ PackageName++;\r
+ } \r
+ sprintf (mGlobals.OverridePackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);\r
+ Status = ReplaceMacros (OriginalOverridePackagePath, mGlobals.OverridePackagePath);\r
+ if (Status == STATUS_WARNING) {\r
+ //\r
+ // No macro replacement, use the previous package file\r
+ //\r
+ strcpy (mGlobals.OverridePackagePath, OriginalOverridePackagePath);\r
+ } else if (Status != STATUS_SUCCESS) {\r
+ return Status;\r
+ } \r
+ }\r
+\r
return STATUS_SUCCESS;\r
}\r
+\r
+static\r
+void\r
+AddMacro (\r
+ UINT8 *MacroString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Add or override a macro definition.\r
+\r
+Arguments:\r
+\r
+ MacroString - macro definition string: name=value\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/ \r
+{\r
+ MACRO *Macro;\r
+ MACRO *NewMacro;\r
+ UINT8 *Value;\r
+ \r
+ //\r
+ // Seperate macro name and value by '\0'\r
+ //\r
+ for (Value = MacroString; *Value && (*Value != '='); Value++);\r
+ \r
+ if (*Value == '=') {\r
+ *Value = '\0';\r
+ Value ++;\r
+ }\r
+ \r
+ //\r
+ // We now have a macro name and value. \r
+ // Look for an existing macro and overwrite it.\r
+ //\r
+ Macro = mGlobals.MacroList;\r
+ while (Macro) {\r
+ if (_strcmpi (MacroString, Macro->Name) == 0) {\r
+ Macro->Value = Value;\r
+ return;\r
+ }\r
+\r
+ Macro = Macro->Next;\r
+ }\r
+ \r
+ //\r
+ // Does not exist, create a new one\r
+ //\r
+ NewMacro = (MACRO *) malloc (sizeof (MACRO));\r
+ memset ((UINT8 *) NewMacro, 0, sizeof (MACRO));\r
+ NewMacro->Name = MacroString;\r
+ NewMacro->Value = Value;\r
+\r
+ //\r
+ // Add it to the head of the list.\r
+ //\r
+ NewMacro->Next = mGlobals.MacroList;\r
+ mGlobals.MacroList = NewMacro;\r
+ \r
+ return;\r
+}\r
+\r
+static\r
+UINT8 *\r
+GetMacroValue (\r
+ UINT8 *MacroName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Look up a macro.\r
+\r
+Arguments:\r
+\r
+ MacroName - The name of macro\r
+\r
+Returns:\r
+\r
+ Pointer to the value of the macro if found\r
+ NULL if the macro is not found\r
+\r
+--*/ \r
+{\r
+\r
+ MACRO *Macro;\r
+ UINT8 *Value;\r
+\r
+ //\r
+ // Scan for macro\r
+ //\r
+ Macro = mGlobals.MacroList;\r
+ while (Macro) {\r
+ if (_strcmpi (MacroName, Macro->Name) == 0) {\r
+ return Macro->Value;\r
+ }\r
+ Macro = Macro->Next;\r
+ }\r
+ \r
+ //\r
+ // Try environment variable\r
+ //\r
+ Value = getenv (MacroName);\r
+ if (Value == NULL) {\r
+ printf ("Environment variable %s not found!\n", MacroName);\r
+ } \r
+ return Value;\r
+}\r
+ \r
+static\r
+void\r
+FreeMacros (\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Free the macro list.\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/ \r
+{\r
+ MACRO *Macro;\r
+ MACRO *NextMacro;\r
+ \r
+ Macro = mGlobals.MacroList;\r
+ while (Macro) {\r
+ NextMacro = Macro->Next;\r
+ free (Macro);\r
+ Macro = NextMacro;\r
+ }\r
+ mGlobals.MacroList = NULL;\r
+ \r
+ return;\r
+}\r
+\r
+static\r
+STATUS\r
+ReplaceMacros (\r
+ UINT8 *InputFile,\r
+ UINT8 *OutputFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Replace all the macros in InputFile to create the OutputFile.\r
+\r
+Arguments:\r
+\r
+ InputFile - Input package file for macro replacement\r
+ OutputFile - Output package file after macro replacement\r
+\r
+Returns:\r
+\r
+ STATUS_SUCCESS - Output package file is created successfully after the macro replacement.\r
+ STATUS_WARNING - Output package file is not created because of no macro replacement.\r
+ STATUS_ERROR - Some error occurred during execution.\r
+\r
+--*/ \r
+{\r
+ FILE *Fptr;\r
+ UINT8 *SaveStart;\r
+ UINT8 *FromPtr;\r
+ UINT8 *ToPtr;\r
+ UINT8 *Value;\r
+ UINT8 *FileBuffer;\r
+ UINTN FileSize;\r
+ \r
+ //\r
+ // Get the file size, and then read the entire thing into memory.\r
+ // Allocate extra space for a terminator character.\r
+ //\r
+ if ((Fptr = fopen (InputFile, "r")) == NULL) {\r
+ Error (NULL, 0, 0, InputFile, "can't open input file");\r
+ return STATUS_ERROR; \r
+ }\r
+ fseek (Fptr, 0, SEEK_END);\r
+ FileSize = ftell (Fptr);\r
+ fseek (Fptr, 0, SEEK_SET);\r
+ FileBuffer = malloc (FileSize + 1);\r
+ if (FileBuffer == NULL) {\r
+ fclose (Fptr);\r
+ Error (NULL, 0, 0, InputFile, "file buffer memory allocation failure");\r
+ return STATUS_ERROR;\r
+ }\r
+ fread (FileBuffer, FileSize, 1, Fptr);\r
+ FileBuffer[FileSize] = '\0';\r
+ fclose (Fptr);\r
+ \r
+ //\r
+ // Walk the entire file, replacing $(MACRO_NAME).\r
+ //\r
+ Fptr = NULL;\r
+ FromPtr = FileBuffer;\r
+ SaveStart = FromPtr;\r
+ while (*FromPtr) {\r
+ if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) {\r
+ FromPtr += 2;\r
+ for (ToPtr = FromPtr; *ToPtr && (*ToPtr != ')'); ToPtr++);\r
+ if (*ToPtr) {\r
+ //\r
+ // Find an $(MACRO_NAME), replace it\r
+ //\r
+ *ToPtr = '\0';\r
+ Value = GetMacroValue (FromPtr);\r
+ *(FromPtr-2)= '\0';\r
+ if (Fptr == NULL) {\r
+ if ((Fptr = fopen (OutputFile, "w")) == NULL) {\r
+ free (FileBuffer);\r
+ Error (NULL, 0, 0, OutputFile, "can't open output file");\r
+ return STATUS_ERROR; \r
+ }\r
+ }\r
+ if (Value != NULL) {\r
+ fprintf (Fptr, "%s%s", SaveStart, Value);\r
+ } else {\r
+ fprintf (Fptr, "%s", SaveStart);\r
+ }\r
+ //\r
+ // Continue macro replacement for the remaining string line\r
+ //\r
+ FromPtr = ToPtr+1;\r
+ SaveStart = FromPtr;\r
+ continue;\r
+ } else {\r
+ break;\r
+ }\r
+ } else {\r
+ FromPtr++;\r
+ }\r
+ }\r
+ if (Fptr != NULL) {\r
+ fprintf (Fptr, "%s", SaveStart);\r
+ }\r
+ \r
+ free (FileBuffer);\r
+ if (Fptr != NULL) {\r
+ fclose (Fptr);\r
+ return STATUS_SUCCESS;\r
+ } else {\r
+ return STATUS_WARNING;\r
+ }\r
+}\r