Shenglei Zhang 3c59d94637 BaseTools/FCE: Add a tool FCE
FCE is a tool to retrieve and change HII configuration data in
Firmware Device(*.fd) files.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
2019-07-04 11:34:56 +08:00

6450 lines
198 KiB
C

/** @file
FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
data in Firmware Device files (".fd" files).
Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Fce.h"
#ifndef __GNUC__
#define COPY_STR "copy \"%s\" \"%s\" > NUL"
#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
#define DEL_STR "del \"%s\" > NUL"
#else
#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
#define RMDIR_STR "rm -r \"%s\" > /dev/null"
#define DEL_STR "rm \"%s\" > /dev/null"
#endif
//
// Utility global variables
//
OPERATION_TYPE Operations;
CHAR8 mInputFdName[MAX_FILENAME_LEN];
CHAR8 mOutputFdName[MAX_FILENAME_LEN];
CHAR8 mOutTxtName[MAX_FILENAME_LEN];
CHAR8 mSetupTxtName[MAX_FILENAME_LEN];
CHAR8* mUtilityFilename = NULL;
UINT32 mEfiVariableAddr = 0;
UQI_PARAM_LIST *mUqiList = NULL;
UQI_PARAM_LIST *mLastUqiList = NULL;
LIST_ENTRY mVarListEntry;
LIST_ENTRY mBfvVarListEntry;
LIST_ENTRY mAllVarListEntry;
LIST_ENTRY mFormSetListEntry;
//
// Store GUIDed Section guid->tool mapping
//
EFI_HANDLE mParsedGuidedSectionTools = NULL;
CHAR8* mGuidToolDefinition = "GuidToolDefinitionConf.ini";
//
//gFfsArray is used to store all the FFS informations of Fd
//
G_EFI_FD_INFO gEfiFdInfo;
//
//mMultiPlatformParam is used to store the structures about multi-platform support
//
MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
UINT32 mFormSetOrderRead;
UINT32 mFormSetOrderParse;
CHAR8 mFullGuidToolDefinitionDir[_MAX_PATH];
CHAR8 *mFvNameGuidString = NULL;
/**
Check the revision of BfmLib. If not matched, return an error.
@retval EFI_SUCCESS If revision matched, return EFI_SUCCESS.
@retval EFI_UNSUPPORTED Other cases.
**/
static
EFI_STATUS
CheckBfmLibRevision (
VOID
)
{
CHAR8 *SystemCommandFormatString;
CHAR8 *SystemCommand;
CHAR8 *TempSystemCommand;
CHAR8 *Revision;
FILE *FileHandle;
CHAR8 RevisionStr[_MAX_BUILD_VERSION];
UINT32 Len;
SystemCommandFormatString = NULL;
SystemCommand = NULL;
TempSystemCommand = NULL;
Revision = "Revision.txt";
memset (RevisionStr, 0, _MAX_BUILD_VERSION);
//
// Construction 'system' command string
//
SystemCommandFormatString = "BfmLib -v > %s";
SystemCommand = malloc (
strlen (SystemCommandFormatString) + strlen (Revision) + 1
);
if (SystemCommand == NULL) {
return EFI_UNSUPPORTED;
}
sprintf (
SystemCommand,
"BfmLib -v > %s",
Revision
);
if (mFullGuidToolDefinitionDir[0] != 0) {
TempSystemCommand = SystemCommand;
SystemCommand = malloc (
strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (SystemCommandFormatString) + strlen (Revision) + 1
);
if (SystemCommand == NULL) {
free (TempSystemCommand);
return EFI_UNSUPPORTED;
}
strcpy (SystemCommand, mFullGuidToolDefinitionDir);
strcat (SystemCommand, OS_SEP_STR);
strcat (SystemCommand, TempSystemCommand);
free (TempSystemCommand);
}
system (SystemCommand);
free (SystemCommand);
FileHandle = fopen (Revision, "r");
if (FileHandle == NULL) {
printf ("Error. Read the revision file of BfmLib failed.\n");
return EFI_ABORTED;
}
fgets(RevisionStr, _MAX_BUILD_VERSION, FileHandle);
Len = strlen(RevisionStr);
if (RevisionStr[Len - 1] == '\n') {
RevisionStr[Len - 1] = 0;
}
fclose (FileHandle);
remove (Revision);
if (strlen (RevisionStr) > _MAX_BUILD_VERSION - 1) {
printf ("The revision string is too long");
return EFI_UNSUPPORTED;
}
if (strcmp (RevisionStr, __BUILD_VERSION) == 0) {
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
/**
Transfer the Ascii string to the Dec Number
@param InStr The Ascii string.
@retval DecNum Return the Dec number.
**/
static
UINT64
StrToDec (
IN CHAR8 *InStr
)
{
UINT8 Index;
UINTN DecNum;
UINTN Temp;
Index = 0;
DecNum = 0;
Temp = 0;
if (InStr == NULL) {
return (UINT64)-1;
}
while (Index < strlen (InStr)) {
if ((*(InStr + Index) >= '0') && (*(InStr + Index) <= '9')) {
Temp = *(InStr + Index) - '0';
} else if ((*(InStr + Index) >= 'a') && (*(InStr + Index) <= 'f')) {
Temp = *(InStr + Index) - 'a' + 10;
} else if ((*(InStr + Index) >= 'A') && (*(InStr + Index) <= 'F')) {
Temp = *(InStr + Index) - 'A' + 10;
}
DecNum = DecNum + Temp * (UINTN) pow (16, strlen (InStr) - Index - 1);
Index++;
}
return DecNum;
}
/**
Check whether there are some errors in uqi parameters of One_of
@param Question The pointer to the question Node.
@param UqiValue The value of One_of.
@retval TRUE If existed error, return TRUE;
@return FALSE Otherwise, return FALSE;
**/
static
BOOLEAN
CheckOneOfParamError (
IN CONST FORM_BROWSER_STATEMENT *Question,
IN UINT64 UqiValue
)
{
LIST_ENTRY *Link;
QUESTION_OPTION *Option;
UINT64 Value;
Link = NULL;
Option = NULL;
Value = 0;
Link = GetFirstNode (&Question->OptionListHead);
while (!IsNull (&Question->OptionListHead, Link)) {
Option = QUESTION_OPTION_FROM_LINK (Link);
Value = 0;
CopyMem (&Value, &Option->Value.Value.u64, Question->StorageWidth);
if (Value == UqiValue) {
return FALSE;
}
Link = GetNextNode (&Question->OptionListHead, Link);
}
return TRUE;
}
/**
Check whether there are some errors in uqi parameters of Orderlist
@param HiiObjList The pointer to the Hii Object Node.
@param UqiValue The pointer to the Uqi parameter.
@retval TRUE If existed error, return TRUE;
@return FALSE Otherwise, return FALSE;
**/
static
BOOLEAN
CheckOrderParamError (
IN CONST FORM_BROWSER_STATEMENT *Question,
IN CHAR8 *UqiValue
)
{
UINT8 MaxNum;
MaxNum = UqiValue[0];
if (MaxNum != (UINT8)(Question->MaxContainers)) {
return TRUE;
}
return FALSE;
}
/**
Writes a Unicode string
@param Package A pointer to the Unicode string.
@return NULL
**/
static
VOID
WriteUnicodeStr (
IN CHAR16 *pcString
)
{
UINTN Index;
if (pcString == NULL) {
return;
}
for (Index = 0; pcString[Index] != 0; Index++) {
printf("%c", pcString[Index] & 0x00FF);
}
}
/**
Parse and set the quick configure information by the command line.
Read the UQI Config information from command line directly, and then compare it with the value in VarList.
Update the Update flag in Varlist.
@param CurUqiList The pointer to the current uqi
@param DefaultId The default Id.
@param PlatformId The platform Id.
@param CurQuestion The pointer to the matched question
@retval EFI_SUCCESS It was complete successfully
@retval EFI_UNSUPPORTED Update a read-only value
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
SetUqiParametersWithQuestion (
IN UQI_PARAM_LIST *CurUqiList,
IN UINT16 DefaultId,
IN UINT64 PlatformId,
IN FORM_BROWSER_STATEMENT *CurQuestion
)
{
FORMSET_STORAGE *VarList;
BOOLEAN IsFound;
UINT8 *ValueAddrOfVar;
UINT16 Index;
UINT64 QuestionValue;
UINT64 UqiValue;
EFI_STATUS Status;
CHAR8 *ErrorStr;
FORM_BROWSER_FORMSET *FormSet;
LIST_ENTRY *FormSetLink;
UINT64 CurValue;
VarList = NULL;
Index = 0;
ValueAddrOfVar = NULL;
QuestionValue = 0;
UqiValue = 0;
ErrorStr = NULL;
Status = EFI_SUCCESS;
FormSet = NULL;
FormSetLink = NULL;
CurValue = 0;
//
// Search the Variable List by VarStoreId and Offset
//
IsFound = FALSE;
FormSetLink = GetFirstNode (&mFormSetListEntry);
while (!IsNull (&mFormSetListEntry, FormSetLink)) {
FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
Status = SearchVarStorage (
CurQuestion,
NULL,
CurQuestion->VarStoreInfo.VarOffset,
FormSet->StorageListHead,
(CHAR8 **) &ValueAddrOfVar,
&VarList
);
if (!EFI_ERROR (Status)) {
IsFound = TRUE;
break;
}
FormSetLink = GetNextNode (&mFormSetListEntry, FormSetLink);
}
if (!IsFound) {
if (CurUqiList->Header.ScriptsLine == 0) {
printf ("Error. The question in the command line doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n");
} else {
printf ("Error. The question in the line %d of script doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n", CurUqiList->Header.ScriptsLine);
}
return EFI_ABORTED;
}
//
// Check the length of variable value
//
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)&QuestionValue);
} else {
switch (CurQuestion->StorageWidth) {
case sizeof (UINT8):
QuestionValue = *(UINT8 *)ValueAddrOfVar;
break;
case sizeof (UINT16):
QuestionValue = *(UINT16 *)ValueAddrOfVar;
break;
case sizeof (UINT32):
QuestionValue = *(UINT32 *)ValueAddrOfVar;
break;
case sizeof (UINT64):
QuestionValue = *(UINT64 *)ValueAddrOfVar;
break;
default:
//
// The storage width of ORDERED_LIST may not be any type above.
//
;
break;
}
}
UqiValue = *(UINT64 *)CurUqiList->Header.Value;
CurUqiList->SameOrNot = TRUE;
//
// Check and set the checkbox value
//
if (CurQuestion->Operand == EFI_IFR_CHECKBOX_OP) {
if ((UqiValue != 0) && (UqiValue != 1)) {
CurUqiList->ErrorOrNot = TRUE;
CurUqiList->SameOrNot = FALSE;
CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
if (CurUqiList->Error == NULL) {
printf ("Fail to allocate memory!\n");
return EFI_ABORTED;
}
memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
sprintf (CurUqiList->Error, "Error. The updated value of CHECKBOX 0x%llx is invalid.\n", (unsigned long long) UqiValue);
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
} else {
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
}
} else {
if (QuestionValue != UqiValue) {
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
} else {
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
memcpy (
ValueAddrOfVar,
CurUqiList->Header.Value,
CurQuestion->StorageWidth
);
}
CurUqiList->SameOrNot = FALSE;
}
}
}
if (CurQuestion->Operand == EFI_IFR_STRING_OP) {
if ((FceStrLen((wchar_t *)CurUqiList->Header.Value) + 1) * 2 > CurQuestion->StorageWidth) {
CurUqiList->ErrorOrNot = TRUE;
CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
if (CurUqiList->Error == NULL) {
printf ("Fail to allocate memory!\n");
return EFI_ABORTED;
}
memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
sprintf (CurUqiList->Error, "Error. The updated value of STRING exceed its Size.\n");
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
} else {
if (memcmp((CHAR8 *)CurUqiList->Header.Value, ValueAddrOfVar, CurQuestion->StorageWidth) != 0) {
memcpy(
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
memcpy(
ValueAddrOfVar,
CurUqiList->Header.Value,
CurQuestion->StorageWidth
);
CurUqiList->SameOrNot = FALSE;
}
}
}
//
// Check and set the NUMERIC value
//
if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
if ((UqiValue < CurQuestion->Minimum) || (UqiValue > CurQuestion->Maximum)) {
CurUqiList->ErrorOrNot = TRUE;
CurUqiList->SameOrNot = FALSE;
CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
if (CurUqiList->Error == NULL) {
printf ("Fail to allocate memory!\n");
return EFI_ABORTED;
}
memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
sprintf (CurUqiList->Error, "Error. The updated value of NUMERIC 0x%llx is invalid.\n", (unsigned long long) UqiValue);
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
} else {
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
}
} else {
if (QuestionValue != UqiValue) {
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
} else {
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
memcpy (
ValueAddrOfVar,
CurUqiList->Header.Value,
CurQuestion->StorageWidth
);
}
CurUqiList->SameOrNot = FALSE;
}
}
}
//
// Check and set the ONE_OF value
//
if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
if (CheckOneOfParamError (CurQuestion, UqiValue)) {
CurUqiList->ErrorOrNot = TRUE;
CurUqiList->SameOrNot = FALSE;
CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
if (CurUqiList->Error == NULL) {
printf ("Fail to allocate memory!\n");
return EFI_ABORTED;
}
memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
sprintf (CurUqiList->Error, "Error. The updated ONE_OF value 0x%llx is invalid.\n", (unsigned long long) UqiValue);
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
} else {
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
}
} else {
if (QuestionValue != UqiValue) {
if (CurQuestion->QuestionReferToBitField) {
GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
} else {
memcpy (
CurUqiList->Header.DiffValue,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
memcpy (
ValueAddrOfVar,
CurUqiList->Header.Value,
CurQuestion->StorageWidth
);
}
CurUqiList->SameOrNot = FALSE;
}
}
}
//
// Check and set the ORDER_LIST value
//
if (CurQuestion->Operand == EFI_IFR_ORDERED_LIST_OP) {
//
// Synchronize the MaxContainers value
//
*CurUqiList->Header.DiffValue = (UINT8)CurQuestion->MaxContainers;
if (CheckOrderParamError (CurQuestion, (CHAR8 *)CurUqiList->Header.Value)) {
CurUqiList->ErrorOrNot = TRUE;
CurUqiList->SameOrNot = FALSE;
CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
if (CurUqiList->Error == NULL) {
printf ("Fail to allocate memory!\n");
return EFI_ABORTED;
}
memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
ErrorStr = CurUqiList->Error;
sprintf (ErrorStr, "Error. The updated NORDERED_LIST value ");
ErrorStr = ErrorStr + strlen ("Error. The updated NORDERED_LIST value ");
for (Index = 0; Index < CurQuestion->StorageWidth; Index++) {
sprintf (ErrorStr, "%02x ", *(CurUqiList->Header.Value + Index + 1));
ErrorStr +=3;
}
sprintf (ErrorStr, "is invalid.\n");
memcpy (
CurUqiList->Header.DiffValue + 1,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
} else {
for (Index = 0; Index < CurQuestion->StorageWidth/CurQuestion->MaxContainers; Index++) {
CurValue = 0;
memcpy (
&CurValue,
(ValueAddrOfVar + Index * CurQuestion->StorageWidth/CurQuestion->MaxContainers),
CurQuestion->StorageWidth/CurQuestion->MaxContainers
);
if (CurValue != *((UINT64 *)CurUqiList->Header.Value + Index + 1)) {
CurUqiList->SameOrNot = FALSE;
break;
}
}
if (!CurUqiList->SameOrNot) {
memcpy (
CurUqiList->Header.DiffValue + 1,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
for (Index = 0; Index < CurQuestion->MaxContainers; Index++) {
switch (CurQuestion->StorageWidth/CurQuestion->MaxContainers) {
case sizeof (UINT8):
*((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
break;
case sizeof (UINT16):
*((UINT16 *)ValueAddrOfVar + Index) = *(UINT16 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
break;
case sizeof (UINT32):
*((UINT32 *)ValueAddrOfVar + Index) = *(UINT32 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
break;
case sizeof (UINT64):
*((UINT64 *)ValueAddrOfVar + Index) = *((UINT64 *)CurUqiList->Header.Value + 1 + Index);
break;
default:
*((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
break;
}
}
//
// Update the vaule of ORDERED_LIST according to its size
//
CurUqiList->Header.Value = (UINT8 *)((UINT64 *)CurUqiList->Header.Value);
memcpy (
CurUqiList->Header.Value + 1,
ValueAddrOfVar,
CurQuestion->StorageWidth
);
}
}
}
return EFI_SUCCESS;
}
/**
Parse and set the quick configure information by the command line.
Read the UQI Config information from command line directly, and then compare it with the value in VarList.
Update the Update flag in Varlist.
@param UqiList The pointer to the uqi list
@param DefaultId The default Id.
@param PlatformId The platform Id.
@retval EFI_SUCCESS It was complete successfully
@retval EFI_UNSUPPORTED Update a read-only value
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
SetUqiParameters (
IN UQI_PARAM_LIST *UqiList,
IN UINT16 DefaultId,
IN UINT64 PlatformId
)
{
FORM_BROWSER_FORMSET *FormSet;
LIST_ENTRY *FormSetLink;
FORM_BROWSER_FORM *Form;
LIST_ENTRY *FormLink;
FORM_BROWSER_STATEMENT *Question;
LIST_ENTRY *QuestionLink;
LIST_ENTRY *FormSetEntryListHead;
UQI_PARAM_LIST *CurUqiList;
FormSet = NULL;
FormSetLink = NULL;
Form = NULL;
FormLink = NULL;
Question = NULL;
QuestionLink = NULL;
FormSetEntryListHead = &mFormSetListEntry;
FormSetLink = GetFirstNode (FormSetEntryListHead);
while (!IsNull (FormSetEntryListHead, FormSetLink)) {
FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
//
// Parse all forms in formset
//
FormLink = GetFirstNode (&FormSet->FormListHead);
while (!IsNull (&FormSet->FormListHead, FormLink)) {
Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
//
// Parse five kinds of Questions in Form
//
QuestionLink = GetFirstNode (&Form->StatementListHead);
while (!IsNull (&Form->StatementListHead, QuestionLink)) {
Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
//
// Parse five kinds of Questions in Form
//
if ((Question->Operand == EFI_IFR_ONE_OF_OP)
|| (Question->Operand == EFI_IFR_NUMERIC_OP)
|| (Question->Operand == EFI_IFR_CHECKBOX_OP)
|| (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
|| (Question->Operand == EFI_IFR_STRING_OP)
) {
if (mMultiPlatformParam.MultiPlatformOrNot) {
//
// Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
//
if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
continue;
}
if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
&& Question->NewEfiVarstore
&& ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
continue;
}
}
CurUqiList = UqiList;
while (CurUqiList != NULL) {
if ((PlatformId == CurUqiList->Header.PlatformId[0])
&& (DefaultId == CurUqiList->Header.DefaultId[0])
&& CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
) {
//
// Add further check to avoid a case that there are many options with a
// same UQI (en-Us), but always returns the first one.
//
if (!CurUqiList->ParseOrNot) {
CurUqiList->ParseOrNot = TRUE;
break;
}
}
CurUqiList = CurUqiList->Next;
}
if (CurUqiList != NULL) {
SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, Question);
}
}
}
FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
}
FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
}
return EFI_SUCCESS;
}
/**
Set question value per UqiList.
@param UqiList The pointer to the uqi list
@param DefaultId The default Id.
@param PlatformId The platform Id.
**/
VOID
SetUqiParametersMultiMode (
IN UQI_PARAM_LIST *UqiList,
IN UINT16 DefaultId,
IN UINT64 PlatformId
)
{
UQI_PARAM_LIST *CurUqiList;
CurUqiList = UqiList;
while (CurUqiList != NULL) {
if ((CurUqiList->ParseOrNot == FALSE)
&& (PlatformId == CurUqiList->Header.PlatformId[0])
&& (DefaultId == CurUqiList->Header.DefaultId[0])
) {
CurUqiList->ParseOrNot = TRUE;
if (CurUqiList->Header.Question != NULL) {
SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, CurUqiList->Header.Question);
}
}
CurUqiList = CurUqiList->Next;
}
}
/**
Find the matched question for each UQI string in UqiList
**/
EFI_STATUS
ScanUqiFullList (
IN UQI_PARAM_LIST *UqiList
)
{
FORM_BROWSER_FORMSET *FormSet;
LIST_ENTRY *FormSetLink;
FORM_BROWSER_FORM *Form;
LIST_ENTRY *FormLink;
FORM_BROWSER_STATEMENT *Question;
LIST_ENTRY *QuestionLink;
LIST_ENTRY *FormSetEntryListHead;
UQI_PARAM_LIST *CurUqiList;
UINT64 PlatformId;
UINT16 DefaultId;
if (UqiList == NULL) {
return EFI_SUCCESS;
}
FormSet = NULL;
FormSetLink = NULL;
Form = NULL;
FormLink = NULL;
Question = NULL;
QuestionLink = NULL;
FormSetEntryListHead = &mFormSetListEntry;
FormSetLink = FormSetEntryListHead->ForwardLink;
while (FormSetEntryListHead != FormSetLink) {
FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
//
// Parse all forms in formset
//
FormLink = FormSet->FormListHead.ForwardLink;
while (&FormSet->FormListHead != FormLink) {
Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
//
// Parse five kinds of Questions in Form
//
QuestionLink = Form->StatementListHead.ForwardLink;
while (&Form->StatementListHead != QuestionLink) {
Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
QuestionLink = QuestionLink->ForwardLink;
//
// Parse five kinds of Questions in Form
//
if ((Question->Operand == EFI_IFR_ONE_OF_OP)
|| (Question->Operand == EFI_IFR_NUMERIC_OP)
|| (Question->Operand == EFI_IFR_CHECKBOX_OP)
|| (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
|| (Question->Operand == EFI_IFR_STRING_OP)
) {
//
// Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
//
if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
continue;
} else if (Question->NewEfiVarstore
&& ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
continue;
}
CurUqiList = UqiList;
PlatformId = 0xFFFFFFFF;
DefaultId = 0xFFFF;
while (CurUqiList != NULL) {
if ((CurUqiList->Header.Question == NULL)
&& CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
&& ((PlatformId != CurUqiList->Header.PlatformId[0]) || (DefaultId != CurUqiList->Header.DefaultId[0]))
) {
CurUqiList->Header.Question = Question;
PlatformId = CurUqiList->Header.PlatformId[0];
DefaultId = CurUqiList->Header.DefaultId[0];
}
CurUqiList = CurUqiList->Next;
}
}
}
FormLink = FormLink->ForwardLink;
}
FormSetLink = FormSetLink->ForwardLink;
}
return EFI_SUCCESS;
}
/**
Create and insert the UQI Node to the UQI parameter list.
@retval Node address If successed, return the node address.
@retval NULL An error occurred.
**/
static
UQI_PARAM_LIST *
CreateInsertUqiNode (
)
{
UQI_PARAM_LIST *Node;
Node = (UQI_PARAM_LIST *) malloc (sizeof (UQI_PARAM_LIST));
if (Node == NULL) {
return NULL;
}
memset (Node, 0, sizeof (UQI_PARAM_LIST));
if (mUqiList == NULL) {
mUqiList = Node;
} else {
mLastUqiList->Next = Node;
}
mLastUqiList = Node;
return Node;
}
/**
Parse the first part of QUI string
@param **argv[] The dual array pointer to the parameters.
@param Number The pointer to the number of the first character of UQI.
@param Buffer The buffer to store the first part of UQI.
@retval EFI_SUCCESS Parse the QUI parameters successfully.
@retval EFI_INVALID_PARAMETER An error occurred.
**/
static
EFI_STATUS
ParseFirstpartOfUqi (
IN CHAR8 **argv[],
OUT UINT32 *Number,
OUT UINT16 **Buffer
)
{
UINT32 Index;
Index = 0;
*Number = (UINT32)StrToDec ((*argv)[0]);
if ((*Number <= 0) || (*Number > MAX_QUI_PARAM_LEN)) {
printf ("Error. Invalid UQI.\n");
return EFI_INVALID_PARAMETER;
}
*Buffer = malloc ((*Number + 1) * sizeof (CHAR16));
assert (*Buffer != NULL);
memset (*Buffer, 0, (*Number + 1) * sizeof (CHAR16));
for (Index = 0; Index < *Number; Index++) {
if (StrToDec ((*argv)[Index]) > 0xff) {
printf ("Error. Invalid UQI.\n");
return EFI_INVALID_PARAMETER;
}
*(*Buffer + Index) = (UINT16)StrToDec ((*argv)[Index + 1]);
}
return EFI_SUCCESS;
}
/**
Parse the QUI input parameters from the command line
@param argc The pointer to the number of input parameters.
@param **argv[] The dual array pointer to the parameters.
@retval EFI_SUCCESS Parse the QUI parameters successfully.
@retval EFI_INVALID_PARAMETER An error occurred.
**/
static
EFI_STATUS
ParseUqiParam (
IN UINT32 *argc,
IN CHAR8 **argv[]
)
{
UINT32 Index;
UQI_PARAM_LIST *UqiNode;
EFI_STATUS Status;
Index = 0;
UqiNode = NULL;
if (*argc < 4) {
printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
return EFI_INVALID_PARAMETER;
}
UqiNode = CreateInsertUqiNode ();
assert (UqiNode != NULL);
UqiNode->Header.DefaultId = (UINT16 *) calloc (1, sizeof (UINT16));
UqiNode->Header.PlatformId = (UINT64 *) calloc (1, sizeof (UINT64));
Status = ParseFirstpartOfUqi (argv, &(UqiNode->Header.HexNum), &(UqiNode->Header.Data));
if (EFI_ERROR (Status)) {
return Status;
}
*argc -= (UqiNode->Header.HexNum + 1);
*argv += UqiNode->Header.HexNum + 1;
//
// Parse the TYPE and value
//
if (strcmp ("ONE_OF", (*argv)[0]) == 0) {
UqiNode->Header.Type = ONE_OF;
} else if (strcmp ("NUMERIC", (*argv)[0]) == 0) {
UqiNode->Header.Type = NUMERIC;
} else if (strcmp ("CHECKBOX", (*argv)[0]) == 0) {
UqiNode->Header.Type = CHECKBOX;
} else if (strcmp ("STRING", (*argv)[0]) == 0) {
UqiNode->Header.Type = STRING;
} else if (strcmp ("ORDERED_LIST", (*argv)[0]) == 0) {
UqiNode->Header.Type = ORDERED_LIST;
} else {
printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
return EFI_INVALID_PARAMETER;
}
*argc -= 1;
*argv += 1;
//
// Get the value according to the type of questions.
//
switch (UqiNode->Header.Type) {
case ONE_OF:
case NUMERIC:
case CHECKBOX:
UqiNode->Header.Value = malloc (sizeof (UINT64));
if (UqiNode->Header.Value == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
memset (UqiNode->Header.Value, 0, sizeof (UINT64));
UqiNode->Header.DiffValue = malloc (sizeof (UINT64));
if (UqiNode->Header.DiffValue == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
memset (
UqiNode->Header.DiffValue,
0,
sizeof (UINT64)
);
*(UINT64 *)(UqiNode->Header.Value) = (UINT64)StrToDec ((*argv)[0]);
break;
case ORDERED_LIST:
UqiNode->Header.Value = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
if (UqiNode->Header.Value == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
memset (
UqiNode->Header.Value,
0,
(UINTN)StrToDec(((*argv)[0]) + 1) * sizeof (UINT64)
);
UqiNode->Header.DiffValue = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
if (UqiNode->Header.DiffValue == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
memset (
UqiNode->Header.DiffValue,
0,
(UINTN)(StrToDec ((*argv)[0]) + 1) * sizeof (UINT64)
);
*UqiNode->Header.Value = (UINT8)StrToDec ((*argv)[0]);
for (Index = 1; Index <= StrToDec ((*argv)[0]); Index++) {
*((UINT64 *)UqiNode->Header.Value + Index) = StrToDec ((*argv)[Index]);
}
*argc -= (UINTN)StrToDec ((*argv)[0]);
*argv += (UINTN)StrToDec ((*argv)[0]);
break;
default:
break;
}
*argc -= 1;
*argv += 1;
if (*argc > 0) {
printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Parse the input Fd file, and get the file name according to the FILETYPE.
@param FdName The Name of Fd file
@param FILETYPE The type of Fd file
@return EFI_SUCCESS Get the file name successfully
@return EFI_ABORTED An error occurred.
**/
static
EFI_STATUS
ParseInFile (
IN CHAR8 *FdName,
IN FILETYPE Type
)
{
FILE *Fptr;
Fptr = NULL;
if ((Type == INFD) && ((FdName == NULL) || (Fptr = fopen (FdName, "r")) == NULL)) {
if (FdName != NULL) {
printf ("Error: The <infd> file doesn't exist '%s'\n", FdName);
}
return EFI_ABORTED;
}
if ((Type == OUTFD) && (FdName == NULL) ) {
printf ("Error: The <Outfd> name is NULL.\n");
return EFI_ABORTED;
}
if ((Type == SETUPTXT) && (FdName == NULL) ) {
printf ("Error: The <script> name is NULL.\n");
return EFI_ABORTED;
}
if (strlen (FdName) > MAX_FILENAME_LEN - 1) {
printf ("Error: The <fd> name is too long.\n");
if (Fptr != NULL) {
fclose (Fptr);
}
return EFI_ABORTED;
}
//
// Get and copy the file name
//
if (Type == INFD) {
strncpy (mInputFdName, FdName, MAX_FILENAME_LEN - 1);
mInputFdName[MAX_FILENAME_LEN - 1] = 0;
}
if (Type == OUTFD) {
strncpy (mOutputFdName, FdName, MAX_FILENAME_LEN - 1);
mOutputFdName[MAX_FILENAME_LEN - 1] = 0;
}
if (Type == OUTTXT) {
strncpy (mOutTxtName, FdName, MAX_FILENAME_LEN - 1);
mOutTxtName[MAX_FILENAME_LEN - 1] = 0;
}
if (Type == SETUPTXT) {
strncpy (mSetupTxtName, FdName, MAX_FILENAME_LEN - 1);
mSetupTxtName[MAX_FILENAME_LEN - 1] = 0;
}
if (Fptr != NULL) {
fclose (Fptr);
}
return EFI_SUCCESS;
}
/**
Print the usage of this tools.
@return NULL
**/
static
VOID
Usage (
VOID
)
{
//
// Print utility header
//
printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
UTILITY_NAME,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION,
__BUILD_VERSION
);
//
// Copyright declaration
//
fprintf (stdout, "Copyright (c) 2010-2018, Intel Corporation. All rights reserved.\n\n");
//
// Summary usage
//
fprintf (stdout, "The tool enables you to retrieve and change HII configuration (Setup) data in \n");
fprintf (stdout, "Firmware Device files.\n");
fprintf (stdout, "\nUsage: \n");
fprintf (stdout, " FCE [read -i <infd> [<PlatformId UQI>] ['>' <script>]] \n");
fprintf (stdout, " FCE [update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>\n");
fprintf (stdout, " [--remove|--ignore] [-g <FvNameGuid>]] [-a]\n");
fprintf (stdout, " FCE [verify -i <infd> -s <script>] \n");
fprintf (stdout, " FCE [updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>] \n");
fprintf (stdout, " FCE [[help] | [-?]] \n");
fprintf (stdout, "\n");
fprintf (stdout, "Options:\n");
fprintf (stdout, " read Extract the HII data from the <infd> file. \n");
fprintf (stdout, " update Update the HII data to the <outfd> file. \n");
fprintf (stdout, " verify Verify the current platform configuration. \n");
fprintf (stdout, " updateq Update the current platform configuration by command line.\n");
fprintf (stdout, " updateq only supports common mode.\n");
fprintf (stdout, " help Display the help information.\n");
fprintf (stdout, " <infd> The name of a existing Firmware Device binary file input. \n");
fprintf (stdout, " <PlatformId UQI> The UQI is required in multi-platform mode to represent a \n");
fprintf (stdout, " PlatformId question from the VFR files used during binary \n");
fprintf (stdout, " image creation. It must not be used for common mode. \n");
fprintf (stdout, " <outfd> The name of a Firmware Device binary file output. \n");
fprintf (stdout, " <script> The name of a configure scripts.\n");
fprintf (stdout, " <UQI> A hex number followed by an array of hex numbers. \n");
fprintf (stdout, " <Question Type> One of ORDERED_LIST, ONE_OF, NUMERIC, STRING or CHECKBOX. \n");
fprintf (stdout, " <Value> A single hex number, if the <Question Type> is ONE_OF,\n");
fprintf (stdout, " NUMERIC, or CHECKBOX. Or a single hex number containing \n");
fprintf (stdout, " the array size followed by an array of that length of hex\n");
fprintf (stdout, " numbers, if the <Question Type> is ORDERED_LIST. \n");
fprintf (stdout, " <FvNameGuid> GuidValue is one specific FvName guid value.\n");
fprintf (stdout, " Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.\n");
fprintf (stdout, " -i Import an existing FD file <infd>. \n");
fprintf (stdout, " -o Create the new FD with the changes made. \n");
fprintf (stdout, " -s Import config scripts. \n");
fprintf (stdout, " > Redirect the output to a scripts. \n");
fprintf (stdout, " -? Display the help information. \n");
fprintf (stdout, " --remove If one or more of the settings that are updated also \n");
fprintf (stdout, " exists in NV RAM, remove them only in multi-platform mode.\n");
fprintf (stdout, " --ignore If one or more of the settings that are updated also \n");
fprintf (stdout, " existsin NV RAM, ignore them only in multi-platform mode.\n");
fprintf (stdout, " -g Specify the FV image to store the multi-platform default \n");
fprintf (stdout, " setting. If it is missing, the multi-platform default \n");
fprintf (stdout, " will be inserted into BFV image.\n");
fprintf (stdout, " -a Specify this tool to choose the smaller size between two \n");
fprintf (stdout, " different storage formats in NV RAM. It's only vaild in \n");
fprintf (stdout, " multi-platform mode. \n");
fprintf (stdout, "\n");
fprintf (stdout, "Mode:\n");
fprintf (stdout, " Common Extract the HII data from IFR binary and update it to the \n");
fprintf (stdout, " EFI variable. \n");
fprintf (stdout, " Multi-platform The default value depends on the PlatformId and DefaultId \n");
fprintf (stdout, " described in the VFR files. This tool will create the \n");
fprintf (stdout, " binary file to store default settings at build time for \n");
fprintf (stdout, " different platforms and modes adding all default settings \n");
fprintf (stdout, " into BFV as one FFS.\n");
fprintf (stdout, "\n");
}
/**
Parse the command line parameters
@param argc The pointer to number of input parameters.
@param *argv[] The pointer to the parameters.
@retval EFI_SUCCESS Parse the parameters successfully.
@retval EFI_INVALID_PARAMETER An error occurred.
**/
static
EFI_STATUS
ParseCommmadLine (
IN UINTN argc,
IN CHAR8 *argv[]
)
{
EFI_STATUS Status;
UINT8 Index;
UINT8 IndexParamI;
UINT8 IndexParamS;
UINT8 IndexParamO;
UINT8 IndexParamRemove;
UINT8 IndexParamIgnore;
UINT8 IndexParamOptimize;
EFI_GUID FvNameGuid;
Status = EFI_SUCCESS;
Index = 0;
IndexParamI = 0;
IndexParamO = 0;
IndexParamS = 0;
IndexParamRemove = 0;
IndexParamIgnore = 0;
IndexParamOptimize = 0;
mMultiPlatformParam.SizeOptimizedParam = FALSE;
//
// Check for only own one operations
//
if (argc == 0) {
Usage ();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
if (
argc == 1 \
&& ((stricmp(argv[0], "read") == 0) \
|| (stricmp(argv[0], "update") == 0) \
|| (stricmp(argv[0], "updateq") == 0) \
|| (stricmp(argv[0], "verify") == 0) )
) {
printf ("Error: Some parameters have been lost. Please correct. \n");
Usage ();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
while (argc > 0) {
if (stricmp(argv[0], "read") == 0) {
Operations = READ;
argc--;
argv++;
if (argc < 2) {
printf ("Error. The correct command is 'FCE read -i <infd>'. \n");
Usage ();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
//
// Get input FD file name.
//
if (stricmp (argv[0], "-i") == 0) {
Status = ParseInFile (argv[1], INFD);
if (EFI_ERROR (Status)) {
goto Done;
}
argc -= 2;
argv += 2;
}
//
// Parse the QUI parameters
//
if (argc > 2) {
Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
mMultiPlatformParam.MultiPlatformOrNot = TRUE;
if (EFI_ERROR (Status)) {
goto Done;
}
}
break;
} else if (stricmp(argv[0], "update") == 0) {
//
// Update the config file to Fd
//
Operations = UPDATE;
argc--;
argv++;
if (argc < 4) {
printf ("Error. The correct command is 'FCE update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>' \n");
Usage ();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
continue;
} else if (stricmp(argv[0], "verify") == 0) {
//
// 3. Parse the command line "FCE verify -i <infd> -s <script>"
//
Operations = VERIFY;
argc--;
argv++;
if (argc < 4) {
printf ("Error. The correct command is 'FCE verify -i <infd> -s <script>'\n");
Usage ();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
continue;
} else if (stricmp(argv[0], "updateq") == 0) {
//
// Parse the command line "FCE updateq -i <infd> -o<outfd> <UQI> <Question Type> <Value>"
//
argc--;
argv++;
//
// Get input/output FD file name.
//
Index = 2;
while ((Index > 0) && (argc > 1)) {
if (stricmp (argv[0], "-i") == 0) {
Status = ParseInFile (argv[1], INFD);
if (EFI_ERROR (Status)) {
goto Done;
}
argc -= 2;
argv += 2;
Index--;
IndexParamI++;
continue;
}
if (stricmp (argv[0], "-o") == 0) {
Status = ParseInFile (argv[1], OUTFD);
if (EFI_ERROR (Status)) {
goto Done;
}
argc -= 2;
argv += 2;
Index--;
IndexParamO++;
continue;
}
if (
(argc >= 1) \
&& (stricmp(argv[0], "-o") != 0) \
&& (stricmp(argv[0], "-i") != 0)
) {
printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
Usage();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
}
if (Index != 0) {
printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
Usage ();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
//
// Parse the QUI parameters
//
Status = ParseUqiParam ((UINT32 *)&argc,&argv);
if (EFI_ERROR (Status)) {
goto Done;
}
Operations = UPDATEQ;
break;
}
if (stricmp (argv[0], "-i") == 0) {
Status = ParseInFile (argv[1], INFD);
if (EFI_ERROR (Status)) {
goto Done;
}
argc -= 2;
argv += 2;
IndexParamI++;
continue;
}
if (stricmp (argv[0], "-o") == 0) {
Status = ParseInFile (argv[1], OUTFD);
if (EFI_ERROR (Status)) {
goto Done;
}
argc -= 2;
argv += 2;
IndexParamO++;
continue;
}
if (stricmp (argv[0], "-s") == 0) {
Status = ParseInFile (argv[1], SETUPTXT);
if (EFI_ERROR (Status)) {
goto Done;
}
argc -= 2;
argv += 2;
IndexParamS++;
continue;
}
if (stricmp (argv[0], "-g") == 0) {
Status = StringToGuid (argv[1], &FvNameGuid);
if (EFI_ERROR (Status)) {
printf ("Error: Invalid parameters for -g option in command line. \n");
Usage();
goto Done;
}
mFvNameGuidString = argv[1];
argc -= 2;
argv += 2;
continue;
}
if (stricmp (argv[0], "-a") == 0) {
argc -= 1;
argv += 1;
IndexParamOptimize++;
mMultiPlatformParam.SizeOptimizedParam = TRUE;
continue;
}
if (stricmp (argv[0], "--remove") == 0) {
argc -= 1;
argv += 1;
IndexParamRemove++;
Operations = UPDATE_REMOVE;
continue;
}
if (stricmp (argv[0], "--ignore") == 0) {
argc -= 1;
argv += 1;
IndexParamIgnore++;
Operations = UPDATE_IGNORE;
continue;
}
if ((stricmp(argv[0], "help") == 0) || (stricmp(argv[0], "-?") == 0)) {
Usage();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
//
// Operations should not be none
//
if ( Operations == NONE ) {
printf ("Error. Only support read/update/verify/updateq mode. \n");
Usage();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
if (Operations == UPDATE) {
Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
if (!EFI_ERROR (Status)) {
mMultiPlatformParam.MultiPlatformOrNot = TRUE;
argc = argc - mMultiPlatformParam.Uqi.HexNum - 1;
argv = argv + mMultiPlatformParam.Uqi.HexNum + 1;
continue;
}
}
if (
(argc >= 1) \
&& (stricmp(argv[0], "-?") != 0)
&& (stricmp(argv[0], "help") != 0)
&& (stricmp(argv[0], "verify") != 0)
&& (stricmp(argv[0], "read") != 0)
&& (stricmp(argv[0], "update") != 0)
&& (stricmp(argv[0], "updateq") != 0)
&& (stricmp(argv[0], "-o") != 0)
&& (stricmp(argv[0], "-i") != 0)
&& (stricmp(argv[0], "-s") != 0)
&& (stricmp(argv[0], "-a") != 0)
&& (stricmp(argv[0], "-g") != 0)
&& (stricmp(argv[0], "--remove") != 0)
&& (stricmp(argv[0], "--ignore") != 0)
) {
printf ("Error: Invalid parameters exist in command line. \n");
Usage();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
}
//
// Check the repeated parameters in command line, such as "-i -i"
//
if (
(IndexParamI > 1)
|| (IndexParamO > 1)
|| (IndexParamS > 1)
|| (IndexParamOptimize > 1)
|| (IndexParamRemove > 1)
|| (IndexParamIgnore > 1)
) {
printf ("Error: Redundant parameters exist in command line.\n");
Usage();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
//
// Check improper parameters in command line, such as "FCE read -i -s"
//
if (
((Operations == READ) && ((IndexParamO >= 1) || (IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
|| ((Operations == VERIFY) && ((IndexParamO >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
|| ((Operations == UPDATEQ) && ((IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
|| ((Operations == UPDATE) && ((IndexParamRemove >= 1) && (IndexParamIgnore >= 1)))
|| ((Operations != UPDATE && Operations != UPDATE_REMOVE && Operations != UPDATE_IGNORE) && ((IndexParamOptimize >= 1) || (mFvNameGuidString != NULL)))
) {
printf ("Error: Improper parameters exist in command line. \n");
Usage();
Status = EFI_INVALID_PARAMETER;
goto Done;
}
Done:
return Status;
}
/**
Check whether exists the valid variables in NvStorage or not.
@retval TRUE If existed, return TRUE.
@retval FALSE Others
**/
static
BOOLEAN
ExistEfiVarOrNot (
IN LIST_ENTRY *StorageListHead
)
{
EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
BOOLEAN Existed;
VOID *VariableStoreHeader;
BOOLEAN AuthencitatedMonotonicOrNot;
BOOLEAN AuthencitatedBasedTimeOrNot;
VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
AuthencitatedMonotonicOrNot = FALSE;
AuthencitatedBasedTimeOrNot = FALSE;
Existed = TRUE;
//
// Judge the layout of NV by gEfiVariableGuid
//
AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
if (AuthencitatedMonotonicOrNot) {
//
// Check the Monotonic based authenticate variable
//
Existed = ExistMonotonicBasedEfiVarOrNot (StorageListHead);
} else if (AuthencitatedBasedTimeOrNot){
//
// Check the Time Sample authenticate variable
//
Existed = ExistTimeBasedEfiVarOrNot (StorageListHead);
} else {
//
// Check the normal variable
//
Existed = ExistNormalEfiVarOrNot (StorageListHead);
}
return Existed;
}
/**
Exchange the data between Efi variable and the data of VarList
If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
update the data from varlist to efi variable.
@param VarToList The flag to control the direction of exchange.
@param StorageListHead Decide which variale list be updated
@retval EFI_SUCCESS Get the address successfully.
**/
static
EFI_STATUS
EfiVarAndListExchange (
IN BOOLEAN VarToList,
IN LIST_ENTRY *StorageListHead
)
{
EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
EFI_STATUS Status;
VOID *VariableStoreHeader;
BOOLEAN AuthencitatedMonotonicOrNot;
BOOLEAN AuthencitatedBasedTimeOrNot;
Status = EFI_ABORTED;
VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
AuthencitatedMonotonicOrNot = FALSE;
AuthencitatedBasedTimeOrNot = FALSE;
//
// Judge the layout of NV by gEfiVariableGuid
//
AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
if (AuthencitatedMonotonicOrNot) {
//
// Update the Monotonic based authenticate variable
//
Status = SynAuthEfiVariable (VarToList, StorageListHead);
} else if (AuthencitatedBasedTimeOrNot){
//
// Update the Time Sample authenticate variable
//
Status = SynAuthEfiVariableBasedTime (VarToList, StorageListHead);
} else {
//
// Update the normal variable
//
Status = SynEfiVariable (VarToList, StorageListHead);
}
return Status;
}
/**
Check the layout of NvStorage and remove the variable from Efi variable
Found the variable with the same name in StorageListHead and remove it.
@param StorageListHead Decide which variale list be removed.
@retval EFI_SUCCESS Remove the variables successfully.
**/
static
EFI_STATUS
RemoveEfiVar (
IN LIST_ENTRY *StorageListHead
)
{
EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
EFI_STATUS Status;
VOID *VariableStoreHeader;
BOOLEAN AuthencitatedMonotonicOrNot;
BOOLEAN AuthencitatedBasedTimeOrNot;
Status = EFI_ABORTED;
VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
AuthencitatedMonotonicOrNot = FALSE;
AuthencitatedBasedTimeOrNot = FALSE;
//
// Judge the layout of NV by gEfiVariableGuid
//
AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
if (AuthencitatedMonotonicOrNot) {
//
// Update the Monotonic based authenticate variable
//
Status = RemoveAuthEfiVariable (StorageListHead);
} else if (AuthencitatedBasedTimeOrNot){
//
// Update the Time Sample authenticate variable
//
Status = RemoveAuthEfiVariableBasedTime (StorageListHead);
} else {
//
// Update the normal variable
//
Status = RemoveNormalEfiVariable (StorageListHead);
}
return Status;
}
/**
Parse the all formset in one VfrBin.
Parse all questions, variables and expression in VfrBin, and store
it in Formset and Form.
@param BaseAddr The pointer to the array of VfrBin base address.
@param UniBinBaseAddress The pointer to one Uni string base address.
@retval EFI_SUCCESS The Search was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
ParseFormSetInVfrBin (
IN UINTN **BaseAddr,
IN UINTN *UniBinBaseAddress,
IN UINT8 Index
)
{
UINT32 PackageLength;
EFI_STATUS Status;
FORM_BROWSER_FORMSET *FormSet;
UINT8 *IfrBinaryData;
EFI_IFR_OP_HEADER *IfrOpHdr;
UINT32 IfrOffset;
PackageLength = 0;
Status = EFI_SUCCESS;
FormSet = NULL;
IfrBinaryData = NULL;
IfrOpHdr = NULL;
//
// The first 4 Bytes of VfrBin is used to record the Array Length
// The header of VfrBin is, ARRAY LENGTH:4 Bytes, PACKAGE HEADER:4 Bytes (2 Bytes for Len, and the other for Type)
//
PackageLength = *(UINT32 *)*(BaseAddr + Index) - 4;
IfrBinaryData = (UINT8 *)*(BaseAddr + Index) + 4;
//
// Go through the form package to parse OpCode one by one.
//
IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
while (IfrOffset < PackageLength) {
//
// Search the Formset in VfrBin
//
IfrOpHdr = (EFI_IFR_OP_HEADER *) (IfrBinaryData + IfrOffset);
if (IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) {
FormSet = calloc (sizeof (FORM_BROWSER_FORMSET), sizeof (CHAR8));
if (FormSet == NULL) {
return EFI_ABORTED;
}
FormSet->IfrBinaryData = IfrBinaryData + IfrOffset;
FormSet->UnicodeBinary = (UINT8 *) UniBinBaseAddress;
//
//This length will be corrected in ParseOpCodes function.
//
FormSet->IfrBinaryLength = PackageLength - IfrOffset;
//
// Parse opcodes in the formset IFR binary.
//
Status = ParseOpCodes (FormSet);
if (EFI_ERROR (Status)) {
DestroyAllStorage (FormSet->StorageListHead);
DestroyFormSet (FormSet);
return EFI_ABORTED;
}
IfrOffset += FormSet->IfrBinaryLength;
FormSet->EnUsStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
FormSet->EnUsStringList.CachedIdNum = 0;
FormSet->EnUsStringList.MaxIdNum = STRING_NUMBER;
FormSet->UqiStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
FormSet->UqiStringList.CachedIdNum = 0;
FormSet->UqiStringList.MaxIdNum = STRING_NUMBER;
//
// Insert the FormSet to mFormSet
//
InsertTailList (&mFormSetListEntry, &FormSet->Link);
} else {
IfrOffset += IfrOpHdr->Length;
}
}
return EFI_SUCCESS;
}
/**
Store all defaultId to mMultiPlatformParam.
The mMultiPlatformParam.DefaultId[0] is used to store standard default.
@param DefaultId The current defaultID.
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
VOID
StoreAllDefaultId (
IN UINT16 DefaultId
)
{
UINT32 Index;
if ((mMultiPlatformParam.DefaultIdNum == 0) && (DefaultId != 0)) {
mMultiPlatformParam.DefaultId[0] = DefaultId;
mMultiPlatformParam.DefaultIdNum++;
return;
}
//
// Only store the different value to mMultiPlatformParam.DefaultId[1] - mMultiPlatformParam.DefaultId[n]
//
for (Index = 0; Index < mMultiPlatformParam.DefaultIdNum; Index++) {
if (mMultiPlatformParam.DefaultId[Index] == DefaultId) {
return;
}
}
mMultiPlatformParam.DefaultId[Index] = DefaultId;
mMultiPlatformParam.DefaultIdNum++;
}
/**
Read all defaultId and platformId from binary.
@param Binary The pointer to the bianry
@param Storage The pointer to the Storage
**/
VOID
ReadDefaultAndPlatformIdFromBfv (
IN UINT8 *Binary,
IN FORMSET_STORAGE *Storage
)
{
UINT16 Length;
UINT16 Size;
UINT32 Index;
Length = *(UINT16 *)Binary - sizeof (UINT16);
Index = 0;
Size = 0;
Binary = Binary + sizeof (UINT16);
for (Size = 0; Size < Length; Size += sizeof (UINT16) + mMultiPlatformParam.PlatformIdWidth, Index++) {
Storage->DefaultId[Index] = *(UINT16 *)(Binary + Size);
memcpy (&Storage->PlatformId[Index], (Binary + Size + sizeof (UINT16)), mMultiPlatformParam.PlatformIdWidth);
}
Storage->DefaultPlatformIdNum = Index - 1;
}
/**
Store all defaultId and platformId to binary.
@param Binary The pointer to the bianry
@param Storage The pointer to the Storage
@retval Length Return the length of the header
**/
UINT32
WriteDefaultAndPlatformId (
IN UINT8 *Binary,
IN FORMSET_STORAGE *Storage
)
{
UINT16 Length;
UINT32 Index;
UINT8 *Buffer;
Length = 0;
Buffer = Binary;
Buffer = Buffer + sizeof (CHAR16);
for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
*(UINT16 *)Buffer = Storage->DefaultId[Index];
Buffer = Buffer + sizeof (CHAR16);
memcpy (Buffer, &Storage->PlatformId[Index], mMultiPlatformParam.PlatformIdWidth);
Buffer = Buffer + mMultiPlatformParam.PlatformIdWidth;
}
Length = (UINT16) (Buffer - Binary);
//
// Record the offset to the first two bytes
//
*(UINT16 *)Binary = Length;
return Length;
}
/**
Store all defaultId and platformId to binary.
@param Binary The pointer to the bianry
@param Storage The pointer to the Storage
@retval Length Return the length of the header
**/
UINT32
WriteNvStoreDefaultAndPlatformId (
IN UINT8 *Binary,
IN FORMSET_STORAGE *Storage
)
{
UINT16 Length;
UINT32 Index;
UINT8 *Buffer;
Length = 0;
Buffer = Binary + 8;
for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
*(UINT64 *)Buffer = Storage->PlatformId[Index];
Buffer = Buffer + sizeof(UINT64);
*(UINT16 *)Buffer = Storage->DefaultId[Index];
Buffer = Buffer + sizeof(UINT16);
// for Resered
Buffer = Buffer + 6;
}
Length = (UINT16) (Buffer - Binary - 8);
// for Header size
Length += 4;
return Length;
}
/**
Read the platformId from questions.
@retval EFI_SUCCESS It was complete successfully.
@return EFI_ABORTED An error occurred.
**/
EFI_STATUS
ReadPlaformId (
IN FORM_BROWSER_STATEMENT *CurQuestion
)
{
UINT16 Index;
UINT64 IdValue;
LIST_ENTRY *Link;
QUESTION_OPTION *Option;
UINT64 Step;
Index = 0;
IdValue = 0;
Step = 0;
//
// Check whether it is the question of paltform Id
//
if (!CompareUqiHeader (&(CurQuestion->Uqi), &(mMultiPlatformParam.Uqi))) {
return EFI_ABORTED;
}
//
// Copy the Question with platform to mMultiPlatformParam
//
memcpy (&mMultiPlatformParam.PlatformIdQuestion, CurQuestion, sizeof (FORM_BROWSER_STATEMENT));
mMultiPlatformParam.Question = CurQuestion;
//
// Pick up the value of NUMERIC and ONE_OF from current question and fill it in mMultiPlatformParam
//
mMultiPlatformParam.PlatformIdWidth = CurQuestion->StorageWidth;
if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
Index = 0;
if (CurQuestion->Step == 0) {
Step = 1;
} else {
Step = CurQuestion->Step;
}
for (IdValue = CurQuestion->Minimum; IdValue < CurQuestion->Maximum; IdValue += Step) {
mMultiPlatformParam.PlatformId[Index++] = (UINT64)IdValue;
}
}
if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
Index = 0;
Link = GetFirstNode (&CurQuestion->OptionListHead);
while (!IsNull (&CurQuestion->OptionListHead, Link)) {
Option = QUESTION_OPTION_FROM_LINK (Link);
mMultiPlatformParam.PlatformId[Index++] = Option->Value.Value.u64;
Link = GetNextNode (&CurQuestion->OptionListHead, Link);
}
}
if (Index >= MAX_PLATFORM_DEFAULT_ID_NUM) {
return EFI_ABORTED;
}
mMultiPlatformParam.PlatformIdNum = Index;
return EFI_SUCCESS;
}
/**
Clear the buffer of Storage list.
@param StorageListHead The pointer to the entry of the storage list
@param DefaultId The default Id for multi-platform support
@param PlatformId The platform Id for multi-platform support
@retval NULL
**/
VOID
ClearStorageEntryList (
IN LIST_ENTRY *StorageListHead,
IN UINT16 DefaultId,
IN UINT64 PlatformId
)
{
LIST_ENTRY *StorageLink;
FORMSET_STORAGE *Storage;
Storage = NULL;
StorageLink = GetFirstNode (StorageListHead);
while (!IsNull (StorageListHead, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if (Storage != NULL) {
memset (Storage->Buffer, 0x0, Storage->Size);
Storage->DefaultId[0] = DefaultId;
Storage->PlatformId[0] = PlatformId;
Storage->DefaultPlatformIdNum = 0;
}
StorageLink = GetNextNode (StorageListHead, StorageLink);
}
}
/**
Append the platformid and default to the variables of CurDefaultId and CurPlatformId
@param StorageListHead The pointer to the storage list
@param CurDefaultId The default Id for multi-platform mode
@param CurPlatformId The platform Id for multi-platform mode
@param DefaultId The default Id for multi-platform mode
@param PlatformId The platform Id for multi-platform mode
@retval NULL
**/
VOID
AppendIdToVariables (
IN LIST_ENTRY *StorageListHead,
IN UINT16 CurDefaultId,
IN UINT64 CurPlatformId,
IN UINT16 DefaultId,
IN UINT64 PlatformId
)
{
LIST_ENTRY *StorageLink;
FORMSET_STORAGE *Storage;
Storage = NULL;
StorageLink = GetFirstNode (StorageListHead);
while (!IsNull (StorageListHead, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if ((Storage->DefaultId[0] == CurDefaultId)
&& (Storage->PlatformId[0] == CurPlatformId)
) {
++Storage->DefaultPlatformIdNum;
Storage->DefaultId[Storage->DefaultPlatformIdNum] = DefaultId;
Storage->PlatformId[Storage->DefaultPlatformIdNum] = PlatformId;
}
StorageLink = GetNextNode (StorageListHead, StorageLink);
}
}
/**
Check whether StorageListHead2 is included in StorageListHead1
@param StorageListHead1 The pointer to the entry of storage list
@param StorageListHead2 The pointer to the entry of storage list
@param DefaultId The default Id for multi-platform mode
@param PlatformId The platform Id for multi-platform mode
@retval TRUE Totally included.
@return FALSE Other cases.
**/
BOOLEAN
ComparePartSameVariableList (
IN LIST_ENTRY *StorageListHead1,
IN LIST_ENTRY *StorageListHead2,
OUT UINT16 *DefaultId,
OUT UINT64 *PlatformId
)
{
LIST_ENTRY *StorageLink;
LIST_ENTRY *TempStorageHead;
LIST_ENTRY *TempStorageLink;
LIST_ENTRY *TempStorageHead2;
LIST_ENTRY *TempStorageLink2;
FORMSET_STORAGE *Storage;
FORMSET_STORAGE *TempStorage;
FORMSET_STORAGE *TempStorage2;
UINT16 CurDefaultId;
UINT64 CurPlatformId;
UINT32 VariableNum;
UINT32 Index;
StorageLink = NULL;
TempStorageHead = NULL;
TempStorageLink = NULL;
TempStorageHead2 = NULL;
TempStorageLink2 = NULL;
Storage = NULL;
TempStorage = NULL;
TempStorage2 = NULL;
CurDefaultId = 0;
CurPlatformId = 0;
VariableNum = 0;
Index = 0;
TempStorageHead = StorageListHead1;
//
// Get the number of variables in StorageListHead2;
//
StorageLink = GetFirstNode (StorageListHead2);
while (!IsNull (StorageListHead2, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
//
// For multi-platform support, only need to calcuate the type of EFI_IFR_VARSTORE_EFI_OP.
//
if (mMultiPlatformParam.MultiPlatformOrNot &&
(Storage->Type == EFI_IFR_VARSTORE_EFI_OP) && (Storage->Name != NULL) && (Storage->NewEfiVarstore) &&
((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)) {
VariableNum++;
}
StorageLink = GetNextNode (StorageListHead2, StorageLink);
}
//
// Parse every variables in StorageListHead1 and compare with ones in StorageListHead2
// Only all variables in StorageListHead2 are included in StorageListHead1, return TRUE.
//
StorageLink = GetFirstNode (StorageListHead1);
while (!IsNull (StorageListHead1, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
//
// Get specified DefaultId and PlatformId firstly
//
CurDefaultId = Storage->DefaultId[0];
CurPlatformId = Storage->PlatformId[0];
Index = 0;
//
// Compare all variables under same defaultId and platformId
//
TempStorageLink = GetFirstNode (TempStorageHead);
while (!IsNull (TempStorageHead, TempStorageLink)) {
TempStorage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
if ((TempStorage->DefaultId[0] == CurDefaultId)
&& (TempStorage->PlatformId[0] == CurPlatformId)
&& (TempStorage->Name != NULL)
&& (TempStorage->Type == EFI_IFR_VARSTORE_EFI_OP)
&& (TempStorage->NewEfiVarstore)
&& ((TempStorage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
) {
//
//Search the matched variable by Guid and name in StorageListHead2
//
TempStorageHead2 = StorageListHead2;
TempStorageLink2 = GetFirstNode (TempStorageHead2);
while (!IsNull (TempStorageHead2, TempStorageLink2)) {
TempStorage2 = FORMSET_STORAGE_FROM_LINK (TempStorageLink2);
if ((TempStorage2->Name != NULL)
&& (TempStorage2->Type == EFI_IFR_VARSTORE_EFI_OP)
&& (TempStorage2->NewEfiVarstore)
&& ((TempStorage2->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
&& !FceStrCmp (TempStorage->Name, TempStorage2->Name)
&& !CompareGuid(&TempStorage->Guid, &TempStorage2->Guid)
) {
if (CompareMem (TempStorage->Buffer, TempStorage2->Buffer, TempStorage->Size) == 0) {
Index++;
}
}
TempStorageLink2 = GetNextNode (TempStorageHead2, TempStorageLink2);
}
}
TempStorageLink = GetNextNode (TempStorageHead, TempStorageLink);
}
//
// Check the matched variable number
//
if (Index == VariableNum) {
*DefaultId = CurDefaultId;
*PlatformId = CurPlatformId;
return TRUE;
}
StorageLink = GetNextNode (StorageListHead1, StorageLink);
}
return FALSE;
}
/**
Check whether the defaultId and platformId mathched the variable or not
@param Storage The pointer to the storage
@param DefaultId The default Id for multi-platform mode
@param PlatformId The platform Id for multi-platform mode
@retval TRUE Not Matched.
@return FALSE Matched any one
**/
BOOLEAN
NotEqualAnyIdOfStorage (
IN FORMSET_STORAGE *Storage,
IN UINT16 DefaultId,
IN UINT64 PlatformId
)
{
UINT32 Index;
for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
if ((Storage->DefaultId[Index] == DefaultId)
&&(Storage->PlatformId[Index] == PlatformId)
) {
return FALSE;
}
}
return TRUE;
}
/**
Copy Stroage from StorageListHead2 to StorageListHead1
@param NewStorageListHead The pointer to the entry of storage list
@param OldStorageListHead The pointer to the entry of storage list
@param DefaultId The default Id for multi-platform mode
@param PlatformId The platform Id for multi-platform mode
@param AssignIdOrNot If True, assign the platform Id and default Id to storage;
Or else, only copy the variables under the specified platform
Id and default to the other list.
@param Mode The operation of mode
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
EFI_STATUS
BuildVariableList (
IN LIST_ENTRY *NewStorageListHead,
IN LIST_ENTRY *OldStorageListHead,
IN UINT16 DefaultId,
IN UINT64 PlatformId,
IN BOOLEAN AssignIdOrNot,
IN OPERATION_TYPE Mode
)
{
LIST_ENTRY *StorageLink;
LIST_ENTRY *NameValueLink;
FORMSET_STORAGE *Storage;
FORMSET_STORAGE *StorageCopy;
IN LIST_ENTRY *StorageListHead1;
IN LIST_ENTRY *StorageListHead2;
NAME_VALUE_NODE *NameValueNode;
NAME_VALUE_NODE *CopyNameValueNode;
Storage = NULL;
NameValueNode = NULL;
StorageListHead1 = NewStorageListHead;
StorageListHead2 = OldStorageListHead;
StorageLink = GetFirstNode (StorageListHead2);
while (!IsNull (StorageListHead2, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
||(Storage->Type == EFI_IFR_VARSTORE_OP)
) {
//
// Only support EfiVarStore in Multi-Platform mode, and the attribute must be EFI_VARIABLE_NON_VOLATILE
//
if (mMultiPlatformParam.MultiPlatformOrNot) {
if (Storage->Type == EFI_IFR_VARSTORE_OP) {
StorageLink = GetNextNode (StorageListHead2, StorageLink);
continue;
}
if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
&& Storage->NewEfiVarstore
&& ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
) {
StorageLink = GetNextNode (StorageListHead2, StorageLink);
continue;
}
if (AssignIdOrNot) {
Storage->DefaultId[0] = DefaultId;
Storage->PlatformId[0] = PlatformId;
} else {
//
//only copy the variables under the specified platform Id and default to the other list.
//
if ((Mode == VERIFY) && (NotEqualAnyIdOfStorage (Storage, DefaultId, PlatformId))) {
StorageLink = GetNextNode (StorageListHead2, StorageLink);
continue;
} else if ((Mode != VERIFY) && (Storage->DefaultId[0] != DefaultId || Storage->PlatformId[0] != PlatformId) ) {
StorageLink = GetNextNode (StorageListHead2, StorageLink);
continue;
}
}
}
//
// Copy Storage Node
//
if (Storage->Name == NULL) {
return EFI_ABORTED;
}
StorageCopy = NULL;
StorageCopy = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
if (StorageCopy == NULL) {
printf ("Memory allocation failed.\n");
return EFI_ABORTED;
}
memcpy (StorageCopy, Storage, sizeof (FORMSET_STORAGE));
if (Mode == VERIFY) {
StorageCopy->DefaultId[0] = DefaultId;
StorageCopy->PlatformId[0] = PlatformId;
}
//
//Set the flags for sorting out the variables
//
StorageCopy->Skip = FALSE;
StorageCopy->Name = NULL;
StorageCopy->Name = calloc (FceStrLen (Storage->Name) + 1, sizeof (CHAR16));
if (StorageCopy->Name == NULL) {
printf ("Memory allocation failed.\n");
free (StorageCopy);
return EFI_ABORTED;
}
StrCpy (StorageCopy->Name, Storage->Name);
StorageCopy->Buffer = NULL;
StorageCopy->Buffer = calloc (Storage->Size, sizeof (CHAR8));
if (StorageCopy->Buffer == NULL) {
free (StorageCopy->Name);
free (StorageCopy);
printf ("Memory allocation failed.\n");
return EFI_ABORTED;
}
CopyMem (StorageCopy->Buffer, Storage->Buffer, Storage->Size);
//
// Copy NameValue list of storage node
//
InitializeListHead (&StorageCopy->NameValueListHead);
NameValueLink = GetFirstNode (&Storage->NameValueListHead);
while (!IsNull (&Storage->NameValueListHead, NameValueLink)) {
NameValueNode = NAME_VALUE_NODE_FROM_LINK (NameValueLink);
CopyNameValueNode = NULL;
CopyNameValueNode = calloc (sizeof (NAME_VALUE_NODE), sizeof (CHAR8));
if (CopyNameValueNode == NULL) {
free (StorageCopy->Name);
free (StorageCopy->Buffer);
free (StorageCopy);
printf ("Memory allocation failed.\n");
return EFI_ABORTED;
}
memcpy (CopyNameValueNode, NameValueNode, sizeof (NAME_VALUE_NODE));
CopyNameValueNode->Name = NULL;
CopyNameValueNode->Value = NULL;
CopyNameValueNode->EditValue = NULL;
CopyNameValueNode->Name = calloc (FceStrLen (NameValueNode->Name) + 1, sizeof (CHAR16));
CopyNameValueNode->Value = calloc (FceStrLen (NameValueNode->Value) + 1, sizeof (CHAR16));
CopyNameValueNode->EditValue = calloc (FceStrLen (NameValueNode->EditValue) + 1, sizeof (CHAR16));
if ((CopyNameValueNode->Name == NULL)
|| (CopyNameValueNode->Value == NULL)
|| (CopyNameValueNode->EditValue == NULL)
) {
free (StorageCopy->Name);
free (StorageCopy->Buffer);
free (StorageCopy);
if (CopyNameValueNode->Name != NULL) {
free (CopyNameValueNode->Name );
}
if (CopyNameValueNode->Value != NULL) {
free (CopyNameValueNode->Value);
}
if (CopyNameValueNode->EditValue != NULL) {
free (CopyNameValueNode->EditValue);
}
free (CopyNameValueNode);
printf ("Memory allocation failed.\n");
return EFI_ABORTED;
}
StrCpy (CopyNameValueNode->Name, NameValueNode->Name);
StrCpy (CopyNameValueNode->Value, NameValueNode->Value);
StrCpy (CopyNameValueNode->EditValue, NameValueNode->EditValue);
//
// Insert it to StorageCopy->NameValueListHead
//
InsertTailList(&StorageCopy->NameValueListHead,&CopyNameValueNode->Link);
NameValueLink = GetNextNode (&Storage->NameValueListHead, NameValueLink);
}
//
// Insert it to StorageListHead1
//
InsertTailList(StorageListHead1,&StorageCopy->Link);
}
StorageLink = GetNextNode (StorageListHead2, StorageLink);
}
return EFI_SUCCESS;
}
/**
Check whether the current defaultId and platfrom is equal to the first one of one
group of defaultId and platformId which have the same variable data.
@param DefaultId The default Id
@param PlatformId The platform Id
@retval TRUE If not equal to the first defaultId and platformId, return TRUE
@return EFI_ABORTED Others
**/
BOOLEAN
NoTheKeyIdOfGroup (
IN UINT16 DefaultId,
IN UINT64 PlatformId
)
{
UINT32 Index;
for (Index = 0; Index < mMultiPlatformParam.KeyIdNum; Index++) {
if (
(DefaultId == mMultiPlatformParam.KeyDefaultId[Index])
&& (PlatformId == mMultiPlatformParam.KeyPlatformId[Index])
) {
return FALSE;
}
}
return TRUE;
}
/**
Evaluate the value in all formset according to the defaultId and platformId.
If not the multi-platform mode, the defaultId is 0. In this case, the
platform Id will be the default value of that question.
@param UpdateMode It will be TRUE in update Mode
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
EFI_STATUS
EvaluateTheValueInFormset (
IN BOOLEAN UpdateMode
)
{
EFI_STATUS Status;
UINT16 DefaultId;
UINT64 PlatformId;
UINT16 CurDefaultId;
UINT64 CurPlatformId;
UINT16 DefaultIndex;
UINT16 PlatformIndex;
UINT32 Index;
UQI_PARAM_LIST *CurUqiList;
Status = EFI_SUCCESS;
if (mMultiPlatformParam.MultiPlatformOrNot) {
ScanUqiFullList (mUqiList);
//
// Multi-platform mode support
//
for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
//
//Only parse one time, if a group of defaultId and platformId which have the same variable
// Take the first one as a key Id of a group
//
if (UpdateMode && NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
continue;
}
//
// Initialize the Storage of mVarListEntry
//
ClearStorageEntryList (&mVarListEntry, DefaultId, PlatformId);
Status = ExtractDefault (
NULL,
NULL,
DefaultId,
PlatformId,
SystemLevel
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// Clear the platformId as 0 after calculation.
//
Status = AssignThePlatformId (0);
if (EFI_ERROR (Status)) {
printf ("Failed to clear the platformid.\n");
return Status;
}
//
// Update the value from script file
//
if (UpdateMode) {
SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
}
//
// If not existed the same variables in mAllVarListEntry, insert the new ones.
// Or else, only add the defaultId and platformId to the former one.
//
if (ComparePartSameVariableList (&mAllVarListEntry, &mVarListEntry, &CurDefaultId, &CurPlatformId)) {
AppendIdToVariables (&mAllVarListEntry, CurDefaultId, CurPlatformId, DefaultId, PlatformId);
} else {
//
// Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
//
Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// In update mode, add the other defaultId and platform of a group to the variale list
//
if (UpdateMode) {
CurUqiList = mUqiList;
while (CurUqiList != NULL) {
if ((DefaultId == CurUqiList->Header.DefaultId[0])
&& (PlatformId == CurUqiList->Header.PlatformId[0])
) {
break;
}
CurUqiList = CurUqiList->Next;
}
if (CurUqiList == NULL) {
return EFI_ABORTED;
}
for (Index = 1; Index < CurUqiList->Header.IdNum; Index++) {
CurDefaultId = CurUqiList->Header.DefaultId[Index];
CurPlatformId = CurUqiList->Header.PlatformId[Index];
AppendIdToVariables (&mAllVarListEntry, DefaultId, PlatformId, CurDefaultId, CurPlatformId);
}
}
}
}
}
} else {
//
// General mode
//
Status = ExtractDefault (
NULL,
NULL,
0,
0,
SystemLevel
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// If existed the variable in NvStorage, copy them to mVarListEntry.
// Synchronize the default value from the EFI variable zone to variable list
//
Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
if (Status == EFI_INVALID_PARAMETER) {
Status = EFI_ABORTED;
return Status;
}
//
// Update the value from script file
//
if (UpdateMode) {
Status = SetUqiParameters (mUqiList,0, 0);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// Copy Stroage from mVarListEntry to mAllVarListEntry
//
Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, UPDATE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
return EFI_SUCCESS;
}
/**
Check and compare the value between the script file and variable from BFV.
It's used in the update operation of multi-plaform mode.
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
CheckValueUpdateList (
VOID
)
{
UINT16 DefaultId;
UINT64 PlatformId;
UINT16 DefaultIndex;
UINT16 PlatformIndex;
EFI_STATUS Status;
FORMSET_STORAGE *Storage;
LIST_ENTRY *StorageLink;
UINT16 PreDefaultId;
UINT64 PrePlatformId;
Storage = NULL;
PreDefaultId = 0xFFFF;
PrePlatformId = 0xFFFFFFFFFFFFFFFF;
ScanUqiFullList (mUqiList);
if (gEfiFdInfo.ExistNvStoreDatabase) {
StorageLink = GetFirstNode (&mBfvVarListEntry);
while (!IsNull (&mBfvVarListEntry, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
continue;
} else {
PreDefaultId = Storage->DefaultId[0];
PrePlatformId = Storage->PlatformId[0];
}
DefaultId = PreDefaultId;
PlatformId = PrePlatformId;
//
//Only parse one time, if a group of defaultId and platformId which have the same variable
// Take the first one as a key Id of a group
//
if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
continue;
}
//
// Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
// the FormSet->StorageListHead.
//
DestroyAllStorage (&mVarListEntry);
Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
//
// Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
//
Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
}
} else {
for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
//
//Only parse one time, if a group of defaultId and platformId which have the same variable
// Take the first one as a key Id of a group
//
if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
continue;
}
//
// Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
// the FormSet->StorageListHead.
//
DestroyAllStorage (&mVarListEntry);
Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
//
// Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
//
Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
}
}
return EFI_SUCCESS;
}
/**
Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
If not multi-platform mode, only return EFI_ABORTED.
@param Fv the Pointer to the FFS
@param Length the length of FFS
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
ReadAllIfrToFromset (
IN VOID *Fv,
IN UINTN Length
)
{
UINT8 NumberofMachingVfrBin;
UINTN *VfrBinBaseAddress;
UINTN *UniBinBaseAddress;
EFI_STATUS Status;
UINT8 Index;
EFI_SECTION_STRUCT *EfiBufferHeader;
VOID *EfiAddr;
NumberofMachingVfrBin = 0;
VfrBinBaseAddress = NULL;
UniBinBaseAddress = NULL;
Status = EFI_SUCCESS;
EfiBufferHeader = NULL;
EfiAddr = NULL;
//
// Locate the efi base address
//
EfiBufferHeader = malloc (sizeof (EFI_SECTION_STRUCT));
if (EfiBufferHeader == NULL) {
return EFI_ABORTED;
}
memset (
EfiBufferHeader,
0,
sizeof (EFI_SECTION_STRUCT)
);
Status = ParseSection (
TRUE,
(UINT8 *)Fv,
Length,
&EfiBufferHeader
);
if (Status != EFI_SUCCESS) {
Status = EFI_ABORTED;
goto Done;
}
EfiAddr = (VOID *)EfiBufferHeader->BufferBase;
//
//Search the Offset at the end of FFS, whatever it is compressed or not
//
Status = SearchVfrBinInFFS (Fv, EfiAddr, Length, &VfrBinBaseAddress, &NumberofMachingVfrBin);
if (Status != EFI_SUCCESS) {
Status = EFI_ABORTED;
goto Done;
}
Status = SearchUniBinInFFS (
Fv,
EfiAddr,
Length,
&UniBinBaseAddress
);
if (Status != EFI_SUCCESS) {
Status = EFI_ABORTED;
goto Done;
}
//
// Read all Ifr information into Formset and Form structure
//
for (Index = 0; Index < NumberofMachingVfrBin; Index++) {
if ((EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *(VfrBinBaseAddress + Index)
|| (EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *UniBinBaseAddress
) {
printf ("Failed to locate Ifr data from efi by the offset.\n");
Status = EFI_ABORTED;
goto Done;
}
Status = ParseFormSetInVfrBin (
(UINTN **)VfrBinBaseAddress,
(UINTN *)*UniBinBaseAddress,
Index
);
if (EFI_ERROR (Status)) {
Status = EFI_ABORTED;
goto Done;
}
}
Done:
//
// Free the memory which stores the offset
//
if (VfrBinBaseAddress != NULL) {
free (VfrBinBaseAddress);
}
if (UniBinBaseAddress != NULL) {
free (UniBinBaseAddress);
}
//
// Free the memory for uncompressed space in section
//
for (Index = 0; Index < EfiBufferHeader->UnCompressIndex; Index++) {
if ((VOID *)EfiBufferHeader->UncompressedBuffer[Index] != NULL) {
free ((VOID *)EfiBufferHeader->UncompressedBuffer[Index]);
}
}
return Status;
}
/**
Get next questions of four kinds in FormSet list.
If not one kinds of ONE_OF CHECK_BOX ORDER_LIST and NUMERIC, continue to parse next question.
If parse to the end of questions, return NULL.
@param FormSetEntryListHead the pointer to the LIST_ENTRY
@param OrderOfQuestion the order of question
@retval If succeed, return the pointer to the question
@return NULL
**/
FORM_BROWSER_STATEMENT *
GetNextQuestion (
IN LIST_ENTRY *FormSetEntryListHead,
IN OUT UINT32 *OrderOfQuestion
)
{
FORM_BROWSER_FORMSET *FormSet;
LIST_ENTRY *FormSetLink;
FORM_BROWSER_FORM *Form;
LIST_ENTRY *FormLink;
FORM_BROWSER_STATEMENT *Question;
LIST_ENTRY *QuestionLink;
UINT32 Index;
FormSet = NULL;
FormSetLink = NULL;
Form = NULL;
FormLink = NULL;
Question = NULL;
QuestionLink = NULL;
Index = 0;
FormSetLink = GetFirstNode (FormSetEntryListHead);
while (!IsNull (FormSetEntryListHead, FormSetLink)) {
FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
//
// Parse all forms in formset
//
FormLink = GetFirstNode (&FormSet->FormListHead);
while (!IsNull (&FormSet->FormListHead, FormLink)) {
Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
//
// Parse five kinds of Questions in Form
//
QuestionLink = GetFirstNode (&Form->StatementListHead);
while (!IsNull (&Form->StatementListHead, QuestionLink)) {
Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
//
// Parse five kinds of Questions in Form
//
if ((Question->Operand == EFI_IFR_ONE_OF_OP)
|| (Question->Operand == EFI_IFR_NUMERIC_OP)
|| (Question->Operand == EFI_IFR_CHECKBOX_OP)
|| (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
|| (Question->Operand == EFI_IFR_STRING_OP)
) {
if (*OrderOfQuestion == Index++) {
(*OrderOfQuestion)++;
return Question;
}
}
QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
}
FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
}
FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
}
return NULL;
}
/**
Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
If not multi-platform mode, only return EFI_ABORTED.
@param Fv the Pointer to the FFS
@param Length the length of FFS
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
ReadDefaultAndPlatformId (
IN LIST_ENTRY *FormSetEntryListHead
)
{
EFI_STATUS Status;
FORM_BROWSER_FORMSET *FormSet;
LIST_ENTRY *FormLink;
FORMSET_DEFAULTSTORE *DefaultStore;
LIST_ENTRY *DefaultStoreLink;
FORM_BROWSER_STATEMENT *CurQuestion;
UINT32 MatchedNum;
UINT32 QuestionOrder;
Status = EFI_SUCCESS;
CurQuestion = NULL;
MatchedNum = 0;
QuestionOrder = 0;
//
//Check whether it is the Multi-Platform solution or not
//
if (!mMultiPlatformParam.MultiPlatformOrNot) {
Status = EFI_SUCCESS;
goto Done;
}
//
// Read defaultId from FormSet List
//
FormLink = GetFirstNode (FormSetEntryListHead);
while (!IsNull (FormSetEntryListHead, FormLink)) {
FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
//
// Parse Default Store in formset
//
DefaultStoreLink = GetFirstNode (&FormSet->DefaultStoreListHead);
while (!IsNull (&FormSet->DefaultStoreListHead, DefaultStoreLink)) {
DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultStoreLink);
StoreAllDefaultId (DefaultStore->DefaultId);
DefaultStoreLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultStoreLink);
}
FormLink = GetNextNode (FormSetEntryListHead, FormLink);
}
//
//Read the platformId from FormSetList
//
while ((CurQuestion = GetNextQuestion (FormSetEntryListHead, &QuestionOrder)) != NULL) {
Status = ReadPlaformId (CurQuestion);
if (!EFI_ERROR (Status)) {
MatchedNum++;
}
}
if (MatchedNum == 0) {
printf ("There are no questions included in the platformid in the FD.");
Status = EFI_ABORTED;
} else if (MatchedNum > 1) {
printf ("There are %d questions included in the platformid in the FD.", MatchedNum);
Status = EFI_ABORTED;
} else {
Status = EFI_SUCCESS;
}
Done:
return Status;
}
/**
Read the first two bytes to check whether it is Ascii or UCS2.
@param ScriptFile Pointer to the script file.
@reture TRUE If ascii, return TRUE
@reture FALSE Others, return FALSE.
**/
FILE_TYPE
IsAsciiOrUcs2 (
IN FILE *ScriptFile
)
{
CHAR16 FirstTwoBytes;
fread(&FirstTwoBytes, 1, 2, ScriptFile);
if (FirstTwoBytes == BigUnicodeFileTag) {
return BIG_UCS2;
} else if (FirstTwoBytes == LittleUnicodeFileTag) {
return LITTLE_UCS2;
} else {
return ASCII;
}
}
/**
Read Unicode characters and transfer it to ASCII.
@param ScriptFile The pointer to the script file.
@param Type The type of BigUCS2 or LittleUCS2
@return The ASCII characters
**/
CHAR8 *
ReadUcs2ToStr (
IN OUT FILE *ScriptFile,
IN FILE_TYPE Type
)
{
CHAR16 TempChar16;
CHAR16 TempChar8;
CHAR8 *StrChar8;
UINTN Index;
BOOLEAN FirstParse;
TempChar16 = L'\0';
TempChar8 = '\0';
StrChar8 = NULL;
Index = 0;
FirstParse = TRUE;
if (ScriptFile == NULL) {
return NULL;
}
StrChar8 = calloc (MAX_STR_LEN_FOR_PICK_UQI, sizeof (CHAR8));
assert (StrChar8);
for (Index = 0; Index < MAX_STR_LEN_FOR_PICK_UQI; Index++) {
//
// The first parse should skip the 0x0020 (BigUCS2) or 0x2000 (LittleUCS2)
//
if (FirstParse) {
do {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
} while ((TempChar16 == 0x0020) || (TempChar16 == 0x2000));
FirstParse = FALSE;
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
}
//
// Read until break the "Space"
//
if ((TempChar16 == 0x0020) || (TempChar16 == 0x2000)) {
break;
}
if (Type == BIG_UCS2) {
TempChar8 = (CHAR8)TempChar16;
} else {
TempChar8 = (CHAR8)(TempChar16 >> 8);
}
memcpy (StrChar8 + Index, &TempChar8, 0x1);
}
if (Index == MAX_STR_LEN_FOR_PICK_UQI) {
free (StrChar8);
return NULL;
}
*(StrChar8 + Index) = '\0';
return StrChar8;
}
/**
Read Unicode characters and transfer it to ASCII.
@param AsciiStr The pointer to the Ascii string. It may inlcudes blank space.
@param IdArray The pointer to the array of Id.
@return The number of default or platform Id
**/
static
UINT16
GetNumFromAsciiString (
IN CHAR8 *AsciiStr,
IN OUT UINT64 *IdArray
)
{
UINT16 Index1;
UINT16 Index2;
UINT16 NumofId;
CHAR8 CharArray[16];
BOOLEAN ExistedValue;
Index1 = 0;
Index2 = 0;
NumofId = 0;
ExistedValue = FALSE;
while (*(AsciiStr + Index1) != '\n') {
Index2 = 0;
ExistedValue = FALSE;
memset (CharArray, 0, 16);
for (; *(AsciiStr + Index1) == ' '; Index1++);
for (; (*(AsciiStr + Index1) != ' ') && (*(AsciiStr + Index1) != '\n'); Index1++) {
assert (Index2 <= 15);
*(CharArray + Index2++) = *(AsciiStr + Index1);
ExistedValue = TRUE;
}
if (ExistedValue && (*(AsciiStr + Index1 - 1) != '\n')) {
sscanf(CharArray, "%lld", (long long *)&IdArray[NumofId++]);
}
}
return NumofId;
}
/**
Parse the script file to build the linked list of question structures.
Pick up the UQI information and save it to the UqiList. The current scripts
could be Ascii or UCS2 (Little or Big Mode).
@param ScriptFile The pointer to the script file.
@return EFI_SUCCESS
@return EFI_INVALID_PARAMETER ScriptFile is NULL
**/
static
EFI_STATUS
PickUpUqiFromScript (
IN FILE *ScriptFile
)
{
CHAR8 TempChar;
BOOLEAN InQuote;
CHAR16 TempChar16;
UINT32 UqiSize;
CHAR16 *UqiBuffer;
CHAR8 Type[32];
UINT16 Index;
UQI_PARAM_LIST *UqiNode;
UINTN MaxContainers;
UINT32 ScriptsLine;
FILE_TYPE AsciiOrUcs2;
CHAR8 *Char8Str;
CHAR8 DefaultIdStr[30];
CHAR8 PlatformIdStr[30];
CHAR8 PlatformUqi[30];
UINT16 Index1;
UINT16 Index2;
UINT16 Index3;
UINT16 Index4;
UINT16 Index5;
BOOLEAN ReadDefaultId;
BOOLEAN ReadPlatformId;
BOOLEAN ReadPlatformIdUqi;
UINT64 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
UINT16 DefaultIdNum;
UINT16 PlatformIdNum;
UINT8 Array[MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM];
UINT16 IdStart;
UINT16 IdEnd;
Char8Str = NULL;
ScriptsLine = 0;
AsciiOrUcs2 = ASCII;
Index1 = 0;
Index2 = 0;
Index3 = 0;
Index4 = 0;
Index5 = 0;
ReadDefaultId = FALSE;
ReadPlatformId = FALSE;
ReadPlatformIdUqi = FALSE;
DefaultIdNum = 1;
PlatformIdNum = 1;
InQuote = FALSE;
memset (DefaultId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
memset (PlatformId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
memcpy (DefaultIdStr, "/ FCEKEY DEFAULT_ID:", strlen ("/ FCEKEY DEFAULT_ID:") + 1);
memcpy (PlatformIdStr,"/FCEKEY PLATFORM_ID:", strlen ("/FCEKEY PLATFORM_ID:") + 1);
memcpy (PlatformUqi, "/FCEKEY PLATFORM_UQI:", strlen ("/FCEKEY PLATFORM_UQI:") + 1);
if (ScriptFile == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check the file type
//
AsciiOrUcs2 = IsAsciiOrUcs2 (ScriptFile);
if (AsciiOrUcs2 == ASCII) {
fseek (ScriptFile, 0, SEEK_SET);
}
while(!feof(ScriptFile)) {
//
// Reset local data
//
TempChar = '\0';
TempChar16 = L'\0';
UqiSize = 0;
UqiBuffer = NULL;
MaxContainers = 0;
UqiNode = NULL;
memset(Type, 0, 32);
//
// Read first character of the line to find the line type
//
if (AsciiOrUcs2 == ASCII) {
fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
if (AsciiOrUcs2 == BIG_UCS2) {
TempChar = (CHAR8)TempChar16;
} else {
TempChar = (CHAR8)(TempChar16 >> 8);
}
}
//
// Take "\n\r" one line
//
if (TempChar != 0x0d) {
ScriptsLine++;
}
switch (TempChar) {
case 'Q':
//
// Process question line
//
// Read size of UQI string
//
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %x", (INT32 *)&UqiSize);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %x", (INT32 *)&UqiSize);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
if (UqiSize > MAX_INPUT_ALLOCATE_SIZE) {
return EFI_ABORTED;
}
if (UqiSize == 0) {
do {
if (AsciiOrUcs2 == ASCII) {
fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
if (AsciiOrUcs2 == BIG_UCS2) {
TempChar = (CHAR8)TempChar16;
} else {
TempChar = (CHAR8)(TempChar16 >> 8);
}
}
} while((TempChar != '\n') && !feof(ScriptFile));
break;
}
//
// Malloc buffer for string size + null termination
//
UqiBuffer = (CHAR16 *)calloc(UqiSize + 1, sizeof(CHAR16));
if (UqiBuffer == NULL) {
printf("Error. Unable to allocate 0x%04lx bytes for UQI string -- FAILURE\n", (unsigned long)((UqiSize + 1) * sizeof(CHAR16)));
break;
}
//
// Read UQI string
//
for (Index = 0; Index < UqiSize; Index++) {
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %hx", (short *)&(UqiBuffer[Index]));
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
free (UqiBuffer );
return EFI_ABORTED;
}
sscanf(Char8Str, " %hx", (short *)&(UqiBuffer[Index]));
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
}
//
// Set null termination
//
UqiBuffer[Index] = 0;
//
// Read question type
//
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, "%31s", Type);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
free (UqiBuffer);
return EFI_ABORTED;
}
sscanf(Char8Str, " %31s", Type);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
if (stricmp(Type, "ONE_OF") == 0) {
UqiNode = CreateInsertUqiNode ();
if (UqiNode == NULL) {
free (UqiBuffer);
return EFI_ABORTED;
}
UqiNode->Header.Type = ONE_OF;
UqiNode->Header.HexNum = UqiSize;
UqiNode->Header.Data = UqiBuffer;
UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
UqiNode->Header.IdNum = PlatformIdNum;
UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
if (UqiNode->Header.DefaultId == NULL) {
printf("Fail to allocate memory");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
if (UqiNode->Header.PlatformId == NULL) {
printf("Fail to allocate memory");
return EFI_OUT_OF_RESOURCES;
}
for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
}
memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
} else if (stricmp(Type, "CHECKBOX") == 0) {
UqiNode = CreateInsertUqiNode ();
if (UqiNode == NULL) {
free (UqiBuffer);
return EFI_ABORTED;
}
UqiNode->Header.Type = CHECKBOX;
UqiNode->Header.HexNum = UqiSize;
UqiNode->Header.Data = UqiBuffer;
UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
UqiNode->Header.IdNum = PlatformIdNum;
UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
if (UqiNode->Header.DefaultId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
if (UqiNode->Header.PlatformId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
}
memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
} else if (stricmp(Type, "STRING") == 0) {
UqiNode = CreateInsertUqiNode ();
if (UqiNode == NULL) {
free (UqiBuffer);
return EFI_ABORTED;
}
UqiNode->Header.Type = STRING;
UqiNode->Header.HexNum = UqiSize;
UqiNode->Header.Data = UqiBuffer;
UqiNode->Header.Value = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
UqiNode->Header.DiffValue = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
if (UqiNode->Header.Value == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
if (UqiNode->Header.DiffValue == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.IdNum = PlatformIdNum;
UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
if (UqiNode->Header.DefaultId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
if (UqiNode->Header.PlatformId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
}
memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
InQuote = FALSE;
IdStart = 0;
IdEnd = 0;
for (Index = 0; Index < MAX_INPUT_ALLOCATE_SIZE; Index ++) {
if (AsciiOrUcs2 == ASCII) {
fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
if (AsciiOrUcs2 == BIG_UCS2) {
TempChar = (CHAR8)TempChar16;
} else {
TempChar = (CHAR8)(TempChar16 >> 8);
}
}
if (TempChar == '\"') {
if (InQuote == TRUE) {
InQuote = FALSE;
IdEnd = Index;
} else {
InQuote = TRUE;
IdStart = Index;
}
}
if (Index > IdStart) {
if (InQuote == FALSE) {
break;
}
*(UqiNode->Header.Value + Index - IdStart -1) = TempChar;
Index ++;
}
}
if (IdEnd < IdStart) {
printf("The STRING is not end with \" character!\n");
return EFI_ABORTED;
}
if (IdStart == 0) {
printf("The STRING is not start with \" character!\n");
return EFI_ABORTED;
}
} else if (stricmp(Type, "NUMERIC") == 0) {
UqiNode = CreateInsertUqiNode ();
if (UqiNode == NULL) {
free (UqiBuffer);
return EFI_ABORTED;
}
UqiNode->Header.Type = NUMERIC;
UqiNode->Header.HexNum = UqiSize;
UqiNode->Header.Data = UqiBuffer;
UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
UqiNode->Header.IdNum = PlatformIdNum;
UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
if (UqiNode->Header.DefaultId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
if (UqiNode->Header.PlatformId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
}
memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
} else if (stricmp(Type, "ORDERED_LIST") == 0) {
UqiNode = CreateInsertUqiNode ();
if (UqiNode == NULL) {
free (UqiBuffer);
return EFI_ABORTED;
}
UqiNode->Header.Type = ORDERED_LIST;
UqiNode->Header.HexNum = UqiSize;
UqiNode->Header.Data = UqiBuffer;
UqiNode->Header.IdNum = PlatformIdNum;
UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
if (UqiNode->Header.DefaultId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
if (UqiNode->Header.PlatformId == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
}
memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %x", (INT32 *)&MaxContainers);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %x", (INT32 *)&MaxContainers);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
if (MaxContainers > MAX_INPUT_ALLOCATE_SIZE) {
return EFI_ABORTED;
}
UqiNode->Header.Value = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
if (UqiNode->Header.Value == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
UqiNode->Header.DiffValue = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
if (UqiNode->Header.DiffValue == NULL) {
printf ("Fali to allocate memory!\n");
return EFI_OUT_OF_RESOURCES;
}
*UqiNode->Header.Value = (UINT8) MaxContainers;
*UqiNode->Header.DiffValue = (UINT8) MaxContainers;
for (Index = 1; Index <= MaxContainers; Index++) {
if (*(UqiNode->Header.Value + Index) == '/') {
printf ("Error. Failed to parse the value of ORDERED_LIST.\n");
return EFI_INVALID_PARAMETER;
}
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %llx", ((long long *)UqiNode->Header.Value + Index));
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %llx", ((long long *)UqiNode->Header.Value + Index));
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
}
} else {
//
// Unknown type
//
// Free UQI buffer before skipping to next line
//
free(UqiBuffer);
UqiBuffer = NULL;
printf ("Error. Invalid parameters exist in scripts line %d", ScriptsLine);
return EFI_ABORTED;
}
UqiNode->Header.ScriptsLine = ScriptsLine;
//
// Skip to next line
//
do {
if (AsciiOrUcs2 == ASCII) {
fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
if (AsciiOrUcs2 == BIG_UCS2) {
TempChar = (CHAR8)TempChar16;
} else {
TempChar = (CHAR8)(TempChar16 >> 8);
}
}
} while((TempChar != '\n') && !feof(ScriptFile));
break;
case '\n':
case '\r':
//
// Newline, skip to next character
//
break;
case '/':
//
// Get the value of PlatformId and DefaultId from comments
//
do {
if (AsciiOrUcs2 == ASCII) {
fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
if (AsciiOrUcs2 == BIG_UCS2) {
TempChar = (CHAR8)TempChar16;
} else {
TempChar = (CHAR8)(TempChar16 >> 8);
}
}
//
//"/ DefaultId :"
//
if (!ReadDefaultId) {
if (TempChar == DefaultIdStr[Index1]) {
Index1++;
} else {
Index1 = 0;
}
if (Index1 == strlen (DefaultIdStr)) {
Index1 = 0;
Index3 = 0;
memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
ReadDefaultId = TRUE;
mMultiPlatformParam.MultiPlatformOrNot = TRUE;
}
} else if (ReadDefaultId) {
if (TempChar == '\n') {
ReadDefaultId = FALSE;
Array[Index3] = TempChar;
DefaultIdNum = GetNumFromAsciiString ((CHAR8 *)Array, DefaultId);
mMultiPlatformParam.KeyDefaultId[mMultiPlatformParam.KeyIdNum] = (UINT16)DefaultId[0];
} else {
Array[Index3++] = TempChar;
}
}
//
//"/ PlatformId:"
//
if (!ReadPlatformId) {
if (TempChar == PlatformIdStr[Index2]) {
Index2++;
} else {
Index2 = 0;
}
if (Index2 == strlen (PlatformIdStr)) {
Index2 = 0;
Index3 = 0;
memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
ReadPlatformId = TRUE;
}
} else if (ReadPlatformId) {
if (TempChar == '\n') {
ReadPlatformId = FALSE;
Array[Index3] = TempChar;
PlatformIdNum = GetNumFromAsciiString ((CHAR8 *)Array, PlatformId);
//
// Take the first defaultid an platformid as the key of this group
//
mMultiPlatformParam.KeyPlatformId[mMultiPlatformParam.KeyIdNum++] = PlatformId[0];
assert (DefaultIdNum == PlatformIdNum);
} else {
Array[Index3++] = TempChar;
}
}
//
//"/ PlatformIdUqi:"
//
if (!ReadPlatformIdUqi) {
if (TempChar == PlatformUqi[Index4]) {
Index4++;
} else {
Index4 = 0;
}
if (Index4 == strlen (PlatformUqi)) {
Index4 = 0;
Index3 = 0;
memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
ReadPlatformIdUqi = TRUE;
}
} else if (ReadPlatformIdUqi) {
if (mMultiPlatformParam.Uqi.HexNum > 0) {
continue;
}
//
// Read size of UQI string
//
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
if (mMultiPlatformParam.Uqi.HexNum > MAX_INPUT_ALLOCATE_SIZE) {
return EFI_ABORTED;
}
//
// Malloc buffer for string size + null termination
//
if (mMultiPlatformParam.Uqi.Data != NULL) {
free (mMultiPlatformParam.Uqi.Data);
mMultiPlatformParam.Uqi.Data = NULL;
}
mMultiPlatformParam.Uqi.Data = (CHAR16 *)calloc(mMultiPlatformParam.Uqi.HexNum + 1, sizeof(CHAR16));
if (mMultiPlatformParam.Uqi.Data == NULL) {
printf("Error. Unable to allocate 0x%04zx bytes for UQI string -- FAILURE\n", (mMultiPlatformParam.Uqi.HexNum + 1) * sizeof(CHAR16));
break;
}
//
// Read UQI string
//
for (Index = 0; Index < mMultiPlatformParam.Uqi.HexNum; Index++) {
if (AsciiOrUcs2 == ASCII) {
fscanf(ScriptFile, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
} else {
Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
if (Char8Str == NULL) {
return EFI_ABORTED;
}
sscanf(Char8Str, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
if (Char8Str != NULL) {
free (Char8Str);
Char8Str = NULL;
}
}
}
//
// Set null termination
//
mMultiPlatformParam.Uqi.Data[Index] = 0;
ReadPlatformIdUqi = FALSE;
}
} while((TempChar != '\n') && !feof(ScriptFile));
break;
//
// To do: Get and set DefaultId and PlatformId here!
//
default:
//
// Comment or garbage, skip to next line
//
do {
if (AsciiOrUcs2 == ASCII) {
fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
} else {
fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
if (AsciiOrUcs2 == BIG_UCS2) {
TempChar = (CHAR8)TempChar16;
} else {
TempChar = (CHAR8)(TempChar16 >> 8);
}
}
} while((TempChar != '\n') && !feof(ScriptFile));
break;
}
}
return EFI_SUCCESS;
}
/**
Get the offset of file name from the whole path.
@param NameStr The whole file path.
@retval Offset Return the offset of file name in path
**/
static
UINTN
GetOffsetOfFileName (
IN CHAR8 *NameStr
)
{
CHAR8 *Str;
UINTN Index;
UINTN CurIndex;
Index = 0;
CurIndex = 0;
Str = NameStr;
if (NameStr == NULL) {
return 0;
}
while (*Str != '\0') {
if (*Str == OS_SEP) {
CurIndex = Index;
}
Str++;
Index++;
}
if (*(NameStr + CurIndex) == OS_SEP) {
return CurIndex + 1;
} else {
return 0;
}
}
/**
Print the questions which is updated to the current platform successfully.
Parse the Uqi List, and print it till break NULL.
@param List Pointer to a List.
@retval EFI_SUCCESS The Print was complete successfully
@return EFI_ABORTED An error occurred
**/
static
VOID
PrintUpdateListInfo (
IN UQI_PARAM_LIST *UqiList
)
{
UINT32 Index;
UINT32 Index1;
UINT32 Index2;
UQI_PARAM_LIST *CurList;
Index1 = 0;
Index2 = 0;
Index = 0;
CurList = UqiList;
printf ("\n\n -- Update List -- ");
while (CurList != NULL) {
if (!CurList->ErrorOrNot && CurList->ParseOrNot && !CurList->SameOrNot) {
++Index;
printf ("\n\n[Script line %d] Update No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
printf ("Q %04x ", CurList->Header.HexNum);
for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
printf ("%04x ", CurList->Header.Data[Index2]);
}
if (CurList->Header.Type == ORDERED_LIST) {
printf ("ORDERED_LIST ");
} else if (CurList->Header.Type == CHECKBOX) {
printf ("CHECKBOX ");
} else if (CurList->Header.Type == ONE_OF) {
printf ("ONE_OF ");
} else if (CurList->Header.Type == NUMERIC) {
printf ("NUMERIC ");
} else if (CurList->Header.Type == STRING) {
printf ("STRING ");
} else {
printf ("UNKNOWN ");
}
//
//Print the value of scripts
//
printf ("\n[ Update Value From: ");
if (CurList->Header.Type == ORDERED_LIST) {
for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
printf ("%02x ", *(CurList->Header.DiffValue + Index2));
}
} else if (CurList->Header.Type == STRING) {
printf("\"");
WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
printf("\"");
} else {
printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
}
//
//Print the value of current platform
//
printf (" To: ");
if (CurList->Header.Type == ORDERED_LIST) {
for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
printf ("%02x ", *(CurList->Header.Value + Index2));
}
} else if (CurList->Header.Type == STRING) {
printf("\"");
WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
printf("\"");
} else {
printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
}
printf ("]");
}
CurList = CurList->Next;
}
if (Index > 1) {
printf ("\n\n\n[Results]: %d questions have been updated successfully in total. \n", Index);
} else {
printf ("\n\n\n[Results]: %d question has been updated successfully in total. \n", Index);
}
}
/**
Print the error, when update questions.
Parse the Uqi List, and print it till break NULL.
@param List The Pointer to a List.
**/
static
BOOLEAN
PrintErrorInfo (
IN UQI_PARAM_LIST *UqiList
)
{
UINT32 Index1;
UINT32 Index2;
UINT32 Index;
UQI_PARAM_LIST *CurList;
BOOLEAN IsError;
Index1 = 0;
Index2 = 0;
Index = 0;
CurList = UqiList;
IsError = FALSE;
while (CurList != NULL) {
if (CurList->ErrorOrNot && CurList->ParseOrNot) {
IsError = TRUE;
++Index;
printf ("\n\n[Script line %d] Error Information No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
printf ("Q %04x ", CurList->Header.HexNum);
for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
printf ("%04x ", CurList->Header.Data[Index2]);
}
if (CurList->Header.Type == ORDERED_LIST) {
printf ("ORDERED_LIST ");
} else if (CurList->Header.Type == CHECKBOX) {
printf ("CHECKBOX ");
} else if (CurList->Header.Type == ONE_OF) {
printf ("ONE_OF ");
} else if (CurList->Header.Type == NUMERIC) {
printf ("NUMERIC ");
} else if (CurList->Header.Type == STRING) {
printf ("STRING ");
} else {
printf ("UNKNOWN ");
}
//
//Print the Input value of scripts
//
if (CurList->Header.Type == ORDERED_LIST) {
for (Index2 = 0; Index2 <= *CurList->Header.Value; Index2++) {
printf ("%02x ", *(CurList->Header.Value + Index2));
}
} else if (CurList->Header.Type == STRING) {
printf("\"");
WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
printf("\"");
} else {
printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
}
//
//Print the Error information
//
if (CurList->Error != NULL) {
printf ("\n%s ", CurList->Error);
}
}
CurList = CurList->Next;
}
if (IsError) {
if (Index > 1) {
printf ("\n\n[Results]: Occurred %d errors during the update process. \n", Index);
} else {
printf ("\n\n[Results]: Occurred %d error during the update process. \n", Index);
}
}
return IsError;
}
/**
Any questions that exist in both the script and the current platform and have
different values will be logged to the screen.
Parse the Uqi List, and print it till break NULL.
@param List Pointer to a List.
@retval EFI_SUCCESS The Print was complete successfully
@return EFI_ABORTED An error occurreds
**/
static
VOID
PrintVerifiedListInfo (
IN UQI_PARAM_LIST *UqiList
)
{
UINT32 Index1;
UINT32 Index2;
UINT32 Index3;
UINT32 Index;
UQI_PARAM_LIST *CurList;
UINT32 StrLen;
UINT32 StrLen1;
UINT32 StrLen2;
Index1 = 0;
Index2 = 0;
Index = 0;
StrLen = 0;
CurList = UqiList;
StrLen1 = strlen (mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
StrLen2 = strlen (mInputFdName + GetOffsetOfFileName (mInputFdName));
StrLen = (StrLen1 > StrLen2) ? StrLen1:StrLen2;
printf ("\n\n -- Different List -- ");
while (CurList != NULL) {
if (!CurList->SameOrNot && CurList->ParseOrNot) {
++Index;
printf ("\n\n[Script line %d] Difference No.%d:", CurList->Header.ScriptsLine, ++Index1);
printf ("\n[%s", mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
for (Index3 = 0; Index3 < StrLen - StrLen1; Index3++) {
printf (" ");
}
printf ("]:");
printf (" Q %04x ", CurList->Header.HexNum);
for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
printf ("%04x ", CurList->Header.Data[Index2]);
}
if (CurList->Header.Type == ORDERED_LIST) {
printf ("ORDERED_LIST ");
} else if (CurList->Header.Type == CHECKBOX) {
printf ("CHECKBOX ");
} else if (CurList->Header.Type == ONE_OF) {
printf ("ONE_OF ");
} else if (CurList->Header.Type == NUMERIC) {
printf ("NUMERIC ");
} else if (CurList->Header.Type == STRING) {
printf ("STRING ");
} else {
printf ("UNKNOWN ");
}
//
//Print the Input value of scripts
//
if (CurList->Header.Type == ORDERED_LIST) {
for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
printf ("%02x ", *(CurList->Header.Value + Index2));
}
} else if (CurList->Header.Type == STRING) {
printf("\"");
WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
printf("\"");
} else {
printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
}
//
//Print the value of current platform
//
printf ("\n[%s", mInputFdName + GetOffsetOfFileName (mInputFdName));
for (Index3 = 0; Index3 < StrLen - StrLen2; Index3++) {
printf (" ");
}
printf ("]:");
printf (" Q %04x ", CurList->Header.HexNum);
for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
printf ("%04x ", CurList->Header.Data[Index2]);
}
if (CurList->Header.Type == ORDERED_LIST) {
printf ("ORDERED_LIST ");
} else if (CurList->Header.Type == CHECKBOX) {
printf ("CHECKBOX ");
} else if (CurList->Header.Type == ONE_OF) {
printf ("ONE_OF ");
} else if (CurList->Header.Type == NUMERIC) {
printf ("NUMERIC ");
} else if (CurList->Header.Type == STRING) {
printf ("STRING ");
} else {
printf ("UNKNOWN ");
}
if (CurList->Header.Type == ORDERED_LIST) {
for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
printf ("%02x ", *(CurList->Header.DiffValue + Index2));
}
} else if (CurList->Header.Type == STRING) {
printf("\"");
WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
printf("\"");
} else {
printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
}
}
CurList = CurList->Next;
}
if (Index > 1) {
printf (
"\n\n\n[Results]: There are %d differences between '%s' and '%s' in total.\n\n\n",
Index,
mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
mInputFdName + GetOffsetOfFileName (mInputFdName)
);
} else {
printf (
"\n\n\n[Results]: There is %d difference between '%s' and '%s' in total.\n\n\n",
Index,
mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
mInputFdName + GetOffsetOfFileName (mInputFdName)
);
}
}
/**
Insert Uqi object to the end of unidirection List.
@param InList The Pointer to the current object
@param UqiListEntry The pointer to the entry of UqiList
@return EFI_SUCCESS
**/
EFI_STATUS
InsertUnidirectionList (
IN UQI_PARAM_LIST *InList,
IN UQI_PARAM_LIST **UqiListEntry
)
{
UQI_PARAM_LIST **UqiCurList;
UQI_PARAM_LIST *UqiNext;
UqiCurList = NULL;
UqiNext = NULL;
if (UqiListEntry == NULL) {
return EFI_ABORTED;
}
//
// Insert to Uqi Node to UqiList
//
UqiCurList = UqiListEntry;
UqiNext = *UqiCurList;
if (UqiNext == NULL) {
//
//Insert is the first node as node header
//
*UqiCurList = InList;
} else {
while ((UqiNext != NULL) && (UqiNext->Next != NULL)) {
UqiNext = UqiNext->Next;
}
UqiNext->Next = InList;
}
return EFI_SUCCESS;
}
/**
Free variable unidirection List.
@param UqiListEntry The pointer to the entry of UqiList
@return EFI_SUCCESS
**/
EFI_STATUS
FreeUnidirectionList (
IN UQI_PARAM_LIST *UqiListEntry
)
{
UQI_PARAM_LIST *Next;
Next = NULL;
//
// Free Uqi List
//
while (UqiListEntry != NULL) {
Next = UqiListEntry->Next;
if (UqiListEntry->Header.Value != NULL) {
free (UqiListEntry->Header.Value);
}
if (UqiListEntry->Header.DiffValue != NULL) {
free (UqiListEntry->Header.DiffValue);
}
if (UqiListEntry->Header.Data != NULL) {
free (UqiListEntry->Header.Data);
}
if (UqiListEntry->Header.DefaultId != NULL) {
free (UqiListEntry->Header.DefaultId);
}
if (UqiListEntry->Header.PlatformId != NULL) {
free (UqiListEntry->Header.PlatformId);
}
if (UqiListEntry->Error != NULL) {
free (UqiListEntry->Error);
}
free (UqiListEntry);
UqiListEntry = Next;
}
return EFI_SUCCESS;
}
/**
Delete a directory and files in it.
@param DirName Name of the directory need to be deleted.
@return EFI_INVALID_PARAMETER
@return EFI_SUCCESS
**/
static
EFI_STATUS
LibRmDir (
IN CHAR8* DirName
)
{
CHAR8* SystemCommand;
SystemCommand = NULL;
if (DirName == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Delete a directory and files in it.
//
SystemCommand = malloc (
strlen (RMDIR_STR) +
strlen (DirName) +
1
);
if (SystemCommand == NULL) {
return EFI_OUT_OF_RESOURCES;
}
sprintf (
SystemCommand,
RMDIR_STR,
DirName
);
system (SystemCommand);
free(SystemCommand);
return EFI_SUCCESS;
}
/**
Pick up the FFS from the FD image.
Call BfmLib to get all FFS in one FD image, and save all which includes IFR
Binary to gEfiFdInfo structure.
@retval EFI_SUCCESS Get the address successfully.
**/
static
EFI_STATUS
PickUpFfsFromFd (
VOID
)
{
CHAR8 *SystemCommandFormatString;
CHAR8 *SystemCommand;
CHAR8 *TempSystemCommand;
CHAR8 *TemDir;
EFI_STATUS Status;
INT32 ReturnValue;
Status = EFI_SUCCESS;
SystemCommandFormatString = NULL;
SystemCommand = NULL;
TempSystemCommand = NULL;
TemDir = NULL;
ReturnValue = 0;
memset (&gEfiFdInfo, 0, sizeof (G_EFI_FD_INFO));
//
// Construction 'system' command string
//
SystemCommandFormatString = "BfmLib -e \"%s\" ";
SystemCommand = malloc (
strlen (SystemCommandFormatString) + strlen (mInputFdName) + 1
);
if (SystemCommand == NULL) {
printf ("Fail to allocate memory.\n");
return EFI_ABORTED;
}
sprintf (
SystemCommand,
"BfmLib -e \"%s\" ",
mInputFdName
);
if (mFullGuidToolDefinitionDir[0] != 0) {
TempSystemCommand = SystemCommand;
SystemCommand = malloc (
strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (TempSystemCommand) + 1
);
if (SystemCommand == NULL) {
free (TempSystemCommand);
return EFI_UNSUPPORTED;
}
strcpy (SystemCommand, mFullGuidToolDefinitionDir);
strcat (SystemCommand, OS_SEP_STR);
strcat (SystemCommand, TempSystemCommand);
free (TempSystemCommand);
}
//
// Call BfmLib to get all FFS in Temp folder of current path
//
ReturnValue = system (SystemCommand);
free (SystemCommand);
if (ReturnValue == -1) {
printf ("Error. Call BfmLib failed.\n");
return EFI_ABORTED;
}
//
//Pick up the FFS which is interrelated with the IFR binary.
//
TemDir = getcwd (NULL, _MAX_PATH);
if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME)> _MAX_PATH - 1) {
printf ("The directory is too long \n");
return EFI_ABORTED;
}
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
mMultiPlatformParam.ExistStorageFfsInBfv = FALSE;
Status = FindFileInFolder (TemDir, &mMultiPlatformParam.ExistStorageFfsInBfv, &mMultiPlatformParam.SizeOptimized);
return Status;
}
#define BUILD_IN_TOOL_COUNT 4
/**
Generate pre-defined guided tools data.
@return An EFI_HANDLE contain guided tools data.
**/
static
EFI_HANDLE
PreDefinedGuidedTools (
VOID
)
{
EFI_GUID Guid;
STRING_LIST *Tool;
GUID_SEC_TOOL_ENTRY *FirstGuidTool;
GUID_SEC_TOOL_ENTRY *LastGuidTool;
GUID_SEC_TOOL_ENTRY *NewGuidTool;
UINT8 Index;
EFI_STATUS Status;
CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
"a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
"ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
"fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
"3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
};
Tool = NULL;
FirstGuidTool = NULL;
LastGuidTool = NULL;
NewGuidTool = NULL;
for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
if ((Tool != NULL) &&
(Tool->Count == 3)
) {
Status = StringToGuid (Tool->Strings[0], &Guid);
if (!EFI_ERROR (Status)) {
NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
if (NewGuidTool != NULL) {
memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
NewGuidTool->Name = CloneString(Tool->Strings[1]);
NewGuidTool->Path = CloneString(Tool->Strings[2]);
NewGuidTool->Next = NULL;
} else {
printf ( "Fail to allocate memory. \n");
if (Tool != NULL) {
FreeStringList (Tool);
}
return NULL;
}
if (FirstGuidTool == NULL) {
FirstGuidTool = NewGuidTool;
} else {
LastGuidTool->Next = NewGuidTool;
}
LastGuidTool = NewGuidTool;
}
} else {
fprintf (stdout, "Error");
}
if (Tool != NULL) {
FreeStringList (Tool);
Tool = NULL;
}
}
return FirstGuidTool;
}
/**
Read all storages under a specified platformId and defaultId from BFV.
@param Binary The pointer to the buffer of binary.
@param StorageListEntry The pointer to the storage list.
@return length The length of storage
**/
UINT32
ReadStorageFromBinary (
IN UINT8 *Binary,
IN LIST_ENTRY *StorageListEntry
)
{
UINT32 Length;
UINT8 *DataBase;
BOOLEAN AuthencitatedMonotonicOrNot;
BOOLEAN AuthencitatedBasedTimeOrNot;
Length = 0;
AuthencitatedMonotonicOrNot = FALSE;
AuthencitatedBasedTimeOrNot = FALSE;
DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
//
// Judge the layout of NV by Variable Guid
//
AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((VOID *)(DataBase + *(UINT16 *)DataBase));
AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((VOID *)(DataBase + *(UINT16 *)DataBase));
if (AuthencitatedMonotonicOrNot) {
//
// Read variable with Monotonic based layout from binary
//
Length = ReadMonotonicBasedVariableToList (Binary, StorageListEntry);
} else if (AuthencitatedBasedTimeOrNot){
//
// Read variable with time-based layout from binary
//
Length = ReadTimeBasedVariableToList (Binary, StorageListEntry);
} else {
//
// Read variable with normal layout from binary
//
Length = ReadVariableToList (Binary, StorageListEntry);
}
return Length;
}
/**
Insert one storage to the raw bianry, and return its length.
@param Storage The pointer to a storage in storage list.
@param Binary The pointer to the buffer of binary.
@return length The length of storage
**/
UINT32
PutStorageToBinary (
IN FORMSET_STORAGE *Storage,
IN UINT8 *Binary,
IN LIST_ENTRY *StorageListEntry
)
{
EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
UINT32 Length;
UINT32 Index;
UINT8 *BinaryBeginning;
FORMSET_STORAGE *CurStorage;
LIST_ENTRY *StorageLink;
VOID *VariableStoreHeader;
BOOLEAN AuthencitatedMonotonicOrNot;
BOOLEAN AuthencitatedBasedTimeOrNot;
VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
Length = 0;
Index = 0;
BinaryBeginning = Binary;
VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
AuthencitatedMonotonicOrNot = FALSE;
AuthencitatedBasedTimeOrNot = FALSE;
//
// Judge the layout of NV by gEfiVariableGuid
//
AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
//
// Build the binary for BFV
//
StorageLink = GetFirstNode (StorageListEntry);
while (!IsNull (StorageListEntry, StorageLink)) {
CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if ((CurStorage->DefaultId[0] == Storage->DefaultId[0])
&& (CurStorage->PlatformId[0] == Storage->PlatformId[0])
&& !CurStorage->Skip
) {
CurStorage->Skip = TRUE;
if (AuthencitatedMonotonicOrNot) {
//
// Copy variable with Monotonic based layout to binary
//
Length = CopyMonotonicBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
} else if (AuthencitatedBasedTimeOrNot){
//
// Copy variable with time-based layout to binary
//
Length = CopyTimeBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
} else {
//
// Copy variable with normall layout to binary
//
Length = CopyVariableToBinary (CurStorage, BinaryBeginning, Index);
}
Index++;
}
StorageLink = GetNextNode (StorageListEntry, StorageLink);
}
//
// Fix the length of storage header under a specified DefaultId and PlatformId
//
if (AuthencitatedMonotonicOrNot) {
FixMontonicVariableHeaderSize (BinaryBeginning, Length);
} else if (AuthencitatedBasedTimeOrNot){
FixBasedTimeVariableHeaderSize (BinaryBeginning, Length);
} else {
FixVariableHeaderSize (BinaryBeginning, Length);
}
return Length;
}
/**
Insert one storage to Fd's NvStoreDatabase, and return its length.
@param Storage The pointer to a storage in storage list.
@param Binary The pointer to the buffer of binary.
@return length The length of storage
**/
UINT32
PutStorageToNvStoreBinary (
IN FORMSET_STORAGE *Storage,
IN UINT8 *Binary,
IN LIST_ENTRY *StorageListEntry
)
{
UINT32 Length;
UINT32 Index;
UINT8 *BinaryBeginning;
FORMSET_STORAGE *CurStorage;
LIST_ENTRY *StorageLink;
Length = 0;
Index = 0;
BinaryBeginning = Binary;
//
// Build the binary for NvStorDatabase
//
StorageLink = GetFirstNode (StorageListEntry);
while (!IsNull (StorageListEntry, StorageLink)) {
CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if ((CurStorage->PlatformId[0] == Storage->PlatformId[0])
&& (CurStorage->DefaultId[0] == Storage->DefaultId[0])
&& !CurStorage->Skip
) {
CurStorage->Skip = TRUE;
Length = CopyVariableToNvStoreBinary (CurStorage, BinaryBeginning, Index);
Index++;
}
StorageLink = GetNextNode (StorageListEntry, StorageLink);
}
// Alignment
Length = (Length + 3) & ~3;
FixNvStoreVariableHeaderSize (BinaryBeginning, Length);
return Length;
}
/**
Optimize the Delta binary size based on the default setting binary, and
create a new binary with new size on the Storage.ffs.
@param DefaultBinary The pointer to a default setting binary
@param DefaultHeaderLen The header lenght of default setting binary
@param DeltaBinary The pointer to a delta setting binary
@param CurrentSize The size of current delta data.
@return length The length of new storage
**/
UINT32
OptimizeStorageDeltaData (
IN UINT8 *DefaultBinary,
IN UINT8 *CurrentBinary,
IN OUT UINT8 *DeltaBinary,
IN UINT32 CurrentSize
)
{
UINT32 Size;
UINT16 Index;
UINT32 DefaultHeaderSize;
UINT32 DeltaHeaderSize;
UINT32 AlignSize;
PCD_DATA_DELTA DeltaData;
DefaultHeaderSize = ((PCD_DEFAULT_DATA *)DefaultBinary)->HeaderSize + 4;
DeltaHeaderSize = ((PCD_DEFAULT_DATA *)CurrentBinary)->HeaderSize + 4;
//
// Copy the Delta Header directly
//
Size = DeltaHeaderSize;
memcpy (DeltaBinary, CurrentBinary, Size);
//
// Compare the delta data and optimize the size
//
for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
DeltaData.Offset = Index;
DeltaData.Value = *(CurrentBinary + DeltaHeaderSize + Index);
memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
Size = Size + sizeof(DeltaData);
}
}
*(UINT32 *)DeltaBinary = Size;
AlignSize = (Size + 7) & ~7;
//set Alignment data 0x00
for (Index = 0; Index < AlignSize - Size; Index++){
*(DeltaBinary + Size + Index) = 0x0;
}
return Size;
}
/**
Optimize the Delta binary size based on the default setting binary, and
create a new binary with new size on the Storage.ffs.
@param DefaultBinary The pointer to a default setting binary
@param DefaultHeaderLen The header lenght of default setting binary
@param DeltaBinary The pointer to a delta setting binary
@param CurrentSize The size of current delta data.
@return length The length of new storage
**/
UINT32
OptimizeStorageSection (
IN UINT8 *DefaultBinary,
IN UINT8 *CurrentBinary,
IN OUT UINT8 *DeltaBinary,
IN UINT32 CurrentSize
)
{
UINT32 Size;
UINT16 Index;
UINT32 DefaultHeaderSize;
UINT32 DeltaHeaderSize;
DATA_DELTA DeltaData;
DefaultHeaderSize = *(UINT16 *)DefaultBinary;
DeltaHeaderSize = *(UINT16 *)CurrentBinary;
//
// Copy the Delta Header directly
//
Size = DeltaHeaderSize;
memcpy (DeltaBinary, CurrentBinary, Size);
//
// Compare the delta data and optimize the size
//
for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
DeltaData.Offset = Index;
DeltaData.Value = *(CurrentBinary + DeltaHeaderSize + Index);
memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
Size = Size + sizeof(DeltaData);
}
}
return Size;
}
/**
Create the storage section and copy it to memory.
@param Buffer The pointer to the buffer
@param Size The size of input buffer.
@return the new size
**/
UINT32
CreateStorageSection (
IN OUT UINT8 *Buffer,
IN UINT32 Size,
IN CHAR8 *FileName
)
{
FILE *BinaryFd;
UINTN BytesWrite;
UINT32 SectionSize;
BinaryFd = NULL;
//
// Create the raw section files in FFS
//
BinaryFd = fopen (FileName, "wb+");
if (BinaryFd == NULL) {
printf ("Error. Failed to create the raw data section.\n");
return 0;
}
fseek (BinaryFd, 0, SEEK_SET);
BytesWrite = fwrite (Buffer, sizeof (CHAR8), Size, BinaryFd);
fclose (BinaryFd);
if (BytesWrite != Size) {
printf ("Error. Failed to write the raw data section.\n");
return 0;
}
CreateRawSection (FileName, FileName);
BinaryFd = fopen (FileName, "rb");
if (BinaryFd == NULL) {
printf ("Error. Failed to open the raw data section.\n");
return 0;
}
fseek (BinaryFd, 0, SEEK_SET);
BytesWrite = fread (Buffer, sizeof (CHAR8), (Size + sizeof (EFI_COMMON_SECTION_HEADER)), BinaryFd);
fclose (BinaryFd);
if (BytesWrite != (Size + sizeof (EFI_COMMON_SECTION_HEADER))) {
printf ("Error. Failed to read the raw data section.\n");
return 0;
}
SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)Buffer)->Size);
return SectionSize;
}
/**
Read NvStoreDataBase and insert it to the Storage list.
@param InputFdName The pointer to the input fd name.
@param VarListEntry The pointer to the variable list.
@return EFI_INVALID_PARAMETER
@return EFI_SUCCESS
**/
EFI_STATUS
ReadStorageFromNvStoreDatabase (
IN LIST_ENTRY *VarListEntry
)
{
UINT8 *Binary;
UINT8 *FullBinary;
UINT8 *VarDataBinary;
UINT8 *PreVarDataBinary;
UINT8 *DataBase;
PCD_DEFAULT_DATA *DeltaVarStoreHeader;
PCD_DEFAULT_DATA *PrePcdDefaultData;
UINT8 *DeltaData;
UINT32 DeltaSize;
UINT32 DataSize;
UINT32 HeaderSize;
UINT32 BinaryLength;
UINT32 Size;
UINT32 PreVarDataSize;
PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
UINT32 Offset;
UINT32 Value;
UINT32 Index;
BinaryLength = 0;
Binary = NULL;
FullBinary = NULL;
DataBase = NULL;
DeltaVarStoreHeader = NULL;
PreVarDataBinary = NULL;
PreVarDataSize = 0;
DeltaSize = 0;
Size = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER);
VarDataBinary = NULL;
//
// Check whether the FD has included the storage FFS
//
//if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
// return EFI_ABORTED;
//}
NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)gEfiFdInfo.NvStoreDatabase;
BinaryLength = NvStoreHeader->Length;
Binary = (UINT8 *)gEfiFdInfo.NvStoreDatabase;
//
// If detect size optimized format, transfer it to normal format
// before parse it
//
if (mMultiPlatformParam.SizeOptimized) {
FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
if (FullBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
return EFI_ABORTED;
}
}
while (Size < BinaryLength) {
DataBase = Binary + Size;
DataSize = *(UINT32 *)DataBase;
if (Size == sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
PrePcdDefaultData = (PCD_DEFAULT_DATA *) DataBase;
HeaderSize = PrePcdDefaultData->HeaderSize;
PreVarDataSize = DataSize - 4 - HeaderSize;
VarDataBinary = malloc(DataSize);
if (VarDataBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
return EFI_ABORTED;
}
memcpy (VarDataBinary, DataBase, DataSize);
PreVarDataBinary = malloc(DataSize - 4 - HeaderSize);
if (PreVarDataBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
return EFI_ABORTED;
}
memcpy (PreVarDataBinary, DataBase + 4 + HeaderSize , DataSize - 4 - HeaderSize);
} else {
DeltaVarStoreHeader = (PCD_DEFAULT_DATA *)DataBase;
DeltaSize = DeltaVarStoreHeader->DataSize;
HeaderSize = DeltaVarStoreHeader->HeaderSize;
DeltaData = (UINT8*) DeltaVarStoreHeader;
VarDataBinary = malloc(PreVarDataSize + HeaderSize + 4);
if (VarDataBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
return EFI_ABORTED;
}
//
// Copy the default setting data
//
memcpy (VarDataBinary, DataBase, HeaderSize + 4);
memcpy (VarDataBinary + HeaderSize + 4, PreVarDataBinary, PreVarDataSize);
//
// Merge the delta data with default setting to get the full delta data
//
for (Index = 0; Index < (DeltaSize - HeaderSize - 4)/sizeof(PCD_DATA_DELTA); Index++) {
Offset = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Offset;
Value = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Value;
if (*(VarDataBinary + HeaderSize + 4 + Offset) != Value) {
*(VarDataBinary + HeaderSize + 4 + Offset) = (UINT8)Value;
}
}
}
//
// Store the Variable Data to VarListEntry
//
ReadNvStoreVariableToList(VarDataBinary, VarListEntry);
Size += (DataSize + 7) & ~7;
}
if (VarDataBinary != NULL) {
free (VarDataBinary);
}
return EFI_SUCCESS;
}
/**
Read FFS from BFV and insert it to the Storage list.
@param InputFdName The pointer to the input fd name.
@param VarListEntry The pointer to the variable list.
@return EFI_INVALID_PARAMETER
@return EFI_SUCCESS
**/
EFI_STATUS
ReadStorageFromBfv (
IN LIST_ENTRY *VarListEntry
)
{
UINT8 *Binary;
UINT8 *FullBinary;
UINT8 *DataBase;
UINT8 *PreVarStoreHeader;
DATA_DELTA *DeltaVarStoreHeader;
UINT8 *DeltaData;
UINT32 PreDataSize;
UINT32 DeltaSize;
UINT32 BinaryLength;
UINT32 Size;
UINT32 SectionSize;
UINT32 FullSectionLen;
UINT32 FullSectionSize;
EFI_FFS_FILE_HEADER *FfsHeader;
UINT16 Offset;
UINT8 Value;
UINT32 Index;
CHAR8 *SectionName;
BinaryLength = 0;
Binary = NULL;
FullBinary = NULL;
DataBase = NULL;
PreVarStoreHeader = NULL;
DeltaVarStoreHeader = NULL;
PreDataSize = 0;
DeltaSize = 0;
FullSectionSize = 0;
Size = sizeof (EFI_FFS_FILE_HEADER);
FfsHeader = NULL;
FullSectionLen = 0;
SectionName = NULL;
SectionName = getcwd(NULL, _MAX_PATH);
if (strlen (SectionName) + 2 * strlen (OS_SEP_STR) + strlen ("Temp") + strlen ("TempSection.sec") >
_MAX_PATH - 1) {
printf ("Error. The current path is too long.\n");
return EFI_INVALID_PARAMETER;
}
sprintf (SectionName + strlen (SectionName), "%cTemp%cTempSection.sec", OS_SEP, OS_SEP);
//
// Check whether the FD has included the storage FFS
//
if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
return EFI_ABORTED;
}
FfsHeader = (EFI_FFS_FILE_HEADER *)gEfiFdInfo.StorageFfsInBfv;
BinaryLength = FvBufExpand3ByteSize (FfsHeader->Size);
Binary = (UINT8 *)FfsHeader;
//
// If detect size optimized format, transfer it to normal format
// before parse it
//
if (mMultiPlatformParam.SizeOptimized) {
FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
if (FullBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
return EFI_ABORTED;
}
while (Size < BinaryLength) {
SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)(Binary + Size))->Size);
DataBase = Binary + Size + sizeof (EFI_COMMON_SECTION_HEADER);
if (Size == sizeof (EFI_FFS_FILE_HEADER)) {
PreVarStoreHeader = DataBase + *(UINT16 *)DataBase;
PreDataSize = SectionSize - (*(UINT16 *)DataBase + sizeof(EFI_COMMON_SECTION_HEADER));
memcpy (FullBinary, DataBase, SectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
FullSectionLen = CreateStorageSection (FullBinary, *(UINT16 *)DataBase + PreDataSize, SectionName);
} else {
DeltaVarStoreHeader = (DATA_DELTA *)(DataBase + *(UINT16 *)DataBase);
DeltaSize = *(UINT16 *)DataBase + PreDataSize;
DeltaData = FullBinary + FullSectionSize + *(UINT16 *)DataBase;
//
// Copy the DefaultId and PlatformId directly
//
memcpy (FullBinary + FullSectionSize, DataBase, *(UINT16 *)DataBase);
//
// Copy the default setting data
//
memcpy (DeltaData, PreVarStoreHeader, PreDataSize);
//
// Merge the delta data with default setting to get the full delta data
//
for (Index = 0; Index < (SectionSize - *(UINT16 *)DataBase - sizeof(EFI_COMMON_SECTION_HEADER))/sizeof(DATA_DELTA); Index++) {
Offset = (DeltaVarStoreHeader + Index)->Offset;
Value = (DeltaVarStoreHeader + Index)->Value;
if (*(DeltaData + Offset) != Value) {
*(DeltaData + Offset) = Value;
}
}
FullSectionLen = CreateStorageSection (FullBinary + FullSectionSize, DeltaSize, SectionName);
}
//
// Store the previous binary information
//
DataBase = FullBinary + FullSectionSize + sizeof (EFI_COMMON_SECTION_HEADER);
PreVarStoreHeader = DataBase + *(UINT16 *)DataBase;
Size += (SectionSize + 3) & ~3;
FullSectionSize += (FullSectionLen + 3) & ~3;;
}
//
// Update to the new size
//
BinaryLength = FullSectionSize;
Binary = FullBinary;
Size = 0;
}
//
// Read the storage from BFV and insert to storage list
//
while (Size < BinaryLength) {
SectionSize = ReadStorageFromBinary ((Binary + Size), VarListEntry);
Size += (SectionSize + 3) & ~3;
}
if (FullBinary != NULL) {
free (FullBinary);
}
return EFI_SUCCESS;
}
#define SIZE_64K 0x10000
/**
Create the storage and insert it to BFV by calling BfmLib.
@param InputFdName The pointer to the input fd name.
@param OutputFdName The pointer to the input fd name.
@param VarListEntry The pointer to the variable list.
@return EFI_INVALID_PARAMETER
@return EFI_SUCCESS
**/
EFI_STATUS
InsertBinaryToBfv (
IN CHAR8 *InputFdName,
IN CHAR8 *OutputFdName,
IN LIST_ENTRY *VarListEntry
)
{
UINT8 *Binary;
UINT8 *PreBinary;
UINT32 BinaryLength;
UINT32 PreBinaryLength;
UINT32 OptimizedBinaryLength;
UINT32 Size;
UINT32 OptimizedSize;
EFI_STATUS Status;
LIST_ENTRY *StorageLink;
FORMSET_STORAGE *Storage;
CHAR8 *SystemCommandFormatString;
CHAR8 *SectionNameFormatString;
CHAR8 *SystemCommand;
CHAR8 *TempSystemCommand;
INT32 ReturnValue;
CHAR8 *FileName;
BOOLEAN SizeOptimizedFlag;
CHAR8 *SectionName[_MAXIMUM_SECTION_FILE_NUM];
UINT32 Index;
CHAR8 *TemDir;
//
// Workaround for static code checkers.
// Ensures the size of 'IndexStr' can hold all the digits of an unsigned
// 32-bit integer.
//
CHAR8 IndexStr[16];
BinaryLength = 0;
PreBinaryLength = 0;
Storage = NULL;
StorageLink = NULL;
Binary = NULL;
PreBinary = NULL;
Size = 0;
OptimizedSize = 0;
Status = EFI_SUCCESS;
SystemCommandFormatString = NULL;
SectionNameFormatString = NULL;
SystemCommand = NULL;
TempSystemCommand = NULL;
SizeOptimizedFlag = FALSE;
Index = 0;
FileName = NULL;
TemDir = getcwd (NULL, _MAX_PATH);
SectionNameFormatString = "%s%cTemp%c%s.sec";
memset (SectionName, 0, _MAXIMUM_SECTION_FILE_NUM * sizeof(CHAR8 *));
FileName = malloc (strlen (TemDir) + 1 + strlen ("Storage.ffs") + 1);
if (FileName == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
sprintf (FileName, "%s%cStorage.ffs", TemDir, OS_SEP);
//
// Allocate the buffer which is the same with the input FD
//
Binary = malloc (SIZE_64K);
if (Binary == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
PreBinary = malloc (SIZE_64K);
if (PreBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
//
// If already existed a Storage.ffs in FD, keep the same format when execute update operation whatever input -a or not -a options.
//
if (mMultiPlatformParam.SizeOptimized
|| (!mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam)
) {
SizeOptimizedFlag = TRUE;
} else if (mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam && !mMultiPlatformParam.SizeOptimized) {
printf ("\nWarning. The \"-a\" parameter is ignored.\n");
}
//
// Build the binary for BFV
//
StorageLink = GetFirstNode (VarListEntry);
while (!IsNull (VarListEntry, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if (!Storage->Skip) {
//
// Assign the section name under the Temp directory
//
sprintf (IndexStr, "%d", Index);
SectionName[Index] = calloc (
strlen (SectionNameFormatString) + strlen (TemDir) + strlen(IndexStr) + 1,
sizeof(CHAR8)
);
if (SectionName[Index] == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
sprintf (
SectionName[Index],
"%s%cTemp%c%s.sec",
TemDir,
OS_SEP,
OS_SEP,
IndexStr
);
memset(Binary, 0, SIZE_64K);
Size = PutStorageToBinary (Storage, Binary, VarListEntry);
assert (Size < SIZE_64K);
//
// Re-calculate the storage section by size optimization
//
if (PreBinaryLength != 0 && SizeOptimizedFlag) {
OptimizedSize = OptimizeStorageSection (
PreBinary + sizeof (EFI_COMMON_SECTION_HEADER),
Binary,
PreBinary + PreBinaryLength,
Size
);
if (OptimizedSize == 0) {
printf ("Error. Failed to optimize the storage section.\n");
Status = EFI_ABORTED;
goto Done;
}
}
//
// Create the raw section with normal format
//
assert (Size < SIZE_64K - sizeof (EFI_COMMON_SECTION_HEADER));
BinaryLength = CreateStorageSection (Binary, Size, SectionName[Index]);
if (BinaryLength == 0) {
printf ("Error. Failed to create the storage section.\n");
Status = EFI_ABORTED;
goto Done;
}
assert (BinaryLength < SIZE_64K);
//
// Create the raw section with optimized format
//
if (PreBinaryLength != 0 && SizeOptimizedFlag) {
OptimizedBinaryLength = CreateStorageSection (PreBinary + PreBinaryLength, OptimizedSize, SectionName[Index]);
if (OptimizedBinaryLength == 0) {
printf ("Error. Failed to create the storage section.\n");
Status = EFI_ABORTED;
goto Done;
}
}
PreBinaryLength = BinaryLength;
memcpy (PreBinary, Binary, PreBinaryLength);
Index++;
}
StorageLink = GetNextNode (VarListEntry, StorageLink);
}
//
// Create the raw ffs by GenFfs
//
CreateRawFfs (&SectionName[0], FileName, SizeOptimizedFlag);
//
// Call BfmLib to insert this binary into the BFV of FD.
//
//
// Construction 'system' command string
//
if (mMultiPlatformParam.ExistStorageFfsInBfv) {
if (mFvNameGuidString != NULL) {
SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s";
SystemCommand = malloc (
strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
);
if (SystemCommand == NULL) {
Status = EFI_ABORTED;
goto Done;
}
sprintf (
SystemCommand,
"BfmLib -r \"%s\" \"%s\" \"%s\" -g %s",
mInputFdName,
FileName,
mOutputFdName,
mFvNameGuidString
);
} else {
SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\"";
SystemCommand = malloc (
strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
);
if (SystemCommand == NULL) {
Status = EFI_ABORTED;
goto Done;
}
sprintf (
SystemCommand,
"BfmLib -r \"%s\" \"%s\" \"%s\"",
mInputFdName,
FileName,
mOutputFdName
);
}
} else {
if (mFvNameGuidString != NULL) {
SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s";
SystemCommand = malloc (
strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
);
if (SystemCommand == NULL) {
Status = EFI_ABORTED;
goto Done;
}
sprintf (
SystemCommand,
"BfmLib -i \"%s\" \"%s\" \"%s\" -g %s",
mInputFdName,
FileName,
mOutputFdName,
mFvNameGuidString
);
} else {
SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\"";
SystemCommand = malloc (
strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
);
if (SystemCommand == NULL) {
Status = EFI_ABORTED;
goto Done;
}
sprintf (
SystemCommand,
"BfmLib -i \"%s\" \"%s\" \"%s\"",
mInputFdName,
FileName,
mOutputFdName
);
}
}
if (mFullGuidToolDefinitionDir[0] != 0) {
TempSystemCommand = SystemCommand;
SystemCommand = malloc (
strlen (mFullGuidToolDefinitionDir) + strlen ("\\") + strlen (TempSystemCommand ) + 1
);
if (SystemCommand == NULL) {
free (TempSystemCommand);
goto Done;
}
strcpy (SystemCommand, mFullGuidToolDefinitionDir);
strcat (SystemCommand, OS_SEP_STR);
strcat (SystemCommand, TempSystemCommand);
free (TempSystemCommand);
}
ReturnValue = system (SystemCommand);
free (SystemCommand);
remove (FileName);
if (ReturnValue == -1) {
Status = EFI_ABORTED;
}
Done:
for (Index = 0; SectionName[Index] != NULL; Index++) {
free (SectionName[Index]);
}
if (PreBinary != NULL) {
free (PreBinary);
}
if (Binary) {
free (Binary);
}
return Status;
}
/**
Create the storage and insert it to NvStoreDatabase.
@param InputFdName The pointer to the input fd name.
@param OutputFdName The pointer to the input fd name.
@param VarListEntry The pointer to the variable list.
@return EFI_INVALID_PARAMETER
@return EFI_SUCCESS
**/
EFI_STATUS
InsertBinaryToNvStoreDatabase (
IN CHAR8 *InputFdName,
IN CHAR8 *OutputFdName,
IN LIST_ENTRY *VarListEntry
)
{
UINT8 *Binary;
UINT8 *PreBinary;
UINT8 *NvStoreDatabaseBuffer;
UINT32 PreBinaryLength;
UINT32 Size;
UINT32 NvStoreDatabaseSize;
UINT32 OptimizedSize;
EFI_STATUS Status;
LIST_ENTRY *StorageLink;
FORMSET_STORAGE *Storage;
BOOLEAN SizeOptimizedFlag;
PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreBufferHeader;
PCD_DEFAULT_DATA *PcdDefaultData;
//
// Workaround for static code checkers.
// Ensures the size of 'IndexStr' can hold all the digits of an unsigned
// 32-bit integer.
//
PreBinaryLength = 0;
Storage = NULL;
StorageLink = NULL;
Binary = NULL;
PreBinary = NULL;
NvStoreDatabaseBuffer = NULL;
PcdDefaultData = NULL;
Size = 0;
NvStoreDatabaseSize = 0;
OptimizedSize = 0;
Status = EFI_SUCCESS;
SizeOptimizedFlag = FALSE;
//
// Allocate the buffer which is the same with the input FD
//
Binary = malloc (SIZE_64K);
if (Binary == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
NvStoreBufferHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *) gEfiFdInfo.NvStoreDatabase;
NvStoreDatabaseBuffer = malloc (NvStoreBufferHeader->MaxLength);
if (NvStoreDatabaseBuffer == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
memcpy(NvStoreDatabaseBuffer, gEfiFdInfo.NvStoreDatabase, NvStoreBufferHeader->MaxLength);
PreBinary = malloc (SIZE_64K);
if (PreBinary == NULL) {
printf ("Error. Memory allocation failed.\n");
Status = EFI_ABORTED;
goto Done;
}
if (gEfiFdInfo.ExistNvStoreDatabase) {
SizeOptimizedFlag = TRUE;
} else {
Status = EFI_ABORTED;
goto Done;
}
//
// Build the binary for BFV
//
StorageLink = GetFirstNode (VarListEntry);
while (!IsNull (VarListEntry, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if (!Storage->Skip) {
memset(Binary, 0, SIZE_64K);
Size = PutStorageToNvStoreBinary (Storage, Binary, VarListEntry);
assert (Size < SIZE_64K);
//
// Re-calculate the storage section by size optimization
//
if (PreBinaryLength != 0 && SizeOptimizedFlag) {
OptimizedSize = OptimizeStorageDeltaData (
PreBinary,
Binary,
NvStoreDatabaseBuffer + NvStoreDatabaseSize,
Size
);
if (OptimizedSize == 0) {
printf ("Error. Failed to optimize the storage section.\n");
Status = EFI_ABORTED;
goto Done;
}
//Alignment
OptimizedSize = (OptimizedSize + 7) & ~7;
NvStoreDatabaseSize += OptimizedSize;
} else {
//Alignment
Size = (Size + 7) & ~7;
PcdDefaultData = (PCD_DEFAULT_DATA *)Binary;
memcpy(NvStoreDatabaseBuffer + sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER), Binary, Size + PcdDefaultData->HeaderSize + 4 );
PreBinaryLength = Size + PcdDefaultData->HeaderSize + 4;
NvStoreDatabaseSize = sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + PreBinaryLength;
memcpy(PreBinary, Binary, PreBinaryLength);
}
}
StorageLink = GetNextNode (VarListEntry, StorageLink);
}
if (NvStoreBufferHeader->Length != NvStoreDatabaseSize) {
((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)NvStoreDatabaseBuffer)->Length = NvStoreDatabaseSize;
}
memcpy(gEfiFdInfo.NvStoreDatabase, NvStoreDatabaseBuffer, NvStoreDatabaseSize);
Done:
DestroyAllStorage (&mAllVarListEntry);
if (PreBinary != NULL) {
free (PreBinary);
}
if (Binary) {
free (Binary);
}
return Status;
}
extern UINT32 mMaxCount;
extern UINT32 mCount;
extern CHAR8 *mStringBuffer;
/**
Read the HII configure file from all FFS
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
ReadCongFile (
VOID
)
{
EFI_STATUS Status;
UINT32 Index;
UINT16 DefaultIndex;
UINT16 PlatformIndex;
UINT16 PreDefaultId;
UINT64 PrePlatformId;
LIST_ENTRY NewStorageListHead;
BOOLEAN BfvOverried;
FORMSET_STORAGE *Storage;
LIST_ENTRY *StorageLink;
Storage = NULL;
Status = EFI_SUCCESS;
BfvOverried = FALSE;
Index = 0;
PreDefaultId = 0xFFFF;
PrePlatformId = 0xFFFFFFFFFFFFFFFF;
//
// Read all Ifr information to Formset list
//
for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
Status = ReadAllIfrToFromset (
gEfiFdInfo.FfsArray[Index],
gEfiFdInfo.Length[Index]
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// Read defaultId and platformId
//
if (!gEfiFdInfo.ExistNvStoreDatabase) {
Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// If existed the variable data in BFV, abstract them to a variable list.
// If not exsited, just skip it.
//
if (mMultiPlatformParam.MultiPlatformOrNot) {
if (gEfiFdInfo.ExistNvStoreDatabase) {
Status = ReadStorageFromNvStoreDatabase(&mBfvVarListEntry);
} else {
Status = ReadStorageFromBfv (&mBfvVarListEntry);
}
if (!EFI_ERROR (Status)) {
BfvOverried = TRUE;
}
}
//
// If not existed the storage data in BFV, evaluate the
// default value according to the defaultId and platformId
// Or else, skip it.
//
if (!BfvOverried) {
Status = EvaluateTheValueInFormset (FALSE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// Output the question and value information on screen
//
if (mMultiPlatformParam.MultiPlatformOrNot) {
//
// Multi-platform mode support
//
if (gEfiFdInfo.ExistNvStoreDatabase) {
StorageLink = GetFirstNode (&mBfvVarListEntry);
while (!IsNull (&mBfvVarListEntry, StorageLink)) {
Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
continue;
} else {
PreDefaultId = Storage->DefaultId[0];
PrePlatformId = Storage->PlatformId[0];
}
InitializeListHead(&NewStorageListHead);
//
// Use the varaible stroage list from BFV
//
Status = BuildVariableList(
&NewStorageListHead,
&mBfvVarListEntry,
Storage->DefaultId[0],
Storage->PlatformId[0],
FALSE,
READ
);
if (EFI_ERROR (Status)) {
DestroyAllStorage (&NewStorageListHead);
return EFI_ABORTED;
}
if (IsListEmpty (&NewStorageListHead)) {
continue;
}
Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
if (EFI_ERROR (Status)) {
DestroyAllStorage (&NewStorageListHead);
return EFI_ABORTED;
}
DestroyAllStorage (&NewStorageListHead);
StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
}
} else {
for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
InitializeListHead(&NewStorageListHead);
if (BfvOverried) {
//
// Use the varaible stroage list from BFV
//
Status = BuildVariableList(
&NewStorageListHead,
&mBfvVarListEntry,
mMultiPlatformParam.DefaultId[DefaultIndex],
mMultiPlatformParam.PlatformId[PlatformIndex],
FALSE,
READ
);
} else {
//
// Use the varaible storage list from IFR
//
Status = BuildVariableList(
&NewStorageListHead,
&mAllVarListEntry,
mMultiPlatformParam.DefaultId[DefaultIndex],
mMultiPlatformParam.PlatformId[PlatformIndex],
FALSE,
READ
);
}
if (EFI_ERROR (Status)) {
DestroyAllStorage (&NewStorageListHead);
return EFI_ABORTED;
}
if (IsListEmpty (&NewStorageListHead)) {
continue;
}
Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
if (EFI_ERROR (Status)) {
DestroyAllStorage (&NewStorageListHead);
return EFI_ABORTED;
}
DestroyAllStorage (&NewStorageListHead);
}
}
}
} else {
Status = PrintInfoInAllFormset (&mFormSetListEntry, &mAllVarListEntry);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
return Status;
}
/**
Update the HII setup value.
Read the Config information from config file, and then compare it with the current FFS.
Record the different value to EFI variable.
@param Fv the Pointer to the FFS
@param Length the length of FFS
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
UpdateCongFile (
VOID
)
{
EFI_STATUS Status;
UINT32 Index;
BOOLEAN BfvOverried;
Status = EFI_SUCCESS;
BfvOverried = FALSE;
Index = 0;
//
// Read all Ifr information to Formset list
//
for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
Status = ReadAllIfrToFromset (
gEfiFdInfo.FfsArray[Index],
gEfiFdInfo.Length[Index]
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// Read defaultId and platformId
//
if (!gEfiFdInfo.ExistNvStoreDatabase) {
Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// If existed the variable data in BFV, abstract them to a variable list.
// If not exsited, just skip it.
//
if (mMultiPlatformParam.MultiPlatformOrNot) {
if (gEfiFdInfo.ExistNvStoreDatabase) {
Status = ReadStorageFromNvStoreDatabase (&mBfvVarListEntry);
} else {
Status = ReadStorageFromBfv (&mBfvVarListEntry);
}
if (!EFI_ERROR (Status)) {
BfvOverried = TRUE;
}
}
if (mMultiPlatformParam.MultiPlatformOrNot && BfvOverried) {
if (mUqiList == NULL) {
return EFI_SUCCESS;
}
Status = CheckValueUpdateList ();
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
} else {
//
// Evaluate the default value according to the defaultId and platformId
//
if (mUqiList == NULL) {
Status = EvaluateTheValueInFormset (FALSE);
} else {
Status = EvaluateTheValueInFormset (TRUE);
}
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// print error information in UQI list
//
if (PrintErrorInfo (mUqiList)) {
return EFI_ABORTED;
}
//
// Output the variable information to BFV in multi-platform mode
// Or write it to the Nvstrage in general mode
//
if (mMultiPlatformParam.MultiPlatformOrNot) {
if (ExistEfiVarOrNot (&mAllVarListEntry) && Operations == UPDATE) {
printf ("Error. Please use --remove or --ignore to update the variable storage for an FD with variables in its NvStorage.\n");
return EFI_ABORTED;
}
} else {
//
// Sync the data from List data to efi variable.
//
Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
if (Status == EFI_OUT_OF_RESOURCES) {
printf ("Error. There is no available space in efi variable. \n");
return EFI_ABORTED;
}
if (Status == EFI_INVALID_PARAMETER) {
return EFI_ABORTED;
}
}
PrintUpdateListInfo (mUqiList);
return Status;
}
/**
Quick Update the HII setup value.
Read the Config information from command line directly, and then compare it with the current FFS.
Record the different value to EFI variable.
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
EFI_STATUS
QuickUpdateCongFile (
VOID
)
{
EFI_STATUS Status;
UINT32 Index;
Status = EFI_SUCCESS;
Index = 0;
if (mMultiPlatformParam.MultiPlatformOrNot) {
printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
return EFI_ABORTED;
}
//
// Check whether the FD has included the storage FFS
//
if (mMultiPlatformParam.ExistStorageFfsInBfv) {
printf ("Error. Variable storage exists in BFV of Fd. This is generated in multi-platform mode.\n");
printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
return EFI_ABORTED;
}
//
// Read all Ifr information to Formset list
//
for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
Status = ReadAllIfrToFromset (
gEfiFdInfo.FfsArray[Index],
gEfiFdInfo.Length[Index]
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// Evaluate the default value according to the defaultId and platformId
//
Status = EvaluateTheValueInFormset (TRUE);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// print error information in UQI list
//
if (PrintErrorInfo (mUqiList)) {
return EFI_ABORTED;
}
//
// Sync the data from mAllVarListEntry data to efi variable.
//
Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
if (Status == EFI_OUT_OF_RESOURCES) {
printf ("Error. There is no available space in Nvstorage. \n");
return EFI_ABORTED;
}
if (Status == EFI_INVALID_PARAMETER) {
return EFI_ABORTED;
}
PrintUpdateListInfo (mUqiList);
return Status;
}
/**
Check the HII setup value.
Read the Config information from config file, and then compare it with the current FFS.
Print the different values on screen.
@retval EFI_SUCCESS It was complete successfully
@return EFI_ABORTED An error occurred
**/
static
EFI_STATUS
CheckCongFile (
VOID
)
{
EFI_STATUS Status;
UINT32 Index;
UINT16 DefaultIndex;
UINT16 PlatformIndex;
UINT16 DefaultId;
UINT64 PlatformId;
Status = EFI_SUCCESS;
Index = 0;
DefaultIndex = 0;
PlatformIndex = 0;
DefaultId = 0;
PlatformId = 0;
//
// Read all Ifr information to Formset list
//
for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
Status = ReadAllIfrToFromset (
gEfiFdInfo.FfsArray[Index],
gEfiFdInfo.Length[Index]
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
//
// Read defaultId and platformId
//
Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// Read the config data from BFV in multi-platform mode
//
if (mMultiPlatformParam.MultiPlatformOrNot) {
Status = ReadStorageFromBfv (&mAllVarListEntry);
if (EFI_ERROR (Status)) {
printf ("Error. No storage variable data exists in BFV.\n");
return EFI_ABORTED;
}
}
if (mMultiPlatformParam.MultiPlatformOrNot) {
ScanUqiFullList (mUqiList);
//
// Multi-platform mode support
//
for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
//
//Only parse one time, if a group of defaultId and platformId which have the same variable
// Take the first one as a key Id of a group
//
if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
continue;
}
InitializeListHead(&mVarListEntry);
Status = BuildVariableList(
&mVarListEntry,
&mAllVarListEntry,
DefaultId,
PlatformId,
FALSE,
VERIFY
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
if (IsListEmpty (&mVarListEntry)) {
continue;
}
SetUqiParametersMultiMode (mUqiList, DefaultId, PlatformId);
DestroyAllStorage (&mVarListEntry);
}
}
} else {
//
// General mode
//
Status = ExtractDefault (
NULL,
NULL,
0,
0,
SystemLevel
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// If existed the variable in NvStorage, copy them to mVarListEntry.
// Synchronize the default value from the EFI variable zone to variable list
//
Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
if (Status == EFI_INVALID_PARAMETER) {
Status = EFI_ABORTED;
return Status;
}
//
// Update the value from script file
//
Status = SetUqiParameters (mUqiList,0, 0);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// Copy Stroage from mVarListEntry to mAllVarListEntry
//
Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, VERIFY);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
PrintVerifiedListInfo (mUqiList);
return Status;
}
/**
Search the config file from the path list.
Split the path from env PATH, and then search the cofig
file from these paths. The priority is from left to
right of PATH string. When met the first Config file, it
will break and return the pointer to the full file name.
@param PathList the pointer to the path list.
@param FileName the pointer to the file name.
@retval The pointer to the file name.
@return NULL An error occurred.
**/
CHAR8 *
SearchConfigFromPathList (
IN CHAR8 *PathList,
IN CHAR8 *FileName
)
{
CHAR8 *CurDir;
CHAR8 *FileNamePath;
CurDir = NULL;
FileNamePath = NULL;
#ifndef __GNUC__
CurDir = strtok (PathList,";");
#else
CurDir = strtok (PathList,":");
#endif
while (CurDir != NULL) {
FileNamePath = (char *)calloc(
strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
sizeof(char)
);
if (FileNamePath == NULL) {
return NULL;
}
sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
if (access (FileNamePath, 0) != -1) {
return FileNamePath;
}
#ifndef __GNUC__
CurDir = strtok(NULL, ";");
#else
CurDir = strtok(NULL, ":");
#endif
free (FileNamePath);
FileNamePath = NULL;
}
return NULL;
}
/**
FCE application entry point
@param argc The number of input parameters.
@param *argv[] The array pointer to the parameters.
@retval 0 The application exited normally.
@retval 1 An error occurred.
@retval 2 An error about check occurred.
**/
int
main (
int argc,
char *argv[]
)
{
EFI_STATUS Status;
FILE *OutputFd;
FILE *ScriptFile;
UINTN BytesWrite;
UINTN Index;
CHAR8 *TemDir;
BOOLEAN IsFileExist;
CHAR8 FullGuidToolDefinition[_MAX_PATH];
CHAR8 *PathList;
UINTN EnvLen;
CHAR8 *NewPathList;
UINTN FileNameIndex;
CHAR8 *InFilePath;
BOOLEAN UqiIsSet;
Status = EFI_SUCCESS;
OutputFd = NULL;
ScriptFile = NULL;
Operations = NONE;
BytesWrite = 0;
Index = 0;
TemDir = NULL;
mFormSetOrderRead = 0;
mFormSetOrderParse = 0;
IsFileExist = TRUE;
PathList = NULL;
NewPathList = NULL;
EnvLen = 0;
UqiIsSet = FALSE;
TemDir = getcwd (NULL, _MAX_PATH);
if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
printf ("The directory is too long \n");
return FAIL;
}
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
memset (&mMultiPlatformParam, 0, sizeof (MULTI_PLATFORM_PARAMETERS));
SetUtilityName (UTILITY_NAME);
//
// Workaroud: the first call to this function
// returns a file name ends with dot
//
#ifndef __GNUC__
tmpnam (NULL);
#else
CHAR8 tmp[] = "/tmp/fileXXXXXX";
UINTN Fdtmp;
Fdtmp = mkstemp(tmp);
close(Fdtmp);
#endif
//
// Save, and then skip filename arg
//
mUtilityFilename = argv[0];
argc--;
argv++;
//
// Get the same path with the application itself
//
if (strlen (mUtilityFilename) > _MAX_PATH - 1) {
Error (NULL, 0, 2000, "Parameter: The input file name is too long", NULL);
return FAIL;
}
strncpy (FullGuidToolDefinition, mUtilityFilename, _MAX_PATH - 1);
FullGuidToolDefinition[_MAX_PATH - 1] = 0;
FileNameIndex = strlen (FullGuidToolDefinition);
while (FileNameIndex != 0) {
FileNameIndex --;
if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
FullGuidToolDefinition[FileNameIndex] = 0;
strcpy (mFullGuidToolDefinitionDir, FullGuidToolDefinition);
break;
}
}
//
// Build the path list for Config file scan. The priority is below.
// 1. Scan the current path
// 2. Scan the same path with the application itself
// 3. Scan the current %PATH% of OS environment
// 4. Use the build-in default configuration
//
PathList = getenv("PATH");
if (PathList == NULL) {
Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
return FAIL;
}
EnvLen = strlen(PathList);
NewPathList = (char *)calloc(
strlen (".")
+ strlen (";")
+ strlen (mFullGuidToolDefinitionDir)
+ strlen (";")
+ EnvLen
+ 1,
sizeof(char)
);
if (NewPathList == NULL) {
Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
PathList = NULL;
free (PathList);
return -1;
}
#ifndef __GNUC__
sprintf (NewPathList, "%s;%s;%s", ".", mFullGuidToolDefinitionDir, PathList);
#else
sprintf (NewPathList, "%s:%s:%s", ".", mFullGuidToolDefinitionDir, PathList);
#endif
PathList = NULL;
free (PathList);
//
// Load Guid Tools definition
//
InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
free (NewPathList);
if (InFilePath != NULL) {
printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
free (InFilePath);
} else {
//
// Use the pre-defined standard guided tools.
//
printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
mParsedGuidedSectionTools = PreDefinedGuidedTools ();
}
//
// Parse the command line
//
strcpy (mSetupTxtName, "NoSetupFile");
Status = ParseCommmadLine (argc,argv);
if (EFI_ERROR (Status)) {
return FAIL;
}
//
// Print utility header
//
printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
UTILITY_NAME,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION,
__BUILD_VERSION
);
//
// Check the revision of BfmLib
//
Status = CheckBfmLibRevision ();
if (EFI_ERROR (Status)) {
printf ("Please use the correct revision of BfmLib %s. \n", __BUILD_VERSION);
return FAIL;
}
if (strcmp (mSetupTxtName, "NoSetupFile")) {
ScriptFile = fopen (mSetupTxtName, "r");
if (ScriptFile == NULL) {
printf ("Error. Cannot open the script file.\n");
return FAIL;
}
Status = PickUpUqiFromScript (ScriptFile);
if (EFI_ERROR (Status)) {
fclose (ScriptFile);
IsFileExist = FALSE;
goto Done;
}
fclose (ScriptFile);
}
if (!mMultiPlatformParam.MultiPlatformOrNot
&& (Operations == UPDATE_REMOVE || Operations == UPDATE_IGNORE)
) {
printf ("Error. --remove and --ignore cannot be used in normal mode.\n");
Status = FAIL;
goto Done;
}
if (access (TemDir, 0) != -1) {
LibRmDir (TemDir);
}
//
// Initialize the variables
//
Status = PickUpFfsFromFd ();
if (EFI_ERROR (Status)) {
printf ("Error. Invalid FD file.\n");
IsFileExist = FALSE;
Status = FAIL;
goto Done;
}
if (gEfiFdInfo.FfsArray[0] == NULL) {
printf ("Error. Cannot find any HII offset in current FD files, please check the BaseTools.\n");
Status = FAIL;
goto Done;
}
//
//Config the global variables
//
if (mMultiPlatformParam.Uqi.Data != NULL) {
UqiIsSet = TRUE;
}
Status = GetEfiVariablesAddr (UqiIsSet);
if (EFI_ERROR (Status)) {
printf ("Error. Cannot locate the EFI variable zone in FD.\n");
Status = FAIL;
goto Done;
}
if (gEfiFdInfo.ExistNvStoreDatabase && !mMultiPlatformParam.MultiPlatformOrNot) {
mMultiPlatformParam.MultiPlatformOrNot = TRUE;
}
//
// Initialize the FormSet and VarList List
//
InitializeListHead (&mFormSetListEntry);
InitializeListHead (&mVarListEntry);
InitializeListHead (&mBfvVarListEntry);
InitializeListHead (&mAllVarListEntry);
mStringBuffer = malloc (mMaxCount);
if (mStringBuffer == NULL) {
printf ("Fali to allocate memory!\n");
Status = FAIL;
goto Done;
}
//
// Decide how to deal with the Fd
//
switch (Operations) {
case READ:
printf ("\nStart the Read Mode:\n");
Status = ReadCongFile ();
if (EFI_ERROR (Status)) {
Status = FAIL;
}
break;
case UPDATE:
case UPDATE_REMOVE:
case UPDATE_IGNORE:
printf ("\nStart the Update Mode:\n");
Status = UpdateCongFile ();
if (EFI_ERROR (Status)) {
Status = FAIL;
}
break;
case VERIFY:
printf ("\nStart the Verify Mode:\n");
Status = CheckCongFile ();
if (EFI_ERROR (Status)) {
Status = VR_FAIL;
}
break;
case UPDATEQ:
printf ("\nStart the Update Quick Mode:\n");
Status = QuickUpdateCongFile ();
if (EFI_ERROR (Status)) {
Status = FAIL;
}
break;
default:
break;
}
if (mCount > 0) {
mStringBuffer[mCount] = '\0';
fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
}
free (mStringBuffer);
if (Status != SUCCESS) {
goto Done;
}
//
// If multi-platform mode, insert the variables to BFV
//
if (mMultiPlatformParam.MultiPlatformOrNot
&& (IsListEmpty (&mAllVarListEntry) == FALSE)
&&((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ))
) {
IsFileExist = FALSE;
if (gEfiFdInfo.ExistNvStoreDatabase) {
Status = InsertBinaryToNvStoreDatabase (mInputFdName, mOutputFdName, &mAllVarListEntry);
} else {
Status = InsertBinaryToBfv (mInputFdName, mOutputFdName, &mAllVarListEntry);
}
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Remove the variables in NvStorage in multi-platform mode by user specified requirement
//
if (Operations == UPDATE_REMOVE) {
if (gEfiFdInfo.Fd != NULL) {
free (gEfiFdInfo.Fd);
}
gEfiFdInfo.Fd = ReadFileToMemory (mOutputFdName, &gEfiFdInfo.FdSize);
if (gEfiFdInfo.Fd == NULL) {
Status = EFI_ABORTED;
} else {
Status = RemoveEfiVar (&mAllVarListEntry);
}
if (EFI_ERROR (Status)) {
printf ("Error. Failed to remove the variable from NVRAM.\n");
Status = FAIL;
goto Done;
}
}
}
if (
(!mMultiPlatformParam.MultiPlatformOrNot &&((Operations == UPDATE) || (Operations == UPDATEQ)))
|| (mMultiPlatformParam.MultiPlatformOrNot && (Operations == UPDATE_REMOVE || ((Operations == UPDATE) && IsListEmpty (&mAllVarListEntry))))
) {
OutputFd = fopen (mOutputFdName, "wb+");
if (OutputFd == NULL) {
printf ("Error. Failed to create the output FD file.\n");
Status = FAIL;
goto Done;
}
fseek (OutputFd, 0, SEEK_SET);
BytesWrite = fwrite (gEfiFdInfo.Fd, sizeof (CHAR8), gEfiFdInfo.FdSize, OutputFd);
fclose (OutputFd);
if (BytesWrite != gEfiFdInfo.FdSize) {
printf ("Error. Failed to create the FD image. \n");
Status = FAIL;
goto Done;
}
}
if ((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ)) {
printf ("\nCongratulations. The output Fd file '%s' has been completed successfully.\n", mOutputFdName);
}
Done:
//
// Delete the temporary directory and files
//
if (IsFileExist) {
LibRmDir (TemDir);
}
//
// Clean up
//
if (gEfiFdInfo.Fd != NULL) {
free (gEfiFdInfo.Fd);
}
if (mMultiPlatformParam.Uqi.Value != NULL) {
free (mMultiPlatformParam.Uqi.Value);
}
if (mMultiPlatformParam.Uqi.Data != NULL) {
free (mMultiPlatformParam.Uqi.Data);
}
while (gEfiFdInfo.FfsArray[Index] != NULL) {
free (gEfiFdInfo.FfsArray[Index++]);
}
DestroyAllFormSet (&mFormSetListEntry);
DestroyAllStorage (&mVarListEntry);
DestroyAllStorage (&mBfvVarListEntry);
DestroyAllStorage (&mAllVarListEntry);
FreeUnidirectionList (mUqiList);
return Status;
}