/** @file The implementation of HII expression. Copyright (c) 2019, Intel Corporation. All rights reserved.
(C) Copyright 2021 Hewlett Packard Enterprise Development LP
Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "HiiInternal.h" // // Global stack used to evaluate boolean expressions // EFI_HII_VALUE *mOpCodeScopeStack = NULL; EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL; EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL; // // Stack used for Suppressif/grayoutif/disableif expression list. // HII_EXPRESSION **mFormExpressionStack = NULL; HII_EXPRESSION **mFormExpressionEnd = NULL; HII_EXPRESSION **mFormExpressionPointer = NULL; HII_EXPRESSION **mStatementExpressionStack = NULL; HII_EXPRESSION **mStatementExpressionEnd = NULL; HII_EXPRESSION **mStatementExpressionPointer = NULL; HII_EXPRESSION **mOptionExpressionStack = NULL; HII_EXPRESSION **mOptionExpressionEnd = NULL; HII_EXPRESSION **mOptionExpressionPointer = NULL; // // Stack used for the sub expresion in map expression. // EFI_HII_VALUE *mCurrentExpressionStack = NULL; EFI_HII_VALUE *mCurrentExpressionEnd = NULL; EFI_HII_VALUE *mCurrentExpressionPointer = NULL; // // Stack used for the map expression list. // EFI_HII_VALUE *mMapExpressionListStack = NULL; EFI_HII_VALUE *mMapExpressionListEnd = NULL; EFI_HII_VALUE *mMapExpressionListPointer = NULL; // // Stack used for dependency expression. // HII_DEPENDENCY_EXPRESSION **mExpressionDependencyStack = NULL; HII_DEPENDENCY_EXPRESSION **mExpressionDependencyEnd = NULL; HII_DEPENDENCY_EXPRESSION **mExpressionDependencyPointer = NULL; /** Grow size of the stack. This is an internal function. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd On input: old stack end; On output: new stack end @retval EFI_SUCCESS Grow stack success. @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. **/ EFI_STATUS GrowStack ( IN OUT EFI_HII_VALUE **Stack, IN OUT EFI_HII_VALUE **StackPtr, IN OUT EFI_HII_VALUE **StackEnd ) { UINTN Size; EFI_HII_VALUE *NewStack; Size = EXPRESSION_STACK_SIZE_INCREMENT; if (*StackPtr != NULL) { Size = Size + (*StackEnd - *Stack); } NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE)); if (NewStack == NULL) { return EFI_OUT_OF_RESOURCES; } if (*StackPtr != NULL) { // // Copy from Old Stack to the New Stack // CopyMem ( NewStack, *Stack, (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE) ); // // Free The Old Stack // FreePool (*Stack); } // // Make the Stack pointer point to the old data in the new stack // *StackPtr = NewStack + (*StackPtr - *Stack); *Stack = NewStack; *StackEnd = NewStack + Size; return EFI_SUCCESS; } /** Push an element onto the Boolean Stack. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd On input: old stack end; On output: new stack end @param Data Data to push. @retval EFI_SUCCESS Push stack success. **/ EFI_STATUS PushStack ( IN OUT EFI_HII_VALUE **Stack, IN OUT EFI_HII_VALUE **StackPtr, IN OUT EFI_HII_VALUE **StackEnd, IN EFI_HII_VALUE *Data ) { EFI_STATUS Status; // // Check for a stack overflow condition // if (*StackPtr >= *StackEnd) { // // Grow the stack // Status = GrowStack (Stack, StackPtr, StackEnd); if (EFI_ERROR (Status)) { return Status; } } // // Push the item onto the stack // CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE)); if (Data->Type == EFI_IFR_TYPE_BUFFER) { (*StackPtr)->Buffer = AllocateCopyPool (Data->BufferLen, Data->Buffer); if ((*StackPtr)->Buffer == NULL) { return EFI_OUT_OF_RESOURCES; } } *StackPtr = *StackPtr + 1; return EFI_SUCCESS; } /** Pop an element from the stack. @param Stack On input: old stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param Data Data to pop. @retval EFI_SUCCESS The value was popped onto the stack. @retval EFI_ACCESS_DENIED The pop operation underflowed the stack **/ EFI_STATUS PopStack ( IN EFI_HII_VALUE *Stack, IN OUT EFI_HII_VALUE **StackPtr, OUT EFI_HII_VALUE *Data ) { // // Check for a stack underflow condition // if (*StackPtr == Stack) { return EFI_ACCESS_DENIED; } // // Pop the item off the stack // *StackPtr = *StackPtr - 1; CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE)); return EFI_SUCCESS; } /** Reset stack pointer to begin of the stack. **/ VOID ResetCurrentExpressionStack ( VOID ) { mCurrentExpressionPointer = mCurrentExpressionStack; mFormExpressionPointer = mFormExpressionStack; mStatementExpressionPointer = mStatementExpressionStack; mOptionExpressionPointer = mOptionExpressionStack; } /** Push current expression onto the Stack @param Pointer Pointer to current expression. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PushCurrentExpression ( IN VOID *Pointer ) { EFI_HII_VALUE Data; Data.Type = EFI_IFR_TYPE_NUM_SIZE_64; Data.Value.u64 = (UINT64)(UINTN)Pointer; return PushStack ( &mCurrentExpressionStack, &mCurrentExpressionPointer, &mCurrentExpressionEnd, &Data ); } /** Pop current expression from the Stack @param Pointer Pointer to current expression to be pop. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PopCurrentExpression ( OUT VOID **Pointer ) { EFI_STATUS Status; EFI_HII_VALUE Data; Status = PopStack ( mCurrentExpressionStack, &mCurrentExpressionPointer, &Data ); *Pointer = (VOID *)(UINTN)Data.Value.u64; return Status; } /** Reset stack pointer to begin of the stack. **/ VOID ResetMapExpressionListStack ( VOID ) { mMapExpressionListPointer = mMapExpressionListStack; } /** Grow size of the stack. This is an internal function. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd On input: old stack end; On output: new stack end @param MemberSize The stack member size. @retval EFI_SUCCESS Grow stack success. @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. **/ EFI_STATUS GrowConditionalStack ( IN OUT HII_EXPRESSION ***Stack, IN OUT HII_EXPRESSION ***StackPtr, IN OUT HII_EXPRESSION ***StackEnd, IN UINTN MemberSize ) { UINTN Size; HII_EXPRESSION **NewStack; Size = EXPRESSION_STACK_SIZE_INCREMENT; if (*StackPtr != NULL) { Size = Size + (*StackEnd - *Stack); } NewStack = AllocatePool (Size * MemberSize); if (NewStack == NULL) { return EFI_OUT_OF_RESOURCES; } if (*StackPtr != NULL) { // // Copy from Old Stack to the New Stack // CopyMem ( NewStack, *Stack, (*StackEnd - *Stack) * MemberSize ); // // Free The Old Stack // FreePool (*Stack); } // // Make the Stack pointer point to the old data in the new stack // *StackPtr = NewStack + (*StackPtr - *Stack); *Stack = NewStack; *StackEnd = NewStack + Size; return EFI_SUCCESS; } /** Push an element onto the Stack. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd On input: old stack end; On output: new stack end @param Data Data to push. @retval EFI_SUCCESS Push stack success. **/ EFI_STATUS PushConditionalStack ( IN OUT HII_EXPRESSION ***Stack, IN OUT HII_EXPRESSION ***StackPtr, IN OUT HII_EXPRESSION ***StackEnd, IN HII_EXPRESSION **Data ) { EFI_STATUS Status; // // Check for a stack overflow condition // if (*StackPtr >= *StackEnd) { // // Grow the stack // Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (HII_EXPRESSION *)); if (EFI_ERROR (Status)) { return Status; } } // // Push the item onto the stack // CopyMem (*StackPtr, Data, sizeof (HII_EXPRESSION *)); *StackPtr = *StackPtr + 1; return EFI_SUCCESS; } /** Pop an element from the stack. @param Stack On input: old stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param Data Data to pop. @retval EFI_SUCCESS The value was popped onto the stack. @retval EFI_ACCESS_DENIED The pop operation underflowed the stack **/ EFI_STATUS PopConditionalStack ( IN HII_EXPRESSION **Stack, IN OUT HII_EXPRESSION ***StackPtr, OUT HII_EXPRESSION **Data ) { // // Check for a stack underflow condition // if (*StackPtr == Stack) { return EFI_ACCESS_DENIED; } // // Pop the item off the stack // *StackPtr = *StackPtr - 1; CopyMem (Data, *StackPtr, sizeof (HII_EXPRESSION *)); return EFI_SUCCESS; } /** Get the expression list count. @param Level Which type this expression belong to. Form, statement or option? @retval >=0 The expression count @retval -1 Input parameter error. **/ INTN GetConditionalExpressionCount ( IN EXPRESS_LEVEL Level ) { switch (Level) { case ExpressForm: return mFormExpressionPointer - mFormExpressionStack; case ExpressStatement: return mStatementExpressionPointer - mStatementExpressionStack; case ExpressOption: return mOptionExpressionPointer - mOptionExpressionStack; default: ASSERT (FALSE); return -1; } } /** Get the expression Buffer pointer. @param Level Which type this expression belong to. Form, statement or option? @retval The start pointer of the expression buffer or NULL. **/ HII_EXPRESSION ** GetConditionalExpressionList ( IN EXPRESS_LEVEL Level ) { switch (Level) { case ExpressForm: return mFormExpressionStack; case ExpressStatement: return mStatementExpressionStack; case ExpressOption: return mOptionExpressionStack; default: ASSERT (FALSE); return NULL; } } /** Push the expression options onto the Stack. @param Pointer Pointer to the current expression. @param Level Which type this expression belong to. Form, statement or option? @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PushConditionalExpression ( IN HII_EXPRESSION *Pointer, IN EXPRESS_LEVEL Level ) { switch (Level) { case ExpressForm: return PushConditionalStack ( &mFormExpressionStack, &mFormExpressionPointer, &mFormExpressionEnd, &Pointer ); case ExpressStatement: return PushConditionalStack ( &mStatementExpressionStack, &mStatementExpressionPointer, &mStatementExpressionEnd, &Pointer ); case ExpressOption: return PushConditionalStack ( &mOptionExpressionStack, &mOptionExpressionPointer, &mOptionExpressionEnd, &Pointer ); default: ASSERT (FALSE); return EFI_INVALID_PARAMETER; } } /** Pop the expression options from the Stack @param Level Which type this expression belong to. Form, statement or option? @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PopConditionalExpression ( IN EXPRESS_LEVEL Level ) { HII_EXPRESSION *Pointer; switch (Level) { case ExpressForm: return PopConditionalStack ( mFormExpressionStack, &mFormExpressionPointer, &Pointer ); case ExpressStatement: return PopConditionalStack ( mStatementExpressionStack, &mStatementExpressionPointer, &Pointer ); case ExpressOption: return PopConditionalStack ( mOptionExpressionStack, &mOptionExpressionPointer, &Pointer ); default: ASSERT (FALSE); return EFI_INVALID_PARAMETER; } } /** Push the list of map expression onto the Stack @param Pointer Pointer to the list of map expression to be pushed. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PushMapExpressionList ( IN VOID *Pointer ) { EFI_HII_VALUE Data; Data.Type = EFI_IFR_TYPE_NUM_SIZE_64; Data.Value.u64 = (UINT64)(UINTN)Pointer; return PushStack ( &mMapExpressionListStack, &mMapExpressionListPointer, &mMapExpressionListEnd, &Data ); } /** Pop the list of map expression from the Stack @param Pointer Pointer to the list of map expression to be pop. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PopMapExpressionList ( OUT VOID **Pointer ) { EFI_STATUS Status; EFI_HII_VALUE Data; Status = PopStack ( mMapExpressionListStack, &mMapExpressionListPointer, &Data ); *Pointer = (VOID *)(UINTN)Data.Value.u64; return Status; } /** Reset stack pointer to begin of the stack. **/ VOID ResetScopeStack ( VOID ) { mOpCodeScopeStackPointer = mOpCodeScopeStack; } /** Push an Operand onto the Stack @param Operand Operand to push. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PushScope ( IN UINT8 Operand ) { EFI_HII_VALUE Data; Data.Type = EFI_IFR_TYPE_NUM_SIZE_8; Data.Value.u8 = Operand; return PushStack ( &mOpCodeScopeStack, &mOpCodeScopeStackPointer, &mOpCodeScopeStackEnd, &Data ); } /** Pop an Operand from the Stack @param Operand Operand to pop. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PopScope ( OUT UINT8 *Operand ) { EFI_STATUS Status; EFI_HII_VALUE Data; Status = PopStack ( mOpCodeScopeStack, &mOpCodeScopeStackPointer, &Data ); *Operand = Data.Value.u8; return Status; } /** Grow size of the stack for Expression Dependencies. This is an internal function. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd On input: old stack end; On output: new stack end @retval EFI_SUCCESS Grow Dependency stack success. @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. **/ EFI_STATUS GrowDependencyStack ( IN OUT HII_DEPENDENCY_EXPRESSION ***Stack, IN OUT HII_DEPENDENCY_EXPRESSION ***StackPtr, IN OUT HII_DEPENDENCY_EXPRESSION ***StackEnd ) { UINTN Size; HII_DEPENDENCY_EXPRESSION **NewStack; Size = EXPRESSION_STACK_SIZE_INCREMENT; if (*StackPtr != NULL) { Size = Size + (*StackEnd - *Stack); } NewStack = AllocatePool (Size * sizeof (HII_DEPENDENCY_EXPRESSION *)); if (NewStack == NULL) { return EFI_OUT_OF_RESOURCES; } if (*StackPtr != NULL) { // // Copy from Old Stack to the New Stack // CopyMem ( NewStack, *Stack, (*StackEnd - *Stack) * sizeof (HII_DEPENDENCY_EXPRESSION *) ); // // Free The Old Stack // FreePool (*Stack); } // // Make the Stack pointer point to the old data in the new stack // *StackPtr = NewStack + (*StackPtr - *Stack); *Stack = NewStack; *StackEnd = NewStack + Size; return EFI_SUCCESS; } /** Push an element onto the Stack for Expression Dependencies. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd On input: old stack end; On output: new stack end @param Data Data to push. @retval EFI_SUCCESS Push stack success. **/ EFI_STATUS PushDependencyStack ( IN OUT HII_DEPENDENCY_EXPRESSION ***Stack, IN OUT HII_DEPENDENCY_EXPRESSION ***StackPtr, IN OUT HII_DEPENDENCY_EXPRESSION ***StackEnd, IN HII_DEPENDENCY_EXPRESSION **Data ) { EFI_STATUS Status; // // Check for a stack overflow condition // if (*StackPtr >= *StackEnd) { // // Grow the stack // Status = GrowDependencyStack (Stack, StackPtr, StackEnd); if (EFI_ERROR (Status)) { return Status; } } // // Push the item onto the stack // CopyMem (*StackPtr, Data, sizeof (HII_DEPENDENCY_EXPRESSION *)); *StackPtr = *StackPtr + 1; return EFI_SUCCESS; } /** Pop the Expression Dependency options from the Stack @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param Data Data to push. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PopDependencyStack ( IN HII_DEPENDENCY_EXPRESSION **Stack, IN OUT HII_DEPENDENCY_EXPRESSION ***StackPtr, OUT HII_DEPENDENCY_EXPRESSION **Data ) { // // Check for a stack underflow condition // if (*StackPtr == Stack) { return EFI_ACCESS_DENIED; } // // Pop the item off the stack // *StackPtr = *StackPtr - 1; CopyMem (Data, *StackPtr, sizeof (HII_DEPENDENCY_EXPRESSION *)); return EFI_SUCCESS; } /** Push the list of Expression Dependencies onto the Stack @param Pointer Pointer to the list of map expression to be pushed. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PushDependencyExpDes ( IN HII_DEPENDENCY_EXPRESSION **Pointer ) { return PushDependencyStack ( &mExpressionDependencyStack, &mExpressionDependencyPointer, &mExpressionDependencyEnd, Pointer ); } /** Pop the list of Expression Dependencies from the Stack @param Pointer Pointer to the list of map expression to be pop. @retval EFI_SUCCESS The value was pushed onto the stack. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. **/ EFI_STATUS PopDependencyExpDes ( OUT HII_DEPENDENCY_EXPRESSION **Pointer ) { return PopDependencyStack ( mExpressionDependencyStack, &mExpressionDependencyPointer, Pointer ); } /** Retrieve dependencies within an expression. These dependencies can express how this expression will be evaluated. @param[in,out] Expression Expression to retrieve dependencies. @retval EFI_SUCCESS The dependencies were successfully retrieved. @retval EFI_OUT_OF_RESOURCES There is not enough system memory. **/ EFI_STATUS GetHiiExpressionDependency ( IN OUT HII_EXPRESSION *Expression ) { EFI_STATUS Status; LIST_ENTRY *Link; HII_EXPRESSION_OPCODE *ExpressionOpCode; HII_DEPENDENCY_EXPRESSION *DepExpressionOpCode; LIST_ENTRY *SubExpressionLink; HII_EXPRESSION *SubExpression; UINT8 MapPairCount; Link = GetFirstNode (&Expression->OpCodeListHead); while (!IsNull (&Expression->OpCodeListHead, Link)) { ExpressionOpCode = HII_EXPRESSION_OPCODE_FROM_LINK (Link); Link = GetNextNode (&Expression->OpCodeListHead, Link); Status = EFI_SUCCESS; DepExpressionOpCode = (HII_DEPENDENCY_EXPRESSION *)AllocateZeroPool (sizeof (HII_DEPENDENCY_EXPRESSION)); if (DepExpressionOpCode == NULL) { return EFI_OUT_OF_RESOURCES; } switch (ExpressionOpCode->Operand) { // // Constant // case EFI_IFR_FALSE_OP: case EFI_IFR_ONE_OP: case EFI_IFR_ONES_OP: case EFI_IFR_TRUE_OP: case EFI_IFR_UINT8_OP: case EFI_IFR_UINT16_OP: case EFI_IFR_UINT32_OP: case EFI_IFR_UINT64_OP: case EFI_IFR_UNDEFINED_OP: case EFI_IFR_VERSION_OP: case EFI_IFR_ZERO_OP: DepExpressionOpCode->ConstantExp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->ConstantExp.Value, &ExpressionOpCode->ExtraData.Value, sizeof (EFI_HII_VALUE)); PushDependencyExpDes (&DepExpressionOpCode); break; // // Built-in functions // case EFI_IFR_DUP_OP: DepExpressionOpCode->DupExp.Operand = ExpressionOpCode->Operand; PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_EQ_ID_VAL_OP: DepExpressionOpCode->EqIdValExp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->EqIdValExp.QuestionId, &ExpressionOpCode->ExtraData.EqIdValData.QuestionId, sizeof (EFI_QUESTION_ID)); CopyMem (&DepExpressionOpCode->EqIdValExp.Value, &ExpressionOpCode->ExtraData.EqIdValData.Value, sizeof (EFI_HII_VALUE)); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_EQ_ID_ID_OP: DepExpressionOpCode->EqIdIdExp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->EqIdIdExp.QuestionId1, &ExpressionOpCode->ExtraData.EqIdIdData.QuestionId1, sizeof (EFI_QUESTION_ID)); CopyMem (&DepExpressionOpCode->EqIdIdExp.QuestionId2, &ExpressionOpCode->ExtraData.EqIdIdData.QuestionId2, sizeof (EFI_QUESTION_ID)); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_EQ_ID_VAL_LIST_OP: DepExpressionOpCode->EqIdListExp.Operand = ExpressionOpCode->Operand; DepExpressionOpCode->EqIdListExp.ListLength = ExpressionOpCode->ExtraData.EqIdListData.ListLength; CopyMem (&DepExpressionOpCode->EqIdListExp.QuestionId, &ExpressionOpCode->ExtraData.EqIdListData.QuestionId, sizeof (EFI_QUESTION_ID)); PushDependencyExpDes (&DepExpressionOpCode); DepExpressionOpCode->EqIdListExp.ValueList = AllocateCopyPool ( DepExpressionOpCode->EqIdListExp.ListLength * sizeof (UINT16), ExpressionOpCode->ExtraData.EqIdListData.ValueList ); if (DepExpressionOpCode->EqIdListExp.ValueList == NULL) { return EFI_OUT_OF_RESOURCES; } PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_GET_OP: DepExpressionOpCode->GetExp.Operand = ExpressionOpCode->Operand; DepExpressionOpCode->GetExp.VarStorage = ExpressionOpCode->ExtraData.GetSetData.VarStorage; CopyMem (&DepExpressionOpCode->GetExp.VarStoreInfo.VarName, &ExpressionOpCode->ExtraData.GetSetData.VarStoreInfo.VarName, sizeof (EFI_STRING_ID)); CopyMem (&DepExpressionOpCode->GetExp.VarStoreInfo.VarOffset, &ExpressionOpCode->ExtraData.GetSetData.VarStoreInfo.VarOffset, sizeof (UINT16)); DepExpressionOpCode->GetExp.VarStoreInfo = ExpressionOpCode->ExtraData.GetSetData.VarStoreInfo; if (ExpressionOpCode->ExtraData.GetSetData.ValueName != NULL) { DepExpressionOpCode->GetExp.ValueName = (CHAR16 *)AllocateCopyPool (sizeof (ExpressionOpCode->ExtraData.GetSetData.ValueName), ExpressionOpCode->ExtraData.GetSetData.ValueName); if (DepExpressionOpCode->GetExp.ValueName == NULL) { return EFI_OUT_OF_RESOURCES; } } DepExpressionOpCode->GetExp.ValueType = ExpressionOpCode->ExtraData.GetSetData.ValueType; DepExpressionOpCode->GetExp.ValueWidth = ExpressionOpCode->ExtraData.GetSetData.ValueWidth; PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_QUESTION_REF1_OP: DepExpressionOpCode->QuestionRef1Exp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->QuestionRef1Exp.QuestionId, &ExpressionOpCode->ExtraData.QuestionRef1Data.QuestionId, sizeof (EFI_QUESTION_ID)); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_RULE_REF_OP: DepExpressionOpCode->RuleRefExp.Operand = ExpressionOpCode->Operand; DepExpressionOpCode->RuleRefExp.RuleId = ExpressionOpCode->ExtraData.RuleId; PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_STRING_REF1_OP: DepExpressionOpCode->StringRef1Exp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->StringRef1Exp.Value.Value.string, &ExpressionOpCode->ExtraData.Value.Value.string, sizeof (EFI_STRING_ID)); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_THIS_OP: DepExpressionOpCode->ThisExp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->ThisExp.QuestionId, &ExpressionOpCode->ExtraData.QuestionRef1Data.QuestionId, sizeof (EFI_QUESTION_ID)); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_SECURITY_OP: DepExpressionOpCode->SecurityExp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->SecurityExp.Permissions, &ExpressionOpCode->ExtraData.Guid, sizeof (EFI_GUID)); PushDependencyExpDes (&DepExpressionOpCode); break; // // unary-op // case EFI_IFR_LENGTH_OP: DepExpressionOpCode->LengthExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->LengthExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_NOT_OP: DepExpressionOpCode->NotExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->NotExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_BITWISE_NOT_OP: DepExpressionOpCode->BitWiseNotExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->BitWiseNotExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_QUESTION_REF2_OP: DepExpressionOpCode->QuestionRef2Exp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->QuestionRef2Exp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_QUESTION_REF3_OP: DepExpressionOpCode->QuestionRef3Exp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->QuestionRef3Exp.DevicePath, &ExpressionOpCode->ExtraData.QuestionRef3Data.DevicePath, sizeof (EFI_DEVICE_PATH)); CopyMem (&DepExpressionOpCode->QuestionRef3Exp.Guid, &ExpressionOpCode->ExtraData.QuestionRef3Data.Guid, sizeof (EFI_GUID)); PopDependencyExpDes (&DepExpressionOpCode->QuestionRef3Exp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_SET_OP: DepExpressionOpCode->SetExp.Operand = ExpressionOpCode->Operand; DepExpressionOpCode->SetExp.VarStorage = ExpressionOpCode->ExtraData.GetSetData.VarStorage; CopyMem (&DepExpressionOpCode->SetExp.VarStoreInfo.VarName, &ExpressionOpCode->ExtraData.GetSetData.VarStoreInfo.VarName, sizeof (EFI_STRING_ID)); CopyMem (&DepExpressionOpCode->SetExp.VarStoreInfo.VarOffset, &ExpressionOpCode->ExtraData.GetSetData.VarStoreInfo.VarOffset, sizeof (UINT16)); DepExpressionOpCode->SetExp.VarStoreInfo = ExpressionOpCode->ExtraData.GetSetData.VarStoreInfo; if (ExpressionOpCode->ExtraData.GetSetData.ValueName != NULL) { DepExpressionOpCode->SetExp.ValueName = (CHAR16 *)AllocateCopyPool (sizeof (ExpressionOpCode->ExtraData.GetSetData.ValueName), ExpressionOpCode->ExtraData.GetSetData.ValueName); if (DepExpressionOpCode->SetExp.ValueName == NULL) { return EFI_OUT_OF_RESOURCES; } } DepExpressionOpCode->SetExp.ValueType = ExpressionOpCode->ExtraData.GetSetData.ValueType; DepExpressionOpCode->SetExp.ValueWidth = ExpressionOpCode->ExtraData.GetSetData.ValueWidth; PopDependencyExpDes (&DepExpressionOpCode->SetExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_STRING_REF2_OP: DepExpressionOpCode->StringRef2Exp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->StringRef2Exp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_TO_BOOLEAN_OP: DepExpressionOpCode->ToBooleanExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ToBooleanExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_TO_STRING_OP: DepExpressionOpCode->ToStringExp.Operand = ExpressionOpCode->Operand; DepExpressionOpCode->ToStringExp.Format = ExpressionOpCode->ExtraData.Format; PopDependencyExpDes (&DepExpressionOpCode->ToStringExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_TO_UINT_OP: DepExpressionOpCode->ToUintExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ToUintExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_TO_LOWER_OP: DepExpressionOpCode->ToLowerExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ToLowerExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_TO_UPPER_OP: DepExpressionOpCode->ToUpperExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ToUpperExp.SubExpression); PushDependencyExpDes (&DepExpressionOpCode); break; // // binary-op // case EFI_IFR_ADD_OP: DepExpressionOpCode->AddExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->AddExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->AddExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_AND_OP: DepExpressionOpCode->AndExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->AndExp.SubExpression1); PopDependencyExpDes (&DepExpressionOpCode->AndExp.SubExpression2); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_BITWISE_AND_OP: DepExpressionOpCode->BitwiseAndExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->BitwiseAndExp.SubExpression1); PopDependencyExpDes (&DepExpressionOpCode->BitwiseAndExp.SubExpression2); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_BITWISE_OR_OP: DepExpressionOpCode->BitwiseOrExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->BitwiseOrExp.SubExpression1); PopDependencyExpDes (&DepExpressionOpCode->BitwiseOrExp.SubExpression2); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_CATENATE_OP: DepExpressionOpCode->CatenateExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->CatenateExp.LeftStringExp); PopDependencyExpDes (&DepExpressionOpCode->CatenateExp.RightStringExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_DIVIDE_OP: DepExpressionOpCode->DivExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->DivExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->DivExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_EQUAL_OP: DepExpressionOpCode->EqualExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->EqualExp.SubExpression1); PopDependencyExpDes (&DepExpressionOpCode->EqualExp.SubExpression2); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_GREATER_EQUAL_OP: DepExpressionOpCode->GreaterEqualExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->GreaterEqualExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->GreaterEqualExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_GREATER_THAN_OP: DepExpressionOpCode->GreaterThanExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->GreaterThanExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->GreaterThanExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_LESS_EQUAL_OP: DepExpressionOpCode->LessEqualExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->LessEqualExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->LessEqualExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_LESS_THAN_OP: DepExpressionOpCode->LessThanExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->LessThanExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->LessThanExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_MATCH_OP: DepExpressionOpCode->MatchExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->MatchExp.PatternExp); PopDependencyExpDes (&DepExpressionOpCode->MatchExp.StringExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_MATCH2_OP: DepExpressionOpCode->Match2Exp.Operand = ExpressionOpCode->Operand; CopyMem (&DepExpressionOpCode->Match2Exp.SyntaxType, &ExpressionOpCode->ExtraData.Guid, sizeof (EFI_GUID)); PopDependencyExpDes (&DepExpressionOpCode->Match2Exp.PatternExp); PopDependencyExpDes (&DepExpressionOpCode->Match2Exp.StringExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_MODULO_OP: DepExpressionOpCode->ModExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ModExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->ModExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_MULTIPLY_OP: DepExpressionOpCode->MultExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->MultExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->MultExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_NOT_EQUAL_OP: DepExpressionOpCode->NotEqualExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->NotEqualExp.SubExpression1); PopDependencyExpDes (&DepExpressionOpCode->NotEqualExp.SubExpression2); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_OR_OP: DepExpressionOpCode->OrExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->OrExp.SubExpression1); PopDependencyExpDes (&DepExpressionOpCode->OrExp.SubExpression2); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_SHIFT_LEFT_OP: DepExpressionOpCode->ShiftLeftExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ShiftLeftExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->ShiftLeftExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_SHIFT_RIGHT_OP: DepExpressionOpCode->ShiftRightExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ShiftRightExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->ShiftRightExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_SUBTRACT_OP: DepExpressionOpCode->SubtractExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->SubtractExp.LeftHandExp); PopDependencyExpDes (&DepExpressionOpCode->SubtractExp.RightHandExp); PushDependencyExpDes (&DepExpressionOpCode); break; // // ternary-op // case EFI_IFR_CONDITIONAL_OP: DepExpressionOpCode->ConditionalExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->ConditionalExp.CondTrueValExp); PopDependencyExpDes (&DepExpressionOpCode->ConditionalExp.CondFalseValExp); PopDependencyExpDes (&DepExpressionOpCode->ConditionalExp.ConditionExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_FIND_OP: DepExpressionOpCode->FindExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->FindExp.StringToSearchExp); PopDependencyExpDes (&DepExpressionOpCode->FindExp.StringToCompWithExp); PopDependencyExpDes (&DepExpressionOpCode->FindExp.IndexExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_MID_OP: DepExpressionOpCode->MidExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->MidExp.StringOrBufferExp); PopDependencyExpDes (&DepExpressionOpCode->MidExp.IndexExp); PopDependencyExpDes (&DepExpressionOpCode->MidExp.LengthExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_TOKEN_OP: DepExpressionOpCode->TokenExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->TokenExp.StringToSearchExp); PopDependencyExpDes (&DepExpressionOpCode->TokenExp.DelimiterExp); PopDependencyExpDes (&DepExpressionOpCode->TokenExp.IndexExp); PushDependencyExpDes (&DepExpressionOpCode); break; case EFI_IFR_SPAN_OP: DepExpressionOpCode->SpanExp.Operand = ExpressionOpCode->Operand; PopDependencyExpDes (&DepExpressionOpCode->SpanExp.StringToSearchExp); PopDependencyExpDes (&DepExpressionOpCode->SpanExp.CharsetExp); PopDependencyExpDes (&DepExpressionOpCode->SpanExp.IndexExp); PushDependencyExpDes (&DepExpressionOpCode); break; // // Map // case EFI_IFR_MAP_OP: // // Go through map expression list. // DepExpressionOpCode->MapExp.Operand = ExpressionOpCode->Operand; MapPairCount = 0; SubExpressionLink = GetFirstNode (&ExpressionOpCode->MapExpressionList); while (!IsNull (&ExpressionOpCode->MapExpressionList, SubExpressionLink)) { MapPairCount++; SubExpressionLink = GetNextNode (&ExpressionOpCode->MapExpressionList, SubExpressionLink); if (IsNull (&ExpressionOpCode->MapExpressionList, SubExpressionLink)) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Goto the first expression on next pair. // SubExpressionLink = GetNextNode (&ExpressionOpCode->MapExpressionList, SubExpressionLink); } DepExpressionOpCode->MapExp.ExpPair = (HII_DEPENDENCY_EXPRESSION_PAIR *)AllocateZeroPool ( MapPairCount * sizeof (HII_DEPENDENCY_EXPRESSION_PAIR) ); if (DepExpressionOpCode->MapExp.ExpPair == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } DepExpressionOpCode->MapExp.ExpPairNo = MapPairCount; MapPairCount = 0; PopDependencyExpDes (&DepExpressionOpCode->MapExp.SubExp); // // Go through map expression list. // SubExpressionLink = GetFirstNode (&ExpressionOpCode->MapExpressionList); while (!IsNull (&ExpressionOpCode->MapExpressionList, SubExpressionLink)) { SubExpression = HII_EXPRESSION_FROM_LINK (SubExpressionLink); // // Get the first expression description in this pair. // GetHiiExpressionDependency (SubExpression); DepExpressionOpCode->MapExp.ExpPair[MapPairCount].MatchExp = SubExpression->RootDependencyExp; // // Get the second expression description in this pair. // SubExpressionLink = GetNextNode (&ExpressionOpCode->MapExpressionList, SubExpressionLink); SubExpression = HII_EXPRESSION_FROM_LINK (SubExpressionLink); GetHiiExpressionDependency (SubExpression); DepExpressionOpCode->MapExp.ExpPair[MapPairCount].ReturnExp = SubExpression->RootDependencyExp; // // Goto the first expression on next pair. // SubExpressionLink = GetNextNode (&ExpressionOpCode->MapExpressionList, SubExpressionLink); MapPairCount++; } PushDependencyExpDes (&DepExpressionOpCode); break; default: break; } } PopDependencyExpDes (&Expression->RootDependencyExp); Done: return Status; } /** Return the result of the expression list. Check the expression list and return the highest priority express result. Priority: DisableIf > SuppressIf > GrayOutIf > FALSE @param[in] ExpList The input expression list. @param[in] Evaluate Whether need to evaluate the expression first. @param[in] FormSet FormSet associated with this expression. @param[in] Form Form associated with this expression. @retval EXPRESS_RESULT Return the higher priority express result. DisableIf > SuppressIf > GrayOutIf > FALSE **/ EXPRESS_RESULT EvaluateExpressionList ( IN HII_EXPRESSION_LIST *ExpList, IN BOOLEAN Evaluate, IN HII_FORMSET *FormSet OPTIONAL, IN HII_FORM *Form OPTIONAL ) { UINTN Index; EXPRESS_RESULT ReturnVal; EXPRESS_RESULT CompareOne; EFI_STATUS Status; if (ExpList == NULL) { return ExpressFalse; } ASSERT (ExpList->Signature == HII_EXPRESSION_LIST_SIGNATURE); Index = 0; // // Check whether need to evaluate the expression first. // if (Evaluate) { while (ExpList->Count > Index) { Status = EvaluateHiiExpression (FormSet, Form, ExpList->Expression[Index++]); if (EFI_ERROR (Status)) { return ExpressFalse; } } } // // Run the list of expressions. // ReturnVal = ExpressFalse; for (Index = 0; Index < ExpList->Count; Index++) { if (IsHiiValueTrue (&ExpList->Expression[Index]->Result)) { switch (ExpList->Expression[Index]->Type) { case EFI_HII_EXPRESSION_SUPPRESS_IF: CompareOne = ExpressSuppress; break; case EFI_HII_EXPRESSION_GRAY_OUT_IF: CompareOne = ExpressGrayOut; break; case EFI_HII_EXPRESSION_DISABLE_IF: CompareOne = ExpressDisable; break; default: return ExpressFalse; } ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal; } } return ReturnVal; }