mirror of https://github.com/acidanthera/audk.git
3040 lines
80 KiB
C
3040 lines
80 KiB
C
/*++
|
|
|
|
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
|
|
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 "TianoCommon.h"
|
|
#include "EfiFirmwareFileSystem.h"
|
|
#include "EfiFirmwareVolumeHeader.h"
|
|
#include "EfiImageFormat.h"
|
|
#include "EfiImage.h"
|
|
#include "ParseInf.h"
|
|
#include "Compress.h"
|
|
#include "EfiCustomizedCompress.h"
|
|
#include "crc32.h"
|
|
#include "GenFfsFile.h"
|
|
#include <stdio.h>
|
|
#include <ctype.h> // for isalpha()
|
|
//
|
|
// include file for _spawnv
|
|
//
|
|
#include <process.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "CommonLib.h"
|
|
#include "EfiUtilityMsgs.h"
|
|
#include "SimpleFileParsing.h"
|
|
|
|
#define UTILITY_NAME "GenFfsFile"
|
|
#define UTILITY_VERSION "v1.1"
|
|
#define MAX_ARRAY_SIZE 100
|
|
|
|
static
|
|
INT32
|
|
GetNextLine (
|
|
OUT CHAR8 *Destination,
|
|
IN FILE *Package,
|
|
IN OUT UINT32 *LineNumber
|
|
);
|
|
|
|
static
|
|
void
|
|
CheckSlash (
|
|
IN OUT CHAR8 *String,
|
|
IN FILE *In,
|
|
IN OUT UINT32 *LineNumber
|
|
);
|
|
|
|
static
|
|
INT32
|
|
FindSectionInPackage (
|
|
IN CHAR8 *BuildDirectory,
|
|
IN FILE *OverridePackage,
|
|
IN OUT UINT32 *LineNumber
|
|
);
|
|
|
|
static
|
|
STATUS
|
|
ProcessCommandLineArgs (
|
|
int Argc,
|
|
char *Argv[]
|
|
);
|
|
|
|
static
|
|
void
|
|
PrintUsage (
|
|
void
|
|
);
|
|
|
|
static
|
|
void
|
|
AddMacro (
|
|
UINT8 *MacroString
|
|
);
|
|
|
|
static
|
|
UINT8 *
|
|
GetMacroValue (
|
|
UINT8 *MacroName
|
|
);
|
|
|
|
static
|
|
void
|
|
FreeMacros (
|
|
);
|
|
|
|
static
|
|
STATUS
|
|
ReplaceMacros (
|
|
UINT8 *InputFile,
|
|
UINT8 *OutputFile
|
|
);
|
|
|
|
//
|
|
// Linked list to keep track of all macros
|
|
//
|
|
typedef struct _MACRO {
|
|
struct _MACRO *Next;
|
|
UINT8 *Name;
|
|
UINT8 *Value;
|
|
} MACRO;
|
|
|
|
//
|
|
// Keep globals in this structure
|
|
//
|
|
static struct {
|
|
UINT8 BuildDirectory[_MAX_PATH];
|
|
UINT8 PrimaryPackagePath[_MAX_PATH];
|
|
UINT8 OverridePackagePath[_MAX_PATH];
|
|
UINT8 OutputFilePath[_MAX_PATH];
|
|
BOOLEAN Verbose;
|
|
MACRO *MacroList;
|
|
} mGlobals;
|
|
|
|
static EFI_GUID mZeroGuid = { 0 };
|
|
|
|
static UINT8 MinFfsDataAlignOverride = 0;
|
|
|
|
static
|
|
void
|
|
StripQuotes (
|
|
IN OUT CHAR8 *String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes quotes and/or whitespace from around a string
|
|
|
|
Arguments:
|
|
|
|
String - String to remove quotes from
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UINTN StrLen;
|
|
|
|
Index2 = strspn (String, "\" \t\n");
|
|
StrLen = strlen (String);
|
|
|
|
for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) {
|
|
String[Index - Index2] = String[Index];
|
|
}
|
|
|
|
String[Index - Index2] = 0;
|
|
}
|
|
|
|
static
|
|
void
|
|
PrintUsage (
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print Error / Help message.
|
|
|
|
Arguments:
|
|
|
|
void
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
int Index;
|
|
const char *Str[] = {
|
|
UTILITY_NAME" "UTILITY_VERSION" - Intel Generate FFS File Utility",
|
|
" Copyright (C), 2004 - 2009 Intel Corporation",
|
|
|
|
#if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
|
|
" Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,
|
|
#endif
|
|
"",
|
|
"Usage:",
|
|
" "UTILITY_NAME" [OPTION]...",
|
|
"Options:",
|
|
" -b BuildDirectory Specifies the full path to the component build directory",
|
|
" -p1 P1Path Specifies fully qualified file name to the primary package",
|
|
" file. This file will normally exist in the same directory",
|
|
" as the makefile for the component. Required.",
|
|
" -p2 P2Path Specifies fully qualified file name to the override",
|
|
" package. This file will normally exist in the build tip.",
|
|
" Optional.",
|
|
" -d Name=Value Add a macro definition for the package file. Optional.",
|
|
" -o OutputFile Specifies the file name of output file. Optional.",
|
|
" -v Verbose. Optional.",
|
|
NULL
|
|
};
|
|
for (Index = 0; Str[Index] != NULL; Index++) {
|
|
fprintf (stdout, "%s\n", Str[Index]);
|
|
}
|
|
}
|
|
|
|
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) TianoCompress;
|
|
|
|
} else if (_strcmpi (Type, "LZH") == 0) {
|
|
//
|
|
// EFI standard compression (LZH)
|
|
//
|
|
CompressionType = EFI_STANDARD_COMPRESSION;
|
|
CompressFunction = (COMPRESS_FUNCTION) TianoCompress;
|
|
|
|
} 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
|
|
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 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;
|
|
|
|
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));
|
|
|
|
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));
|
|
|
|
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;
|
|
UINT32 OldSize;
|
|
UINT32 Adjust;
|
|
UINT16 TeStrippedSize;
|
|
CHAR8 Buffer[_MAX_PATH];
|
|
CHAR8 Type[_MAX_PATH];
|
|
CHAR8 FileName[_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;
|
|
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);
|
|
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);
|
|
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
|
|
//
|
|
returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray);
|
|
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] == 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;
|
|
}
|
|
|
|
OldSize = Size;
|
|
fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
|
|
while (!feof (InFile)) {
|
|
FileBuffer[Size++] = ByteBuffer;
|
|
fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
|
|
}
|
|
|
|
fclose (InFile);
|
|
InFile = NULL;
|
|
|
|
//
|
|
// Adjust the TE Section for IPF so that the function entries are 16-byte aligned.
|
|
//
|
|
if (Size - OldSize >= sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER) &&
|
|
((EFI_COMMON_SECTION_HEADER *) &FileBuffer[OldSize])->Type == EFI_SECTION_TE &&
|
|
((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->Machine == EFI_IMAGE_MACHINE_IA64) {
|
|
TeStrippedSize = ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->StrippedSize;
|
|
Adjust = TeStrippedSize - (OldSize + sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER));
|
|
Adjust &= 15;
|
|
if (Adjust > 0) {
|
|
memmove (&FileBuffer[OldSize + Adjust], &FileBuffer[OldSize], Size - OldSize);
|
|
//
|
|
// Pad with RAW Section type
|
|
//
|
|
*(UINT32 *)&FileBuffer[OldSize] = 0x19000000 | Adjust;
|
|
Size += Adjust;
|
|
//
|
|
// Make sure the Data alignment in FFS header is no less than 1 (16-byte aligned)
|
|
//
|
|
MinFfsDataAlignOverride = 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
#if (PI_SPECIFICATION_VERSION < 0x00010000)
|
|
EFI_FFS_FILE_TAIL TailValue;
|
|
#endif
|
|
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;
|
|
}
|
|
}
|
|
#if (PI_SPECIFICATION_VERSION < 0x00010000)
|
|
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
|
|
else if (SFPIsToken ("FFS_ATTRIB_FIXED")) {
|
|
//
|
|
// ***********************************************************************
|
|
//
|
|
// Found: FFS_ATTRIB_FIXED = TRUE | FALSE
|
|
//
|
|
if (FfsAttribDefined & FFS_ATTRIB_FIXED) {
|
|
Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_FIXED previously defined", NULL);
|
|
goto Done;
|
|
}
|
|
|
|
FfsAttribDefined |= FFS_ATTRIB_FIXED;
|
|
if (!SFPIsToken ("=")) {
|
|
Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
|
|
goto Done;
|
|
}
|
|
|
|
if (SFPIsToken ("TRUE")) {
|
|
FfsAttrib |= FFS_ATTRIB_FIXED;
|
|
} else if (SFPIsToken ("FALSE")) {
|
|
//
|
|
// Default is FALSE
|
|
//
|
|
} else {
|
|
Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
|
|
goto Done;
|
|
}
|
|
}
|
|
#endif
|
|
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_SUPPORTED
|
|
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) {
|
|
Error (NULL, 0, 0, "failed to process script", NULL);
|
|
goto Done;
|
|
}
|
|
|
|
if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
|
|
FileSize = AdjustFileSize (FileBuffer, FileSize);
|
|
}
|
|
|
|
if (BaseName[0] == '\"') {
|
|
StripQuotes (BaseName);
|
|
}
|
|
|
|
if (mGlobals.OutputFilePath[0]) {
|
|
//
|
|
// Use user specified output file name
|
|
//
|
|
strcpy (InputString, mGlobals.OutputFilePath);
|
|
} else {
|
|
//
|
|
// Construct the output file name according to FileType
|
|
//
|
|
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_RAW:
|
|
strcat (InputString, ".RAW");
|
|
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);
|
|
if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {
|
|
FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);
|
|
}
|
|
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) {
|
|
#if (PI_SPECIFICATION_VERSION < 0x00010000)
|
|
FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize);
|
|
#else
|
|
FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) ((UINTN)&FileHeader + sizeof (EFI_FFS_FILE_HEADER)), FileSize - sizeof (EFI_FFS_FILE_HEADER));
|
|
#endif
|
|
} 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) {
|
|
Error (NULL, 0, 0, "failed to process script", NULL);
|
|
goto Done;
|
|
}
|
|
|
|
if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
|
|
FileSize = AdjustFileSize (FileBuffer, FileSize);
|
|
}
|
|
|
|
if (BaseName[0] == '\"') {
|
|
StripQuotes (BaseName);
|
|
}
|
|
|
|
if (mGlobals.OutputFilePath[0]) {
|
|
//
|
|
// Use user specified output file name
|
|
//
|
|
strcpy (InputString, mGlobals.OutputFilePath);
|
|
} else {
|
|
//
|
|
// Construct the output file name according to FileType
|
|
//
|
|
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_RAW:
|
|
strcat (InputString, ".RAW");
|
|
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);
|
|
if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {
|
|
FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);
|
|
}
|
|
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 (PI_SPECIFICATION_VERSION < 0x00010000)
|
|
|
|
//
|
|
// 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)
|
|
);
|
|
}
|
|
#endif
|
|
//
|
|
// 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);
|
|
FreeMacros ();
|
|
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
|
|
|
|
--*/
|
|
{
|
|
STATUS Status;
|
|
UINT8 *OriginalPrimaryPackagePath;
|
|
UINT8 *OriginalOverridePackagePath;
|
|
UINT8 *PackageName;
|
|
|
|
//
|
|
// If no args, then print usage instructions and return an error
|
|
//
|
|
if (Argc == 1) {
|
|
PrintUsage ();
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
OriginalPrimaryPackagePath = NULL;
|
|
OriginalOverridePackagePath = NULL;
|
|
memset (&mGlobals, 0, sizeof (mGlobals));
|
|
Argc--;
|
|
Argv++;
|
|
while (Argc > 0) {
|
|
if (_strcmpi (Argv[0], "-b") == 0) {
|
|
//
|
|
// OPTION: -b BuildDirectory
|
|
// Make sure there is another argument, then save it to our globals.
|
|
//
|
|
if (Argc < 2) {
|
|
Error (NULL, 0, 0, "-b option requires the build directory name", NULL);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
if (mGlobals.BuildDirectory[0]) {
|
|
Error (NULL, 0, 0, Argv[0], "option can only be specified once");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
strcpy (mGlobals.BuildDirectory, Argv[1]);
|
|
Argc--;
|
|
Argv++;
|
|
} else if (_strcmpi (Argv[0], "-p1") == 0) {
|
|
//
|
|
// OPTION: -p1 PrimaryPackageFile
|
|
// Make sure there is another argument, then save it to our globals.
|
|
//
|
|
if (Argc < 2) {
|
|
Error (NULL, 0, 0, Argv[0], "option requires the primary package file name");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
if (OriginalPrimaryPackagePath) {
|
|
Error (NULL, 0, 0, Argv[0], "option can only be specified once");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
OriginalPrimaryPackagePath = 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 (OriginalOverridePackagePath) {
|
|
Error (NULL, 0, 0, Argv[0], "option can only be specified once");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
OriginalOverridePackagePath = Argv[1];
|
|
Argc--;
|
|
Argv++;
|
|
} else if (_strcmpi (Argv[0], "-o") == 0) {
|
|
//
|
|
// OPTION: -o OutputFilePath
|
|
// Make sure there is another argument, then save it to out globals.
|
|
//
|
|
if (Argc < 2) {
|
|
Error (NULL, 0, 0, Argv[0], "option requires the output file name");
|
|
return STATUS_ERROR;
|
|
}
|
|
if (mGlobals.OutputFilePath[0]) {
|
|
Error (NULL, 0, 0, Argv[0], "option can only be specified once");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
strcpy (mGlobals.OutputFilePath, Argv[1]);
|
|
Argc--;
|
|
Argv++;
|
|
} else if (_strcmpi (Argv[0], "-v") == 0) {
|
|
//
|
|
// OPTION: -v verbose
|
|
//
|
|
mGlobals.Verbose = TRUE;
|
|
} else if (_strcmpi (Argv[0], "-d") == 0) {
|
|
//
|
|
// OPTION: -d name=value
|
|
// Make sure there is another argument, then add it to our macro list.
|
|
//
|
|
if (Argc < 2) {
|
|
Error (NULL, 0, 0, Argv[0], "option requires the macro definition");
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
AddMacro (Argv[1]);
|
|
Argc--;
|
|
Argv++;
|
|
} else if (_strcmpi (Argv[0], "-h") == 0) {
|
|
//
|
|
// OPTION: -h help
|
|
//
|
|
PrintUsage ();
|
|
return STATUS_ERROR;
|
|
} else if (_strcmpi (Argv[0], "-?") == 0) {
|
|
//
|
|
// OPTION: -? help
|
|
//
|
|
PrintUsage ();
|
|
return STATUS_ERROR;
|
|
} else {
|
|
Error (NULL, 0, 0, Argv[0], "unrecognized option");
|
|
PrintUsage ();
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
Argv++;
|
|
Argc--;
|
|
}
|
|
|
|
//
|
|
// Must have at least specified the build directory
|
|
//
|
|
if (!mGlobals.BuildDirectory[0]) {
|
|
Error (NULL, 0, 0, "must specify build directory", NULL);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
//
|
|
// Must have at least specified the package file name
|
|
//
|
|
if (OriginalPrimaryPackagePath == NULL) {
|
|
Error (NULL, 0, 0, "must specify primary package file", NULL);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
PackageName = OriginalPrimaryPackagePath + strlen (OriginalPrimaryPackagePath);
|
|
while ((*PackageName != '\\') && (*PackageName != '/') &&
|
|
(PackageName != OriginalPrimaryPackagePath)) {
|
|
PackageName--;
|
|
}
|
|
//
|
|
// Skip the '\' or '/'
|
|
//
|
|
if (PackageName != OriginalPrimaryPackagePath) {
|
|
PackageName++;
|
|
}
|
|
sprintf (mGlobals.PrimaryPackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);
|
|
Status = ReplaceMacros (OriginalPrimaryPackagePath, mGlobals.PrimaryPackagePath);
|
|
if (Status == STATUS_WARNING) {
|
|
//
|
|
// No macro replacement, use the previous package file
|
|
//
|
|
strcpy (mGlobals.PrimaryPackagePath, OriginalPrimaryPackagePath);
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if (OriginalOverridePackagePath != NULL) {
|
|
PackageName = OriginalOverridePackagePath + strlen (OriginalOverridePackagePath);
|
|
while ((*PackageName != '\\') && (*PackageName != '/') &&
|
|
(PackageName != OriginalOverridePackagePath)) {
|
|
PackageName--;
|
|
}
|
|
//
|
|
// Skip the '\' or '/'
|
|
//
|
|
if (PackageName != OriginalOverridePackagePath) {
|
|
PackageName++;
|
|
}
|
|
sprintf (mGlobals.OverridePackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);
|
|
Status = ReplaceMacros (OriginalOverridePackagePath, mGlobals.OverridePackagePath);
|
|
if (Status == STATUS_WARNING) {
|
|
//
|
|
// No macro replacement, use the previous package file
|
|
//
|
|
strcpy (mGlobals.OverridePackagePath, OriginalOverridePackagePath);
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
void
|
|
AddMacro (
|
|
UINT8 *MacroString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add or override a macro definition.
|
|
|
|
Arguments:
|
|
|
|
MacroString - macro definition string: name=value
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
MACRO *Macro;
|
|
MACRO *NewMacro;
|
|
UINT8 *Value;
|
|
|
|
//
|
|
// Seperate macro name and value by '\0'
|
|
//
|
|
for (Value = MacroString; *Value && (*Value != '='); Value++);
|
|
|
|
if (*Value == '=') {
|
|
*Value = '\0';
|
|
Value ++;
|
|
}
|
|
|
|
//
|
|
// We now have a macro name and value.
|
|
// Look for an existing macro and overwrite it.
|
|
//
|
|
Macro = mGlobals.MacroList;
|
|
while (Macro) {
|
|
if (_strcmpi (MacroString, Macro->Name) == 0) {
|
|
Macro->Value = Value;
|
|
return;
|
|
}
|
|
|
|
Macro = Macro->Next;
|
|
}
|
|
|
|
//
|
|
// Does not exist, create a new one
|
|
//
|
|
NewMacro = (MACRO *) malloc (sizeof (MACRO));
|
|
memset ((UINT8 *) NewMacro, 0, sizeof (MACRO));
|
|
NewMacro->Name = MacroString;
|
|
NewMacro->Value = Value;
|
|
|
|
//
|
|
// Add it to the head of the list.
|
|
//
|
|
NewMacro->Next = mGlobals.MacroList;
|
|
mGlobals.MacroList = NewMacro;
|
|
|
|
return;
|
|
}
|
|
|
|
static
|
|
UINT8 *
|
|
GetMacroValue (
|
|
UINT8 *MacroName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look up a macro.
|
|
|
|
Arguments:
|
|
|
|
MacroName - The name of macro
|
|
|
|
Returns:
|
|
|
|
Pointer to the value of the macro if found
|
|
NULL if the macro is not found
|
|
|
|
--*/
|
|
{
|
|
|
|
MACRO *Macro;
|
|
UINT8 *Value;
|
|
|
|
//
|
|
// Scan for macro
|
|
//
|
|
Macro = mGlobals.MacroList;
|
|
while (Macro) {
|
|
if (_strcmpi (MacroName, Macro->Name) == 0) {
|
|
return Macro->Value;
|
|
}
|
|
Macro = Macro->Next;
|
|
}
|
|
|
|
//
|
|
// Try environment variable
|
|
//
|
|
Value = getenv (MacroName);
|
|
if (Value == NULL) {
|
|
printf ("Environment variable %s not found!\n", MacroName);
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
static
|
|
void
|
|
FreeMacros (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the macro list.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
MACRO *Macro;
|
|
MACRO *NextMacro;
|
|
|
|
Macro = mGlobals.MacroList;
|
|
while (Macro) {
|
|
NextMacro = Macro->Next;
|
|
free (Macro);
|
|
Macro = NextMacro;
|
|
}
|
|
mGlobals.MacroList = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
static
|
|
STATUS
|
|
ReplaceMacros (
|
|
UINT8 *InputFile,
|
|
UINT8 *OutputFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Replace all the macros in InputFile to create the OutputFile.
|
|
|
|
Arguments:
|
|
|
|
InputFile - Input package file for macro replacement
|
|
OutputFile - Output package file after macro replacement
|
|
|
|
Returns:
|
|
|
|
STATUS_SUCCESS - Output package file is created successfully after the macro replacement.
|
|
STATUS_WARNING - Output package file is not created because of no macro replacement.
|
|
STATUS_ERROR - Some error occurred during execution.
|
|
|
|
--*/
|
|
{
|
|
FILE *Fptr;
|
|
UINT8 *SaveStart;
|
|
UINT8 *FromPtr;
|
|
UINT8 *ToPtr;
|
|
UINT8 *Value;
|
|
UINT8 *FileBuffer;
|
|
UINTN FileSize;
|
|
|
|
//
|
|
// Get the file size, and then read the entire thing into memory.
|
|
// Allocate extra space for a terminator character.
|
|
//
|
|
if ((Fptr = fopen (InputFile, "r")) == NULL) {
|
|
Error (NULL, 0, 0, InputFile, "can't open input file");
|
|
return STATUS_ERROR;
|
|
}
|
|
fseek (Fptr, 0, SEEK_END);
|
|
FileSize = ftell (Fptr);
|
|
fseek (Fptr, 0, SEEK_SET);
|
|
FileBuffer = malloc (FileSize + 1);
|
|
if (FileBuffer == NULL) {
|
|
fclose (Fptr);
|
|
Error (NULL, 0, 0, InputFile, "file buffer memory allocation failure");
|
|
return STATUS_ERROR;
|
|
}
|
|
fread (FileBuffer, FileSize, 1, Fptr);
|
|
FileBuffer[FileSize] = '\0';
|
|
fclose (Fptr);
|
|
|
|
//
|
|
// Walk the entire file, replacing $(MACRO_NAME).
|
|
//
|
|
Fptr = NULL;
|
|
FromPtr = FileBuffer;
|
|
SaveStart = FromPtr;
|
|
while (*FromPtr) {
|
|
if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) {
|
|
FromPtr += 2;
|
|
for (ToPtr = FromPtr; *ToPtr && (*ToPtr != ')'); ToPtr++);
|
|
if (*ToPtr) {
|
|
//
|
|
// Find an $(MACRO_NAME), replace it
|
|
//
|
|
*ToPtr = '\0';
|
|
Value = GetMacroValue (FromPtr);
|
|
*(FromPtr-2)= '\0';
|
|
if (Fptr == NULL) {
|
|
if ((Fptr = fopen (OutputFile, "w")) == NULL) {
|
|
free (FileBuffer);
|
|
Error (NULL, 0, 0, OutputFile, "can't open output file");
|
|
return STATUS_ERROR;
|
|
}
|
|
}
|
|
if (Value != NULL) {
|
|
fprintf (Fptr, "%s%s", SaveStart, Value);
|
|
} else {
|
|
fprintf (Fptr, "%s", SaveStart);
|
|
}
|
|
//
|
|
// Continue macro replacement for the remaining string line
|
|
//
|
|
FromPtr = ToPtr+1;
|
|
SaveStart = FromPtr;
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
FromPtr++;
|
|
}
|
|
}
|
|
if (Fptr != NULL) {
|
|
fprintf (Fptr, "%s", SaveStart);
|
|
}
|
|
|
|
free (FileBuffer);
|
|
if (Fptr != NULL) {
|
|
fclose (Fptr);
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
return STATUS_WARNING;
|
|
}
|
|
}
|