/** @file Parser for IFR binary encoding. ;****************************************************************************** ;* Copyright (c) 2013 - 2021, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "InternalH2OFormBrowser.h" #include "FBTargetInfo.h" UINT32 mStatementIndex; UINT32 mExpressionOpCodeIndex; EFI_QUESTION_ID mUsedQuestionId; extern LIST_ENTRY gBrowserStorageList; EFI_GUID mH2OIfrExtGuid = H2O_IFR_EXT_GUID; /** Initialize Statement header members. @param [in] OpCodeData Pointer of the raw OpCode data. @param [in,out] FormSet Pointer of the current FormSet. @param [in,out] 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); if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP) { return NULL; } } Statement = &FormSet->StatementBuffer[mStatementIndex]; Statement->StatementId = mStatementIndex; mStatementIndex++; InitializeListHead (&Statement->DefaultListHead); InitializeListHead (&Statement->OptionListHead); InitializeListHead (&Statement->InconsistentListHead); InitializeListHead (&Statement->NoSubmitListHead); InitializeListHead (&Statement->WarningListHead); InitializeListHead (&Statement->PropertyListHead); Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE; Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; Statement->OpCode = (EFI_IFR_OP_HEADER *) OpCodeData; 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); if (Statement->Expression == NULL) { return 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 // ASSERT (Form != NULL); if (Form == NULL) { InsertTailList (&FormSet->StatementListOSF, &Statement->Link); } else { InsertTailList (&Form->StatementListHead, &Statement->Link); Form->NumberOfStatement++; } return Statement; } /** Initialize Question's members. @param [in] OpCodeData Pointer of the raw OpCode data. @param [in,out] FormSet Pointer of the current FormSet. @param [in,out] 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); if (Statement->Storage == NULL) { DEBUG ((EFI_D_ERROR, "CreateQuestion() Storage is NULL")); return 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 = GetString (Statement->VarStoreInfo.VarName, FormSet->HiiHandle); ASSERT (Statement->VariableName != NULL); if (Statement->VariableName == NULL) { return 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); if (NameValueNode == NULL) { return 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); if (Expression == NULL) { DEBUG ((EFI_D_INFO, "CreateExpression() Expression is NULL")); return 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 [in] FormSet Pointer of the current FormSet @param [in,out] Storage Pointer of the storage @retval EFI_SUCCESS Initialize ConfigHdr success **/ STATIC EFI_STATUS InitializeConfigHdr ( IN FORM_BROWSER_FORMSET *FormSet, IN OUT BROWSER_STORAGE *Storage ) { CHAR16 *Name; if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { Name = Storage->Name; } else { Name = NULL; } Storage->ConfigHdr = HiiConstructConfigHdr ( &Storage->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; } /** Delete invalid browser storage by checking HII handle. **/ VOID DeleteInvalidBrowserStorage ( VOID ) { LIST_ENTRY *Link; LIST_ENTRY *NameValueLink; NAME_VALUE_NODE *NameValueNode; BROWSER_STORAGE *BrowserStorage; EFI_HII_HANDLE *HiiHandles; UINTN Index; BOOLEAN Found; HiiHandles = HiiGetHiiHandles (NULL); if (HiiHandles == NULL) { return; } Link = GetFirstNode (&gBrowserStorageList); while (!IsNull (&gBrowserStorageList, Link)) { BrowserStorage = BROWSER_STORAGE_FROM_LINK (Link); Link = GetNextNode (&gBrowserStorageList, Link); if (BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE || BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER) { for (Index = 0, Found = FALSE; HiiHandles[Index] != NULL; Index++) { if (HiiHandles[Index] == BrowserStorage->HiiHandle) { Found = TRUE; break; } } if (!Found) { RemoveEntryList (&BrowserStorage->Link); FBFreePool ((VOID **) &BrowserStorage->EditBuffer); FBFreePool ((VOID **) &BrowserStorage->Buffer); FBFreePool ((VOID **) &BrowserStorage->Name); FBFreePool ((VOID **) &BrowserStorage->ConfigHdr); if (BrowserStorage->NameValueListHead.ForwardLink != NULL && BrowserStorage->NameValueListHead.BackLink != NULL && !IsListEmpty(&BrowserStorage->NameValueListHead)) { NameValueLink = GetFirstNode (&BrowserStorage->NameValueListHead); while (!IsNull (&BrowserStorage->NameValueListHead, NameValueLink)) { NameValueNode = NAME_VALUE_NODE_FROM_LINK (NameValueLink); NameValueLink = GetNextNode (&BrowserStorage->NameValueListHead, NameValueLink); RemoveEntryList (&NameValueNode->Link); FBFreePool ((VOID **) &NameValueNode->Name); FBFreePool ((VOID **) &NameValueNode->Value); FBFreePool ((VOID **) &NameValueNode->EditValue); FreePool (NameValueNode); } } FreePool (BrowserStorage); } } } FreePool (HiiHandles); } /** 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); if (StorageName == NULL) { return NULL; } UnicodeString = AllocateZeroPool (AsciiStrSize (StorageName) * 2); ASSERT (UnicodeString != NULL); if (UnicodeString == NULL) { return NULL; } for (Index = 0; StorageName[Index] != 0; Index++) { UnicodeString[Index] = (CHAR16) StorageName[Index]; } } Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE)); ASSERT (Storage != NULL); if (Storage == NULL) { return 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); if (BrowserStorage == NULL) { return 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; UnicodeString = NULL; } BrowserStorage->HiiHandle = FormSet->HiiHandle; InitializeConfigHdr (FormSet, BrowserStorage); BrowserStorage->Initialized = FALSE; } else { // // Always update ConfigHdr string in case device path is changed. // FBFreePool ((VOID **) &BrowserStorage->ConfigHdr); InitializeConfigHdr (FormSet, BrowserStorage); } Storage->BrowserStorage = BrowserStorage; Storage->ConfigRequest = AllocateCopyPool (StrSize (BrowserStorage->ConfigHdr), BrowserStorage->ConfigHdr); Storage->SpareStrLen = 0; FBFreePool ((VOID **) &UnicodeString); return Storage; } /** Initialize Request Element of a Question. ::= '&' | '&'