/** @file The implementation of HII IFR parser. Copyright (c) 2019, Intel Corporation. All rights reserved.
(C) Copyright 2021 Hewlett Packard Enterprise Development LP
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "HiiInternal.h" /** 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. **/ HII_STATEMENT * CreateStatement ( IN UINT8 *OpCodeData, IN OUT HII_FORMSET *FormSet, IN OUT HII_FORM *Form ) { HII_STATEMENT *Statement; EFI_IFR_STATEMENT_HEADER *StatementHdr; INTN ConditionalExprCount; if (Form == NULL) { // // Only guid op may out side the form level. // if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode != EFI_IFR_GUID_OP) { return NULL; } } Statement = (HII_STATEMENT *)AllocateZeroPool (sizeof (HII_STATEMENT)); if (Statement == NULL) { return NULL; } InitializeListHead (&Statement->DefaultListHead); InitializeListHead (&Statement->OptionListHead); InitializeListHead (&Statement->InconsistentListHead); InitializeListHead (&Statement->NoSubmitListHead); InitializeListHead (&Statement->WarningListHead); Statement->Signature = HII_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->ExpressionList = (HII_EXPRESSION_LIST *)AllocatePool ( (UINTN)(sizeof (HII_EXPRESSION_LIST) + ((ConditionalExprCount - 1) * sizeof (HII_EXPRESSION *))) ); if (Statement->ExpressionList == NULL) { return NULL; } Statement->ExpressionList->Count = (UINTN)ConditionalExprCount; Statement->ExpressionList->Signature = HII_EXPRESSION_LIST_SIGNATURE; CopyMem ( Statement->ExpressionList->Expression, GetConditionalExpressionList (ExpressStatement), (UINTN)(sizeof (HII_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[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. **/ HII_STATEMENT * CreateQuestion ( IN UINT8 *OpCodeData, IN OUT HII_FORMSET *FormSet, IN OUT HII_FORM *Form ) { HII_STATEMENT *Statement; EFI_IFR_QUESTION_HEADER *QuestionHdr; LIST_ENTRY *Link; HII_FORMSET_STORAGE *Storage; HII_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 = HII_STORAGE_FROM_LINK (Link); if (Statement->VarStoreId == Storage->VarStoreId) { Statement->Storage = Storage; break; } Link = GetNextNode (&FormSet->StorageListHead, Link); } if (Statement->Storage == NULL) { return NULL; } // // Initialize 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 = GetTokenString (Statement->VarStoreInfo.VarName, FormSet->HiiHandle); 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->NameValueList)) { Link = GetFirstNode (&Statement->Storage->NameValueList); while (!IsNull (&Statement->Storage->NameValueList, Link)) { NameValueNode = HII_NAME_VALUE_NODE_FROM_LINK (Link); if (StrCmp (Statement->VariableName, NameValueNode->Name) == 0) { Find = TRUE; break; } Link = GetNextNode (&Statement->Storage->NameValueList, Link); } } if (!Find) { // // Insert to Name/Value varstore list // NameValueNode = AllocateZeroPool (sizeof (HII_NAME_VALUE_NODE)); if (NameValueNode == NULL) { return NULL; } NameValueNode->Signature = HII_NAME_VALUE_NODE_SIGNATURE; NameValueNode->Name = AllocateCopyPool (StrSize (Statement->VariableName), Statement->VariableName); if (NameValueNode->Name == NULL) { FreePool (NameValueNode); return NULL; } NameValueNode->Value = AllocateZeroPool (0x10); if (NameValueNode->Value == NULL) { FreePool (NameValueNode->Name); FreePool (NameValueNode); return NULL; } InsertTailList (&Statement->Storage->NameValueList, &NameValueNode->Link); } } } return Statement; } /** Allocate a HII_EXPRESSION node. @param[in,out] Form The Form associated with this Expression @param[in] OpCode The binary opcode data. @return Pointer to a HII_EXPRESSION data structure. **/ HII_EXPRESSION * CreateExpression ( IN OUT HII_FORM *Form, IN UINT8 *OpCode ) { HII_EXPRESSION *Expression; Expression = AllocateZeroPool (sizeof (HII_EXPRESSION)); if (Expression == NULL) { return NULL; } Expression->Signature = HII_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 **/ EFI_STATUS InitializeConfigHdr ( IN HII_FORMSET *FormSet, IN OUT HII_FORMSET_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; } /** Convert Ascii string to Unicode. This is an internal function. @param[in] AsciiString The Ascii string to be converted. @param[out] UnicodeString The Unicode string retrieved. **/ VOID AsciiToUnicode ( IN CHAR8 *AsciiString, OUT CHAR16 *UnicodeString ) { UINT8 Index; Index = 0; while (AsciiString[Index] != 0) { UnicodeString[Index] = (CHAR16)AsciiString[Index]; Index++; } UnicodeString[Index] = L'\0'; } /** Allocate a HII_FORMSET_STORAGE data structure and insert to FormSet Storage List. @param[in] FormSet Pointer of the current FormSet @param[in] StorageType Storage type. @param[in] OpCodeData Binary data for this opcode. @return Pointer to a HII_FORMSET_STORAGE data structure. **/ HII_FORMSET_STORAGE * CreateStorage ( IN HII_FORMSET *FormSet, IN UINT8 StorageType, IN UINT8 *OpCodeData ) { HII_FORMSET_STORAGE *Storage; CHAR8 *AsciiStorageName; AsciiStorageName = NULL; Storage = AllocateZeroPool (sizeof (HII_FORMSET_STORAGE)); if (Storage == NULL) { return NULL; } Storage->Signature = HII_STORAGE_SIGNATURE; Storage->Type = StorageType; switch (StorageType) { case EFI_HII_VARSTORE_BUFFER: CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *)OpCodeData)->Guid, sizeof (EFI_GUID)); CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *)OpCodeData)->Size, sizeof (UINT16)); Storage->Buffer = AllocateZeroPool (Storage->Size); if (Storage->Buffer == NULL) { FreePool (Storage); return NULL; } AsciiStorageName = (CHAR8 *)((EFI_IFR_VARSTORE *)OpCodeData)->Name; Storage->Name = AllocatePool (sizeof (CHAR16) * (AsciiStrLen (AsciiStorageName) + 1)); if (Storage->Name == NULL) { FreePool (Storage); return NULL; } AsciiToUnicode (AsciiStorageName, Storage->Name); break; case EFI_HII_VARSTORE_EFI_VARIABLE: case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *)OpCodeData)->Guid, sizeof (EFI_GUID)); CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *)OpCodeData)->Attributes, sizeof (UINT32)); CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE_EFI *)OpCodeData)->Size, sizeof (UINT16)); if (StorageType == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { Storage->Buffer = AllocateZeroPool (Storage->Size); if (Storage->Buffer == NULL) { FreePool (Storage); return NULL; } } AsciiStorageName = (CHAR8 *)((EFI_IFR_VARSTORE_EFI *)OpCodeData)->Name; Storage->Name = AllocatePool (sizeof (CHAR16) * (AsciiStrLen (AsciiStorageName) + 1)); if (Storage->Name == NULL) { FreePool (Storage); return NULL; } AsciiToUnicode (AsciiStorageName, Storage->Name); break; case EFI_HII_VARSTORE_NAME_VALUE: CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *)OpCodeData)->Guid, sizeof (EFI_GUID)); InitializeListHead (&Storage->NameValueList); break; default: break; } InitializeConfigHdr (FormSet, Storage); InsertTailList (&FormSet->StorageListHead, &Storage->Link); return Storage; } /** Get formset storage based on the input varstoreid info. @param[in] FormSet Pointer of the current FormSet. @param[in] VarStoreId Varstore ID info. @return Pointer to a HII_FORMSET_STORAGE data structure. **/ HII_FORMSET_STORAGE * GetFstStgFromVarId ( IN HII_FORMSET *FormSet, IN EFI_VARSTORE_ID VarStoreId ) { HII_FORMSET_STORAGE *Storage; LIST_ENTRY *Link; BOOLEAN Found; Found = FALSE; Storage = NULL; // // Find Formset Storage for this Question // Link = GetFirstNode (&FormSet->StorageListHead); while (!IsNull (&FormSet->StorageListHead, Link)) { Storage = HII_STORAGE_FROM_LINK (Link); if (Storage->VarStoreId == VarStoreId) { Found = TRUE; break; } Link = GetNextNode (&FormSet->StorageListHead, Link); } return Found ? Storage : NULL; } /** Initialize Request Element of a Question. ::= '&' | '&'