/** @file Parser for IFR binary encoding. Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Setup.h" UINTN mStatementIndex; UINTN mExpressionOpCodeIndex; EFI_QUESTION_ID mUsedQuestionId; extern LIST_ENTRY gBrowserStorageList; /** Initialize Statement header members. @param OpCodeData Pointer of the raw OpCode data. @param FormSet Pointer of the current FormSet. @param Form Pointer of the current Form. @return The Statement. **/ FORM_BROWSER_STATEMENT * CreateStatement ( IN UINT8 *OpCodeData, IN OUT FORM_BROWSER_FORMSET *FormSet, IN OUT FORM_BROWSER_FORM *Form ) { FORM_BROWSER_STATEMENT *Statement; EFI_IFR_STATEMENT_HEADER *StatementHdr; INTN ConditionalExprCount; if (Form == NULL) { // // Only guid op may out side the form level. // ASSERT (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP); } Statement = &FormSet->StatementBuffer[mStatementIndex]; mStatementIndex++; InitializeListHead (&Statement->DefaultListHead); InitializeListHead (&Statement->OptionListHead); InitializeListHead (&Statement->InconsistentListHead); InitializeListHead (&Statement->NoSubmitListHead); InitializeListHead (&Statement->WarningListHead); Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE; Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; Statement->OpCode = (EFI_IFR_OP_HEADER *) OpCodeData; Statement->QuestionReferToBitField = FALSE; StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID)); CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID)); ConditionalExprCount = GetConditionalExpressionCount(ExpressStatement); if (ConditionalExprCount > 0) { // // Form is inside of suppressif // Statement->Expression = (FORM_EXPRESSION_LIST *) AllocatePool( (UINTN) (sizeof(FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof(FORM_EXPRESSION *)))); ASSERT (Statement->Expression != NULL); Statement->Expression->Count = (UINTN) ConditionalExprCount; Statement->Expression->Signature = FORM_EXPRESSION_LIST_SIGNATURE; CopyMem (Statement->Expression->Expression, GetConditionalExpressionList(ExpressStatement), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount)); } // // Insert this Statement into current Form // if (Form == NULL) { InsertTailList (&FormSet->StatementListOSF, &Statement->Link); } else { InsertTailList (&Form->StatementListHead, &Statement->Link); } return Statement; } /** Initialize Question's members. @param OpCodeData Pointer of the raw OpCode data. @param FormSet Pointer of the current FormSet. @param Form Pointer of the current Form. @return The Question. **/ FORM_BROWSER_STATEMENT * CreateQuestion ( IN UINT8 *OpCodeData, IN OUT FORM_BROWSER_FORMSET *FormSet, IN OUT FORM_BROWSER_FORM *Form ) { FORM_BROWSER_STATEMENT *Statement; EFI_IFR_QUESTION_HEADER *QuestionHdr; LIST_ENTRY *Link; FORMSET_STORAGE *Storage; NAME_VALUE_NODE *NameValueNode; BOOLEAN Find; Statement = CreateStatement (OpCodeData, FormSet, Form); if (Statement == NULL) { return NULL; } QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID)); CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID)); CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16)); Statement->QuestionFlags = QuestionHdr->Flags; if (Statement->VarStoreId == 0) { // // VarStoreId of zero indicates no variable storage // return Statement; } // // Find Storage for this Question // Link = GetFirstNode (&FormSet->StorageListHead); while (!IsNull (&FormSet->StorageListHead, Link)) { Storage = FORMSET_STORAGE_FROM_LINK (Link); if (Storage->VarStoreId == Statement->VarStoreId) { Statement->Storage = Storage->BrowserStorage; break; } Link = GetNextNode (&FormSet->StorageListHead, Link); } ASSERT (Statement->Storage != NULL); // // Initialilze varname for Name/Value or EFI Variable // if ((Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) || (Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->HiiHandle); ASSERT (Statement->VariableName != NULL); if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { // // Check whether old string node already exist. // Find = FALSE; if (!IsListEmpty(&Statement->Storage->NameValueListHead)) { Link = GetFirstNode (&Statement->Storage->NameValueListHead); while (!IsNull (&Statement->Storage->NameValueListHead, Link)) { NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link); if (StrCmp (Statement->VariableName, NameValueNode->Name) == 0) { Find = TRUE; break; } Link = GetNextNode (&Statement->Storage->NameValueListHead, Link); } } if (!Find) { // // Insert to Name/Value varstore list // NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE)); ASSERT (NameValueNode != NULL); NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE; NameValueNode->Name = AllocateCopyPool (StrSize (Statement->VariableName), Statement->VariableName); ASSERT (NameValueNode->Name != NULL); NameValueNode->Value = AllocateZeroPool (0x10); ASSERT (NameValueNode->Value != NULL); NameValueNode->EditValue = AllocateZeroPool (0x10); ASSERT (NameValueNode->EditValue != NULL); InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link); } } } return Statement; } /** Allocate a FORM_EXPRESSION node. @param Form The Form associated with this Expression @param OpCode The binary opcode data. @return Pointer to a FORM_EXPRESSION data structure. **/ FORM_EXPRESSION * CreateExpression ( IN OUT FORM_BROWSER_FORM *Form, IN UINT8 *OpCode ) { FORM_EXPRESSION *Expression; Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION)); ASSERT (Expression != NULL); Expression->Signature = FORM_EXPRESSION_SIGNATURE; InitializeListHead (&Expression->OpCodeListHead); Expression->OpCode = (EFI_IFR_OP_HEADER *) OpCode; return Expression; } /** Create ConfigHdr string for a storage. @param FormSet Pointer of the current FormSet @param Storage Pointer of the storage @retval EFI_SUCCESS Initialize ConfigHdr success **/ EFI_STATUS InitializeConfigHdr ( IN FORM_BROWSER_FORMSET *FormSet, IN OUT FORMSET_STORAGE *Storage ) { CHAR16 *Name; if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER || Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { Name = Storage->BrowserStorage->Name; } else { Name = NULL; } Storage->ConfigHdr = HiiConstructConfigHdr ( &Storage->BrowserStorage->Guid, Name, FormSet->DriverHandle ); if (Storage->ConfigHdr == NULL) { return EFI_NOT_FOUND; } return EFI_SUCCESS; } /** Find the global storage link base on the input storate type, name and guid. For EFI_HII_VARSTORE_EFI_VARIABLE and EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER, same guid + name = same storage For EFI_HII_VARSTORE_NAME_VALUE: same guid + HiiHandle = same storage For EFI_HII_VARSTORE_BUFFER: same guid + name + HiiHandle = same storage @param StorageType Storage type. @param StorageGuid Storage guid. @param StorageName Storage Name. @param HiiHandle HiiHandle for this varstore. @return Pointer to a GLOBAL_STORAGE data structure. **/ BROWSER_STORAGE * FindStorageInList ( IN UINT8 StorageType, IN EFI_GUID *StorageGuid, IN CHAR16 *StorageName, IN EFI_HII_HANDLE HiiHandle ) { LIST_ENTRY *Link; BROWSER_STORAGE *BrowserStorage; Link = GetFirstNode (&gBrowserStorageList); while (!IsNull (&gBrowserStorageList, Link)) { BrowserStorage = BROWSER_STORAGE_FROM_LINK (Link); Link = GetNextNode (&gBrowserStorageList, Link); if ((BrowserStorage->Type == StorageType) && CompareGuid (&BrowserStorage->Guid, StorageGuid)) { if (StorageType == EFI_HII_VARSTORE_NAME_VALUE) { if (BrowserStorage->HiiHandle == HiiHandle) { return BrowserStorage; } continue; } ASSERT (StorageName != NULL); if (StrCmp (BrowserStorage->Name, StorageName) == 0) { if (StorageType == EFI_HII_VARSTORE_EFI_VARIABLE || StorageType == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { return BrowserStorage; } else if (StorageType == EFI_HII_VARSTORE_BUFFER && BrowserStorage->HiiHandle == HiiHandle) { return BrowserStorage; } } } } return NULL; } /** Intialize the Global Storage. @param BrowserStorage Pointer to the global storage. @param StorageType Storage type. @param OpCodeData Binary data for this opcode. **/ VOID IntializeBrowserStorage ( IN BROWSER_STORAGE *BrowserStorage, IN UINT8 StorageType, IN UINT8 *OpCodeData ) { switch (StorageType) { case EFI_HII_VARSTORE_BUFFER: CopyMem (&BrowserStorage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID)); CopyMem (&BrowserStorage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16)); BrowserStorage->Buffer = AllocateZeroPool (BrowserStorage->Size); BrowserStorage->EditBuffer = AllocateZeroPool (BrowserStorage->Size); break; case EFI_HII_VARSTORE_EFI_VARIABLE: case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: CopyMem (&BrowserStorage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID)); CopyMem (&BrowserStorage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32)); CopyMem (&BrowserStorage->Size, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Size, sizeof (UINT16)); if (StorageType == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { BrowserStorage->Buffer = AllocateZeroPool (BrowserStorage->Size); BrowserStorage->EditBuffer = AllocateZeroPool (BrowserStorage->Size); } break; case EFI_HII_VARSTORE_NAME_VALUE: CopyMem (&BrowserStorage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID)); InitializeListHead (&BrowserStorage->NameValueListHead); break; default: break; } } /** Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List. @param FormSet Pointer of the current FormSet @param StorageType Storage type. @param OpCodeData Binary data for this opcode. @return Pointer to a FORMSET_STORAGE data structure. **/ FORMSET_STORAGE * CreateStorage ( IN FORM_BROWSER_FORMSET *FormSet, IN UINT8 StorageType, IN UINT8 *OpCodeData ) { FORMSET_STORAGE *Storage; CHAR16 *UnicodeString; UINT16 Index; BROWSER_STORAGE *BrowserStorage; EFI_GUID *StorageGuid; CHAR8 *StorageName; UnicodeString = NULL; StorageName = NULL; switch (StorageType) { case EFI_HII_VARSTORE_BUFFER: StorageGuid = (EFI_GUID *) (CHAR8*) &((EFI_IFR_VARSTORE *) OpCodeData)->Guid; StorageName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name; break; case EFI_HII_VARSTORE_EFI_VARIABLE: case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: StorageGuid = (EFI_GUID *) (CHAR8*) &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid; StorageName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name; break; default: ASSERT (StorageType == EFI_HII_VARSTORE_NAME_VALUE); StorageGuid = &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid; break; } if (StorageType != EFI_HII_VARSTORE_NAME_VALUE) { ASSERT (StorageName != NULL); UnicodeString = AllocateZeroPool (AsciiStrSize (StorageName) * 2); ASSERT (UnicodeString != NULL); for (Index = 0; StorageName[Index] != 0; Index++) { UnicodeString[Index] = (CHAR16) StorageName[Index]; } } Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE)); ASSERT (Storage != NULL); Storage->Signature = FORMSET_STORAGE_SIGNATURE; InsertTailList (&FormSet->StorageListHead, &Storage->Link); BrowserStorage = FindStorageInList(StorageType, StorageGuid, UnicodeString, FormSet->HiiHandle); if (BrowserStorage == NULL) { BrowserStorage = AllocateZeroPool (sizeof (BROWSER_STORAGE)); ASSERT (BrowserStorage != NULL); BrowserStorage->Signature = BROWSER_STORAGE_SIGNATURE; InsertTailList (&gBrowserStorageList, &BrowserStorage->Link); IntializeBrowserStorage (BrowserStorage, StorageType, OpCodeData); BrowserStorage->Type = StorageType; if (StorageType != EFI_HII_VARSTORE_NAME_VALUE) { BrowserStorage->Name = UnicodeString; } BrowserStorage->HiiHandle = FormSet->HiiHandle; BrowserStorage->Initialized = FALSE; } Storage->BrowserStorage = BrowserStorage; InitializeConfigHdr (FormSet, Storage); Storage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigHdr), Storage->ConfigHdr); Storage->SpareStrLen = 0; return Storage; } /** Get Formset_storage base on the input varstoreid info. @param FormSet Pointer of the current FormSet. @param VarStoreId Varstore ID info. @return Pointer to a FORMSET_STORAGE data structure. **/ FORMSET_STORAGE * GetFstStgFromVarId ( IN FORM_BROWSER_FORMSET *FormSet, IN EFI_VARSTORE_ID VarStoreId ) { FORMSET_STORAGE *FormsetStorage; LIST_ENTRY *Link; BOOLEAN Found; Found = FALSE; FormsetStorage = NULL; // // Find Formset Storage for this Question // Link = GetFirstNode (&FormSet->StorageListHead); while (!IsNull (&FormSet->StorageListHead, Link)) { FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link); if (FormsetStorage->VarStoreId == VarStoreId) { Found = TRUE; break; } Link = GetNextNode (&FormSet->StorageListHead, Link); } return Found ? FormsetStorage : NULL; } /** Get Formset_storage base on the input browser storage. More than one formsets may share the same browser storage, this function just get the first formset storage which share the browser storage. @param Storage browser storage info. @return Pointer to a FORMSET_STORAGE data structure. **/ FORMSET_STORAGE * GetFstStgFromBrsStg ( IN BROWSER_STORAGE *Storage ) { FORMSET_STORAGE *FormsetStorage; LIST_ENTRY *Link; LIST_ENTRY *FormsetLink; FORM_BROWSER_FORMSET *FormSet; BOOLEAN Found; Found = FALSE; FormsetStorage = NULL; FormsetLink = GetFirstNode (&gBrowserFormSetList); while (!IsNull (&gBrowserFormSetList, FormsetLink)) { FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormsetLink); FormsetLink = GetNextNode (&gBrowserFormSetList, FormsetLink); Link = GetFirstNode (&FormSet->StorageListHead); while (!IsNull (&FormSet->StorageListHead, Link)) { FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link); Link = GetNextNode (&FormSet->StorageListHead, Link); if (FormsetStorage->BrowserStorage == Storage) { Found = TRUE; break; } } if (Found) { break; } } return Found ? FormsetStorage : NULL; } /** Initialize Request Element of a Question. ::= '&' | '&'