diff options
Diffstat (limited to 'MdeModulePkg/Universal/SetupBrowserDxe')
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Expression.c | 7582 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Expression.h | 520 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c | 5500 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c | 5374 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Setup.c | 13504 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Setup.h | 3736 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni | 32 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf | 158 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni | 28 |
9 files changed, 18217 insertions, 18217 deletions
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c index d21930b31a..c6b44ec652 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -1,3791 +1,3791 @@ -/** @file
-Utility functions for expression evaluation.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Setup.h"
-
-//
-// Global stack used to evaluate boolean expresions
-//
-EFI_HII_VALUE *mOpCodeScopeStack = NULL;
-EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
-EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
-
-EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
-EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
-EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
-UINTN mExpressionEvaluationStackOffset = 0;
-
-EFI_HII_VALUE *mCurrentExpressionStack = NULL;
-EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
-EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
-
-EFI_HII_VALUE *mMapExpressionListStack = NULL;
-EFI_HII_VALUE *mMapExpressionListEnd = NULL;
-EFI_HII_VALUE *mMapExpressionListPointer = NULL;
-
-FORM_EXPRESSION **mFormExpressionStack = NULL;
-FORM_EXPRESSION **mFormExpressionEnd = NULL;
-FORM_EXPRESSION **mFormExpressionPointer = NULL;
-
-FORM_EXPRESSION **mStatementExpressionStack = NULL;
-FORM_EXPRESSION **mStatementExpressionEnd = NULL;
-FORM_EXPRESSION **mStatementExpressionPointer = NULL;
-
-FORM_EXPRESSION **mOptionExpressionStack = NULL;
-FORM_EXPRESSION **mOptionExpressionEnd = NULL;
-FORM_EXPRESSION **mOptionExpressionPointer = NULL;
-
-//
-// Unicode collation protocol interface
-//
-EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
-EFI_USER_MANAGER_PROTOCOL *mUserManager = 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);
- ASSERT ((*StackPtr)->Buffer != NULL);
- }
-
- *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 FORM_EXPRESSION ***Stack,
- IN OUT FORM_EXPRESSION ***StackPtr,
- IN OUT FORM_EXPRESSION ***StackEnd,
- IN UINTN MemberSize
- )
-{
- UINTN Size;
- FORM_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 FORM_EXPRESSION ***Stack,
- IN OUT FORM_EXPRESSION ***StackPtr,
- IN OUT FORM_EXPRESSION ***StackEnd,
- IN FORM_EXPRESSION **Data
- )
-{
- EFI_STATUS Status;
-
- //
- // Check for a stack overflow condition
- //
- if (*StackPtr >= *StackEnd) {
- //
- // Grow the stack
- //
- Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (FORM_EXPRESSION *));
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Push the item onto the stack
- //
- CopyMem (*StackPtr, Data, sizeof (FORM_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 FORM_EXPRESSION **Stack,
- IN OUT FORM_EXPRESSION ***StackPtr,
- OUT FORM_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 (FORM_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.
-
-**/
-FORM_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 FORM_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
- )
-{
- FORM_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;
-}
-
-/**
- Push an Expression value onto the Stack
-
- @param Value Expression value 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
-PushExpression (
- IN EFI_HII_VALUE *Value
- )
-{
- return PushStack (
- &mExpressionEvaluationStack,
- &mExpressionEvaluationStackPointer,
- &mExpressionEvaluationStackEnd,
- Value
- );
-}
-
-/**
- Pop an Expression value from the stack.
-
- @param Value Expression value to pop.
-
- @retval EFI_SUCCESS The value was popped onto the stack.
- @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
-
-**/
-EFI_STATUS
-PopExpression (
- OUT EFI_HII_VALUE *Value
- )
-{
- return PopStack (
- mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
- &mExpressionEvaluationStackPointer,
- Value
- );
-}
-
-/**
- Get current stack offset from stack start.
-
- @return Stack offset to stack start.
-**/
-UINTN
-SaveExpressionEvaluationStackOffset (
- VOID
- )
-{
- UINTN TempStackOffset;
-
- TempStackOffset = mExpressionEvaluationStackOffset;
- mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
- return TempStackOffset;
-}
-
-/**
- Restore stack offset based on input stack offset
-
- @param StackOffset Offset to stack start.
-
-**/
-VOID
-RestoreExpressionEvaluationStackOffset (
- UINTN StackOffset
- )
-{
- mExpressionEvaluationStackOffset = StackOffset;
-}
-
-/**
- Get Form given its FormId.
-
- @param FormSet The formset which contains this form.
- @param FormId Id of this form.
-
- @retval Pointer The form.
- @retval NULL Specified Form is not found in the formset.
-
-**/
-FORM_BROWSER_FORM *
-IdToForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN UINT16 FormId
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORM *Form;
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- if (Form->FormId == FormId) {
- return Form;
- }
-
- Link = GetNextNode (&FormSet->FormListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Search a Question in Form scope using its QuestionId.
-
- @param Form The form which contains this Question.
- @param QuestionId Id of this Question.
-
- @retval Pointer The Question.
- @retval NULL Specified Question not found in the form.
-
-**/
-FORM_BROWSER_STATEMENT *
-IdToQuestion2 (
- IN FORM_BROWSER_FORM *Form,
- IN UINT16 QuestionId
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
-
- if ((QuestionId == 0) || (Form == NULL)) {
- //
- // The value of zero is reserved
- //
- return NULL;
- }
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-
- if (Question->QuestionId == QuestionId) {
- return Question;
- }
-
- Link = GetNextNode (&Form->StatementListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Search a Question in Formset scope using its QuestionId.
-
- @param FormSet The formset which contains this form.
- @param Form The form which contains this Question.
- @param QuestionId Id of this Question.
-
- @retval Pointer The Question.
- @retval NULL Specified Question not found in the form.
-
-**/
-FORM_BROWSER_STATEMENT *
-IdToQuestion (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN UINT16 QuestionId
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
-
- //
- // Search in the form scope first
- //
- Question = IdToQuestion2 (Form, QuestionId);
- if (Question != NULL) {
- return Question;
- }
-
- //
- // Search in the formset scope
- //
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- Question = IdToQuestion2 (Form, QuestionId);
- if (Question != NULL) {
- //
- // EFI variable storage may be updated by Callback() asynchronous,
- // to keep synchronous, always reload the Question Value.
- //
- if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
- }
-
- return Question;
- }
-
- Link = GetNextNode (&FormSet->FormListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Get Expression given its RuleId.
-
- @param Form The form which contains this Expression.
- @param RuleId Id of this Expression.
-
- @retval Pointer The Expression.
- @retval NULL Specified Expression not found in the form.
-
-**/
-FORM_EXPRESSION *
-RuleIdToExpression (
- IN FORM_BROWSER_FORM *Form,
- IN UINT8 RuleId
- )
-{
- LIST_ENTRY *Link;
- FORM_EXPRESSION *Expression;
-
- Link = GetFirstNode (&Form->ExpressionListHead);
- while (!IsNull (&Form->ExpressionListHead, Link)) {
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
-
- if ((Expression->Type == EFI_HII_EXPRESSION_RULE) && (Expression->RuleId == RuleId)) {
- return Expression;
- }
-
- Link = GetNextNode (&Form->ExpressionListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Locate the Unicode Collation Protocol interface for later use.
-
- @retval EFI_SUCCESS Protocol interface initialize success.
- @retval Other Protocol interface initialize failed.
-
-**/
-EFI_STATUS
-InitializeUnicodeCollationProtocol (
- VOID
- )
-{
- EFI_STATUS Status;
-
- if (mUnicodeCollation != NULL) {
- return EFI_SUCCESS;
- }
-
- //
- // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
- // instances first and then select one which support English language.
- // Current implementation just pick the first instance.
- //
- Status = gBS->LocateProtocol (
- &gEfiUnicodeCollation2ProtocolGuid,
- NULL,
- (VOID **)&mUnicodeCollation
- );
- return Status;
-}
-
-/**
- Convert the input Unicode character to upper.
-
- @param String Th Unicode character to be converted.
-
-**/
-VOID
-IfrStrToUpper (
- IN CHAR16 *String
- )
-{
- while (*String != 0) {
- if ((*String >= 'a') && (*String <= 'z')) {
- *String = (UINT16)((*String) & ((UINT16) ~0x20));
- }
-
- String++;
- }
-}
-
-/**
- Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
-
- EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
- EFI_IFR_TYPE_BUFFER when do the value compare.
-
- @param Value Expression value to compare on.
-
- @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
- @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
-
-**/
-BOOLEAN
-IsTypeInBuffer (
- IN EFI_HII_VALUE *Value
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_BUFFER:
- case EFI_IFR_TYPE_DATE:
- case EFI_IFR_TYPE_TIME:
- case EFI_IFR_TYPE_REF:
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
-/**
- Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
-
- @param Value Expression value to compare on.
-
- @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
- @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
-
-**/
-BOOLEAN
-IsTypeInUINT64 (
- IN EFI_HII_VALUE *Value
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- case EFI_IFR_TYPE_NUM_SIZE_16:
- case EFI_IFR_TYPE_NUM_SIZE_32:
- case EFI_IFR_TYPE_NUM_SIZE_64:
- case EFI_IFR_TYPE_BOOLEAN:
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
-/**
- Return the buffer length for this value.
-
- EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
- EFI_IFR_TYPE_BUFFER when do the value compare.
-
- @param Value Expression value to compare on.
-
- @retval BufLen Return the buffer length.
-
-**/
-UINT16
-GetLengthForValue (
- IN EFI_HII_VALUE *Value
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_BUFFER:
- return Value->BufferLen;
-
- case EFI_IFR_TYPE_DATE:
- return (UINT16)sizeof (EFI_HII_DATE);
-
- case EFI_IFR_TYPE_TIME:
- return (UINT16)sizeof (EFI_HII_TIME);
-
- case EFI_IFR_TYPE_REF:
- return (UINT16)sizeof (EFI_HII_REF);
-
- default:
- return 0;
- }
-}
-
-/**
- Return the buffer pointer for this value.
-
- EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
- EFI_IFR_TYPE_BUFFER when do the value compare.
-
- @param Value Expression value to compare on.
-
- @retval Buf Return the buffer pointer.
-
-**/
-UINT8 *
-GetBufferForValue (
- IN EFI_HII_VALUE *Value
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_BUFFER:
- return Value->Buffer;
-
- case EFI_IFR_TYPE_DATE:
- return (UINT8 *)(&Value->Value.date);
-
- case EFI_IFR_TYPE_TIME:
- return (UINT8 *)(&Value->Value.time);
-
- case EFI_IFR_TYPE_REF:
- return (UINT8 *)(&Value->Value.ref);
-
- default:
- return NULL;
- }
-}
-
-/**
- Evaluate opcode EFI_IFR_TO_STRING.
-
- @param FormSet Formset which contains this opcode.
- @param Format String format in EFI_IFR_TO_STRING.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrToString (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN UINT8 Format,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value;
- CHAR16 *String;
- CHAR16 *PrintFormat;
- CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
- UINT8 *TmpBuf;
- UINT8 *SrcBuf;
- UINTN SrcLen;
- UINTN BufferSize;
-
- Status = PopExpression (&Value);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- switch (Value.Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- case EFI_IFR_TYPE_NUM_SIZE_16:
- case EFI_IFR_TYPE_NUM_SIZE_32:
- case EFI_IFR_TYPE_NUM_SIZE_64:
- BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
- switch (Format) {
- case EFI_IFR_STRING_UNSIGNED_DEC:
- case EFI_IFR_STRING_SIGNED_DEC:
- PrintFormat = L"%ld";
- break;
-
- case EFI_IFR_STRING_LOWERCASE_HEX:
- PrintFormat = L"%lx";
- break;
-
- case EFI_IFR_STRING_UPPERCASE_HEX:
- PrintFormat = L"%lX";
- break;
-
- default:
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
- String = Buffer;
- break;
-
- case EFI_IFR_TYPE_STRING:
- CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
- return EFI_SUCCESS;
-
- case EFI_IFR_TYPE_BOOLEAN:
- String = (Value.Value.b) ? L"True" : L"False";
- break;
-
- case EFI_IFR_TYPE_BUFFER:
- case EFI_IFR_TYPE_DATE:
- case EFI_IFR_TYPE_TIME:
- case EFI_IFR_TYPE_REF:
- //
- // + 3 is base on the unicode format, the length may be odd number,
- // so need 1 byte to align, also need 2 bytes for L'\0'.
- //
- if (Value.Type == EFI_IFR_TYPE_BUFFER) {
- SrcLen = Value.BufferLen;
- SrcBuf = Value.Buffer;
- } else {
- SrcBuf = GetBufferForValue (&Value);
- SrcLen = GetLengthForValue (&Value);
- }
-
- TmpBuf = AllocateZeroPool (SrcLen + 3);
- ASSERT (TmpBuf != NULL);
- if (Format == EFI_IFR_STRING_ASCII) {
- CopyMem (TmpBuf, SrcBuf, SrcLen);
- PrintFormat = L"%a";
- } else {
- // Format == EFI_IFR_STRING_UNICODE
- CopyMem (TmpBuf, SrcBuf, SrcLen * sizeof (CHAR16));
- PrintFormat = L"%s";
- }
-
- UnicodeSPrint (Buffer, sizeof (Buffer), PrintFormat, TmpBuf);
- String = Buffer;
- FreePool (TmpBuf);
- if (Value.Type == EFI_IFR_TYPE_BUFFER) {
- FreePool (Value.Buffer);
- }
-
- break;
-
- default:
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Result->Type = EFI_IFR_TYPE_STRING;
- Result->Value.string = NewString (String, FormSet->HiiHandle);
- return EFI_SUCCESS;
-}
-
-/**
- Evaluate opcode EFI_IFR_TO_UINT.
-
- @param FormSet Formset which contains this opcode.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrToUint (
- IN FORM_BROWSER_FORMSET *FormSet,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value;
- CHAR16 *String;
- CHAR16 *StringPtr;
-
- Status = PopExpression (&Value);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((Value.Type >= EFI_IFR_TYPE_OTHER) && !IsTypeInBuffer (&Value)) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Status = EFI_SUCCESS;
- if (Value.Type == EFI_IFR_TYPE_STRING) {
- String = GetToken (Value.Value.string, FormSet->HiiHandle);
- if (String == NULL) {
- return EFI_NOT_FOUND;
- }
-
- IfrStrToUpper (String);
- StringPtr = StrStr (String, L"0X");
- if (StringPtr != NULL) {
- //
- // Hex string
- //
- Result->Value.u64 = StrHexToUint64 (String);
- } else {
- //
- // decimal string
- //
- Result->Value.u64 = StrDecimalToUint64 (String);
- }
-
- FreePool (String);
- } else if (IsTypeInBuffer (&Value)) {
- if (GetLengthForValue (&Value) > 8) {
- if (Value.Type == EFI_IFR_TYPE_BUFFER) {
- FreePool (Value.Buffer);
- }
-
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- ASSERT (GetBufferForValue (&Value) != NULL);
- Result->Value.u64 = *(UINT64 *)GetBufferForValue (&Value);
-
- if (Value.Type == EFI_IFR_TYPE_BUFFER) {
- FreePool (Value.Buffer);
- }
- } else {
- CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
- }
-
- Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_CATENATE.
-
- @param FormSet Formset which contains this opcode.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrCatenate (
- IN FORM_BROWSER_FORMSET *FormSet,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[2];
- CHAR16 *String[2];
- UINTN Index;
- CHAR16 *StringPtr;
- UINTN Size;
- UINT16 Length0;
- UINT16 Length1;
- UINT8 *TmpBuf;
- UINTN MaxLen;
-
- //
- // String[0] - The second string
- // String[1] - The first string
- //
- String[0] = NULL;
- String[1] = NULL;
- StringPtr = NULL;
- Status = EFI_SUCCESS;
- ZeroMem (Value, sizeof (Value));
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- for (Index = 0; Index < 2; Index++) {
- if ((Value[Index].Type != EFI_IFR_TYPE_STRING) && !IsTypeInBuffer (&Value[Index])) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- if (Value[Index].Type == EFI_IFR_TYPE_STRING) {
- String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
- if (String[Index] == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
- }
-
- if (Value[0].Type == EFI_IFR_TYPE_STRING) {
- Size = StrSize (String[0]);
- MaxLen = (StrSize (String[1]) + Size) / sizeof (CHAR16);
- StringPtr = AllocatePool (MaxLen * sizeof (CHAR16));
- ASSERT (StringPtr != NULL);
- StrCpyS (StringPtr, MaxLen, String[1]);
- StrCatS (StringPtr, MaxLen, String[0]);
-
- Result->Type = EFI_IFR_TYPE_STRING;
- Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
- } else {
- Result->Type = EFI_IFR_TYPE_BUFFER;
- Length0 = GetLengthForValue (&Value[0]);
- Length1 = GetLengthForValue (&Value[1]);
- Result->BufferLen = (UINT16)(Length0 + Length1);
-
- Result->Buffer = AllocateZeroPool (Result->BufferLen);
- ASSERT (Result->Buffer != NULL);
-
- TmpBuf = GetBufferForValue (&Value[0]);
- ASSERT (TmpBuf != NULL);
- CopyMem (Result->Buffer, TmpBuf, Length0);
- TmpBuf = GetBufferForValue (&Value[1]);
- ASSERT (TmpBuf != NULL);
- CopyMem (&Result->Buffer[Length0], TmpBuf, Length1);
- }
-
-Done:
- if (Value[0].Buffer != NULL) {
- FreePool (Value[0].Buffer);
- }
-
- if (Value[1].Buffer != NULL) {
- FreePool (Value[1].Buffer);
- }
-
- if (String[0] != NULL) {
- FreePool (String[0]);
- }
-
- if (String[1] != NULL) {
- FreePool (String[1]);
- }
-
- if (StringPtr != NULL) {
- FreePool (StringPtr);
- }
-
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_MATCH.
-
- @param FormSet Formset which contains this opcode.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrMatch (
- IN FORM_BROWSER_FORMSET *FormSet,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[2];
- CHAR16 *String[2];
- UINTN Index;
-
- //
- // String[0] - The string to search
- // String[1] - pattern
- //
- String[0] = NULL;
- String[1] = NULL;
- Status = EFI_SUCCESS;
- ZeroMem (Value, sizeof (Value));
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- for (Index = 0; Index < 2; Index++) {
- if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
- if (String[Index] == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
-
- Result->Type = EFI_IFR_TYPE_BOOLEAN;
- Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
-
-Done:
- if (String[0] != NULL) {
- FreePool (String[0]);
- }
-
- if (String[1] != NULL) {
- FreePool (String[1]);
- }
-
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_MATCH2.
-
- @param FormSet Formset which contains this opcode.
- @param SyntaxType Syntax type for match2.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrMatch2 (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN EFI_GUID *SyntaxType,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[2];
- CHAR16 *String[2];
- UINTN Index;
- UINTN GuidIndex;
- EFI_HANDLE *HandleBuffer;
- UINTN BufferSize;
- EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol;
- UINTN RegExSyntaxTypeListSize;
- EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList;
- UINTN CapturesCount;
-
- //
- // String[0] - The string to search
- // String[1] - pattern
- //
- String[0] = NULL;
- String[1] = NULL;
- HandleBuffer = NULL;
- RegExSyntaxTypeList = NULL;
- Status = EFI_SUCCESS;
- ZeroMem (Value, sizeof (Value));
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- for (Index = 0; Index < 2; Index++) {
- if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
- if (String[Index] == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
-
- BufferSize = 0;
- HandleBuffer = NULL;
- Status = gBS->LocateHandle (
- ByProtocol,
- &gEfiRegularExpressionProtocolGuid,
- NULL,
- &BufferSize,
- HandleBuffer
- );
- if (Status == EFI_BUFFER_TOO_SMALL) {
- HandleBuffer = AllocateZeroPool (BufferSize);
- if (HandleBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- Status = gBS->LocateHandle (
- ByProtocol,
- &gEfiRegularExpressionProtocolGuid,
- NULL,
- &BufferSize,
- HandleBuffer
- );
- }
-
- if (EFI_ERROR (Status)) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- ASSERT (HandleBuffer != NULL);
- for ( Index = 0; Index < BufferSize / sizeof (EFI_HANDLE); Index++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiRegularExpressionProtocolGuid,
- (VOID **)&RegularExpressionProtocol
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- RegExSyntaxTypeListSize = 0;
- RegExSyntaxTypeList = NULL;
-
- Status = RegularExpressionProtocol->GetInfo (
- RegularExpressionProtocol,
- &RegExSyntaxTypeListSize,
- RegExSyntaxTypeList
- );
- if (Status == EFI_BUFFER_TOO_SMALL) {
- RegExSyntaxTypeList = AllocateZeroPool (RegExSyntaxTypeListSize);
- if (RegExSyntaxTypeList == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- Status = RegularExpressionProtocol->GetInfo (
- RegularExpressionProtocol,
- &RegExSyntaxTypeListSize,
- RegExSyntaxTypeList
- );
- } else if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- for (GuidIndex = 0; GuidIndex < RegExSyntaxTypeListSize / sizeof (EFI_GUID); GuidIndex++) {
- if (CompareGuid (&RegExSyntaxTypeList[GuidIndex], SyntaxType)) {
- //
- // Find the match type, return the value.
- //
- Result->Type = EFI_IFR_TYPE_BOOLEAN;
- Status = RegularExpressionProtocol->MatchString (
- RegularExpressionProtocol,
- String[0],
- String[1],
- SyntaxType,
- &Result->Value.b,
- NULL,
- &CapturesCount
- );
- goto Done;
- }
- }
-
- if (RegExSyntaxTypeList != NULL) {
- FreePool (RegExSyntaxTypeList);
- }
- }
-
- //
- // Type specified by SyntaxType is not supported
- // in any of the EFI_REGULAR_EXPRESSION_PROTOCOL instances.
- //
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
-
-Done:
- if (String[0] != NULL) {
- FreePool (String[0]);
- }
-
- if (String[1] != NULL) {
- FreePool (String[1]);
- }
-
- if (RegExSyntaxTypeList != NULL) {
- FreePool (RegExSyntaxTypeList);
- }
-
- if (HandleBuffer != NULL) {
- FreePool (HandleBuffer);
- }
-
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_FIND.
-
- @param FormSet Formset which contains this opcode.
- @param Format Case sensitive or insensitive.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrFind (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN UINT8 Format,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[3];
- CHAR16 *String[2];
- UINTN Base;
- CHAR16 *StringPtr;
- UINTN Index;
-
- ZeroMem (Value, sizeof (Value));
-
- if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[2]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Base = (UINTN)Value[0].Value.u64;
-
- //
- // String[0] - sub-string
- // String[1] - The string to search
- //
- String[0] = NULL;
- String[1] = NULL;
- for (Index = 0; Index < 2; Index++) {
- if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
- if (String[Index] == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
- //
- // Case insensitive, convert both string to upper case
- //
- IfrStrToUpper (String[Index]);
- }
- }
-
- Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- if (Base >= StrLen (String[1])) {
- Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
- } else {
- StringPtr = StrStr (String[1] + Base, String[0]);
- Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
- }
-
-Done:
- if (String[0] != NULL) {
- FreePool (String[0]);
- }
-
- if (String[1] != NULL) {
- FreePool (String[1]);
- }
-
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_MID.
-
- @param FormSet Formset which contains this opcode.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrMid (
- IN FORM_BROWSER_FORMSET *FormSet,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[3];
- CHAR16 *String;
- UINTN Base;
- UINTN Length;
- CHAR16 *SubString;
- UINT16 BufferLen;
- UINT8 *Buffer;
-
- ZeroMem (Value, sizeof (Value));
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[2]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Length = (UINTN)Value[0].Value.u64;
-
- if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Base = (UINTN)Value[1].Value.u64;
-
- if ((Value[2].Type != EFI_IFR_TYPE_STRING) && !IsTypeInBuffer (&Value[2])) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- if (Value[2].Type == EFI_IFR_TYPE_STRING) {
- String = GetToken (Value[2].Value.string, FormSet->HiiHandle);
- if (String == NULL) {
- return EFI_NOT_FOUND;
- }
-
- if ((Length == 0) || (Base >= StrLen (String))) {
- SubString = gEmptyString;
- } else {
- SubString = String + Base;
- if ((Base + Length) < StrLen (String)) {
- SubString[Length] = L'\0';
- }
- }
-
- Result->Type = EFI_IFR_TYPE_STRING;
- Result->Value.string = NewString (SubString, FormSet->HiiHandle);
-
- FreePool (String);
- } else {
- BufferLen = GetLengthForValue (&Value[2]);
- Buffer = GetBufferForValue (&Value[2]);
-
- Result->Type = EFI_IFR_TYPE_BUFFER;
- if ((Length == 0) || (Base >= BufferLen)) {
- Result->BufferLen = 0;
- Result->Buffer = NULL;
- } else {
- Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length);
- Result->Buffer = AllocateZeroPool (Result->BufferLen);
- ASSERT (Result->Buffer != NULL);
- CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen);
- }
-
- if (Value[2].Type == EFI_IFR_TYPE_BUFFER) {
- FreePool (Value[2].Buffer);
- }
- }
-
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_TOKEN.
-
- @param FormSet Formset which contains this opcode.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrToken (
- IN FORM_BROWSER_FORMSET *FormSet,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[3];
- CHAR16 *String[2];
- UINTN Count;
- CHAR16 *Delimiter;
- CHAR16 *SubString;
- CHAR16 *StringPtr;
- UINTN Index;
-
- ZeroMem (Value, sizeof (Value));
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[2]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Count = (UINTN)Value[0].Value.u64;
-
- //
- // String[0] - Delimiter
- // String[1] - The string to search
- //
- String[0] = NULL;
- String[1] = NULL;
- for (Index = 0; Index < 2; Index++) {
- if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
- if (String[Index] == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
-
- Delimiter = String[0];
- SubString = String[1];
- while (Count > 0) {
- SubString = StrStr (SubString, Delimiter);
- if (SubString != NULL) {
- //
- // Skip over the delimiter
- //
- SubString = SubString + StrLen (Delimiter);
- } else {
- break;
- }
-
- Count--;
- }
-
- if (SubString == NULL) {
- //
- // nth delimited sub-string not found, push an empty string
- //
- SubString = gEmptyString;
- } else {
- //
- // Put a NULL terminator for nth delimited sub-string
- //
- StringPtr = StrStr (SubString, Delimiter);
- if (StringPtr != NULL) {
- *StringPtr = L'\0';
- }
- }
-
- Result->Type = EFI_IFR_TYPE_STRING;
- Result->Value.string = NewString (SubString, FormSet->HiiHandle);
-
-Done:
- if (String[0] != NULL) {
- FreePool (String[0]);
- }
-
- if (String[1] != NULL) {
- FreePool (String[1]);
- }
-
- return Status;
-}
-
-/**
- Evaluate opcode EFI_IFR_SPAN.
-
- @param FormSet Formset which contains this opcode.
- @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
- @param Result Evaluation result for this opcode.
-
- @retval EFI_SUCCESS Opcode evaluation success.
- @retval Other Opcode evaluation failed.
-
-**/
-EFI_STATUS
-IfrSpan (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN UINT8 Flags,
- OUT EFI_HII_VALUE *Result
- )
-{
- EFI_STATUS Status;
- EFI_HII_VALUE Value[3];
- CHAR16 *String[2];
- CHAR16 *Charset;
- UINTN Base;
- UINTN Index;
- CHAR16 *StringPtr;
- BOOLEAN Found;
-
- ZeroMem (Value, sizeof (Value));
-
- Status = PopExpression (&Value[0]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[1]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = PopExpression (&Value[2]);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- return EFI_SUCCESS;
- }
-
- Base = (UINTN)Value[0].Value.u64;
-
- //
- // String[0] - Charset
- // String[1] - The string to search
- //
- String[0] = NULL;
- String[1] = NULL;
- for (Index = 0; Index < 2; Index++) {
- if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
- if (String[Index] == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
-
- if (Base >= StrLen (String[1])) {
- Result->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- Found = FALSE;
- StringPtr = String[1] + Base;
- Charset = String[0];
- while (*StringPtr != 0 && !Found) {
- Index = 0;
- while (Charset[Index] != 0) {
- if ((*StringPtr >= Charset[Index]) && (*StringPtr <= Charset[Index + 1])) {
- if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
- Found = TRUE;
- break;
- }
- } else {
- if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
- Found = TRUE;
- break;
- }
- }
-
- //
- // Skip characters pair representing low-end of a range and high-end of a range
- //
- Index += 2;
- }
-
- if (!Found) {
- StringPtr++;
- }
- }
-
- Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- Result->Value.u64 = StringPtr - String[1];
-
-Done:
- if (String[0] != NULL) {
- FreePool (String[0]);
- }
-
- if (String[1] != NULL) {
- FreePool (String[1]);
- }
-
- return Status;
-}
-
-/**
- Zero extend integer/boolean/date/time to UINT64 for comparing.
-
- @param Value HII Value to be converted.
-
-**/
-VOID
-ExtendValueToU64 (
- IN EFI_HII_VALUE *Value
- )
-{
- UINT64 Temp;
-
- Temp = 0;
- switch (Value->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- Temp = Value->Value.u8;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- Temp = Value->Value.u16;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- Temp = Value->Value.u32;
- break;
-
- case EFI_IFR_TYPE_BOOLEAN:
- Temp = Value->Value.b;
- break;
-
- case EFI_IFR_TYPE_TIME:
- Temp = Value->Value.u32 & 0xffffff;
- break;
-
- case EFI_IFR_TYPE_DATE:
- Temp = Value->Value.u32;
- break;
-
- default:
- return;
- }
-
- Value->Value.u64 = Temp;
-}
-
-/**
- Get UINT64 type value.
-
- @param Value Input Hii value.
-
- @retval UINT64 Return the UINT64 type value.
-
-**/
-UINT64
-HiiValueToUINT64 (
- IN EFI_HII_VALUE *Value
- )
-{
- UINT64 RetVal;
-
- RetVal = 0;
-
- switch (Value->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- RetVal = Value->Value.u8;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- RetVal = Value->Value.u16;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- RetVal = Value->Value.u32;
- break;
-
- case EFI_IFR_TYPE_BOOLEAN:
- RetVal = Value->Value.b;
- break;
-
- case EFI_IFR_TYPE_DATE:
- RetVal = *(UINT64 *)&Value->Value.date;
- break;
-
- case EFI_IFR_TYPE_TIME:
- RetVal = (*(UINT64 *)&Value->Value.time) & 0xffffff;
- break;
-
- default:
- RetVal = Value->Value.u64;
- break;
- }
-
- return RetVal;
-}
-
-/**
- Compare two Hii value.
-
- @param Value1 Expression value to compare on left-hand.
- @param Value2 Expression value to compare on right-hand.
- @param Result Return value after compare.
- retval 0 Two operators equal.
- return Positive value if Value1 is greater than Value2.
- retval Negative value if Value1 is less than Value2.
- @param HiiHandle Only required for string compare.
-
- @retval other Could not perform compare on two values.
- @retval EFI_SUCCESS Compare the value success.
-
-**/
-EFI_STATUS
-CompareHiiValue (
- IN EFI_HII_VALUE *Value1,
- IN EFI_HII_VALUE *Value2,
- OUT INTN *Result,
- IN EFI_HII_HANDLE HiiHandle OPTIONAL
- )
-{
- INT64 Temp64;
- CHAR16 *Str1;
- CHAR16 *Str2;
- UINTN Len;
- UINT8 *Buf1;
- UINT16 Buf1Len;
- UINT8 *Buf2;
- UINT16 Buf2Len;
-
- if ((Value1->Type == EFI_IFR_TYPE_STRING) && (Value2->Type == EFI_IFR_TYPE_STRING)) {
- if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) {
- //
- // StringId 0 is reserved
- //
- return EFI_INVALID_PARAMETER;
- }
-
- if (Value1->Value.string == Value2->Value.string) {
- *Result = 0;
- return EFI_SUCCESS;
- }
-
- Str1 = GetToken (Value1->Value.string, HiiHandle);
- if (Str1 == NULL) {
- //
- // String not found
- //
- return EFI_NOT_FOUND;
- }
-
- Str2 = GetToken (Value2->Value.string, HiiHandle);
- if (Str2 == NULL) {
- FreePool (Str1);
- return EFI_NOT_FOUND;
- }
-
- *Result = StrCmp (Str1, Str2);
-
- FreePool (Str1);
- FreePool (Str2);
-
- return EFI_SUCCESS;
- }
-
- //
- // Take types(date, time, ref, buffer) as buffer
- //
- if (IsTypeInBuffer (Value1) && IsTypeInBuffer (Value2)) {
- Buf1 = GetBufferForValue (Value1);
- Buf1Len = GetLengthForValue (Value1);
- Buf2 = GetBufferForValue (Value2);
- Buf2Len = GetLengthForValue (Value2);
-
- Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
- *Result = CompareMem (Buf1, Buf2, Len);
- if ((*Result == 0) && (Buf1Len != Buf2Len)) {
- //
- // In this case, means base on samll number buffer, the data is same
- // So which value has more data, which value is bigger.
- //
- *Result = Buf1Len > Buf2Len ? 1 : -1;
- }
-
- return EFI_SUCCESS;
- }
-
- //
- // Take types(integer, boolean) as integer
- //
- if (IsTypeInUINT64 (Value1) && IsTypeInUINT64 (Value2)) {
- Temp64 = HiiValueToUINT64 (Value1) - HiiValueToUINT64 (Value2);
- if (Temp64 > 0) {
- *Result = 1;
- } else if (Temp64 < 0) {
- *Result = -1;
- } else {
- *Result = 0;
- }
-
- return EFI_SUCCESS;
- }
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- Check if current user has the privilege specified by the permissions GUID.
-
- @param[in] Guid A GUID specifying setup access permissions.
-
- @retval TRUE Current user has the privilege.
- @retval FALSE Current user does not have the privilege.
-**/
-BOOLEAN
-CheckUserPrivilege (
- IN EFI_GUID *Guid
- )
-{
- EFI_STATUS Status;
- EFI_USER_PROFILE_HANDLE UserProfileHandle;
- EFI_USER_INFO_HANDLE UserInfoHandle;
- EFI_USER_INFO *UserInfo;
- EFI_GUID *UserPermissionsGuid;
- UINTN UserInfoSize;
- UINTN AccessControlDataSize;
- EFI_USER_INFO_ACCESS_CONTROL *AccessControl;
- UINTN RemainSize;
-
- if (mUserManager == NULL) {
- Status = gBS->LocateProtocol (
- &gEfiUserManagerProtocolGuid,
- NULL,
- (VOID **)&mUserManager
- );
- if (EFI_ERROR (Status)) {
- ///
- /// If the system does not support user management, then it is assumed that
- /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
- /// op-code is always TRUE.
- ///
- return TRUE;
- }
- }
-
- Status = mUserManager->Current (mUserManager, &UserProfileHandle);
- ASSERT_EFI_ERROR (Status);
-
- ///
- /// Enumerate all user information of the current user profile
- /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
- ///
-
- for (UserInfoHandle = NULL; ;) {
- Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- UserInfoSize = 0;
- Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);
- if (Status != EFI_BUFFER_TOO_SMALL) {
- continue;
- }
-
- UserInfo = (EFI_USER_INFO *)AllocatePool (UserInfoSize);
- if (UserInfo == NULL) {
- break;
- }
-
- Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);
- if (EFI_ERROR (Status) ||
- (UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) ||
- (UserInfo->InfoSize <= sizeof (EFI_USER_INFO)))
- {
- FreePool (UserInfo);
- continue;
- }
-
- RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);
- AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);
- while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
- if ((RemainSize < AccessControl->Size) || (AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL))) {
- break;
- }
-
- if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {
- ///
- /// Check if current user has the privilege specified by the permissions GUID.
- ///
-
- UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);
- AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
- while (AccessControlDataSize >= sizeof (EFI_GUID)) {
- if (CompareGuid (Guid, UserPermissionsGuid)) {
- FreePool (UserInfo);
- return TRUE;
- }
-
- UserPermissionsGuid++;
- AccessControlDataSize -= sizeof (EFI_GUID);
- }
- }
-
- RemainSize -= AccessControl->Size;
- AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);
- }
-
- FreePool (UserInfo);
- }
-
- return FALSE;
-}
-
-/**
- Get question value from the predefined formset.
-
- @param DevicePath The driver's device path which produece the formset data.
- @param InputHiiHandle The hii handle associate with the formset data.
- @param FormSetGuid The formset guid which include the question.
- @param QuestionId The question id which need to get value from.
- @param Value The return data about question's value.
-
- @retval TRUE Get the question value success.
- @retval FALSE Get the question value failed.
-**/
-BOOLEAN
-GetQuestionValueFromForm (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- IN EFI_HII_HANDLE InputHiiHandle,
- IN EFI_GUID *FormSetGuid,
- IN EFI_QUESTION_ID QuestionId,
- OUT EFI_HII_VALUE *Value
- )
-{
- EFI_STATUS Status;
- EFI_HII_HANDLE HiiHandle;
- FORM_BROWSER_STATEMENT *Question;
- FORM_BROWSER_FORMSET *FormSet;
- FORM_BROWSER_FORM *Form;
- BOOLEAN GetTheVal;
- LIST_ENTRY *Link;
-
- //
- // The input parameter DevicePath or InputHiiHandle must have one valid input.
- //
- ASSERT (
- (DevicePath != NULL && InputHiiHandle == NULL) ||
- (DevicePath == NULL && InputHiiHandle != NULL)
- );
-
- GetTheVal = TRUE;
- HiiHandle = NULL;
- Question = NULL;
- Form = NULL;
-
- //
- // Get HiiHandle.
- //
- if (DevicePath != NULL) {
- HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid);
- if (HiiHandle == NULL) {
- return FALSE;
- }
- } else {
- HiiHandle = InputHiiHandle;
- }
-
- ASSERT (HiiHandle != NULL);
-
- //
- // Get the formset data include this question.
- //
- FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
- ASSERT (FormSet != NULL);
- Status = InitializeFormSet (HiiHandle, FormSetGuid, FormSet);
- if (EFI_ERROR (Status)) {
- GetTheVal = FALSE;
- goto Done;
- }
-
- //
- // Base on the Question Id to get the question info.
- //
- Question = IdToQuestion (FormSet, NULL, QuestionId);
- if (Question == NULL) {
- GetTheVal = FALSE;
- goto Done;
- }
-
- //
- // Search form in the formset scope
- //
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- Question = IdToQuestion2 (Form, QuestionId);
- if (Question != NULL) {
- break;
- }
-
- Link = GetNextNode (&FormSet->FormListHead, Link);
- Form = NULL;
- }
-
- ASSERT (Form != NULL);
-
- //
- // Get the question value.
- //
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
- if (EFI_ERROR (Status)) {
- GetTheVal = FALSE;
- goto Done;
- }
-
- CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE));
-
-Done:
- //
- // Clean the formset structure and restore the global parameter.
- //
- if (FormSet != NULL) {
- DestroyFormSet (FormSet);
- }
-
- return GetTheVal;
-}
-
-/**
- Evaluate the result of a HII expression.
-
- If Expression is NULL, then ASSERT.
-
- @param FormSet FormSet associated with this expression.
- @param Form Form associated with this expression.
- @param Expression Expression to be evaluated.
-
- @retval EFI_SUCCESS The expression evaluated successfuly
- @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
- could not be found.
- @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
- stack.
- @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
- @retval EFI_INVALID_PARAMETER Syntax error with the Expression
-
-**/
-EFI_STATUS
-EvaluateExpression (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_EXPRESSION *Expression
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EXPRESSION_OPCODE *OpCode;
- FORM_BROWSER_STATEMENT *Question;
- FORM_BROWSER_STATEMENT *Question2;
- UINT16 Index;
- EFI_HII_VALUE Data1;
- EFI_HII_VALUE Data2;
- EFI_HII_VALUE Data3;
- FORM_EXPRESSION *RuleExpression;
- EFI_HII_VALUE *Value;
- INTN Result;
- CHAR16 *StrPtr;
- CHAR16 *NameValue;
- UINT32 TempValue;
- LIST_ENTRY *SubExpressionLink;
- FORM_EXPRESSION *SubExpression;
- UINTN StackOffset;
- UINTN TempLength;
- CHAR16 TempStr[5];
- UINT8 DigitUint8;
- UINT8 *TempBuffer;
- EFI_TIME EfiTime;
- EFI_HII_VALUE QuestionVal;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
-
- StrPtr = NULL;
-
- //
- // Save current stack offset.
- //
- StackOffset = SaveExpressionEvaluationStackOffset ();
-
- ASSERT (Expression != NULL);
- Expression->Result.Type = EFI_IFR_TYPE_OTHER;
-
- Link = GetFirstNode (&Expression->OpCodeListHead);
- while (!IsNull (&Expression->OpCodeListHead, Link)) {
- OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
-
- Link = GetNextNode (&Expression->OpCodeListHead, Link);
-
- ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
- ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
- ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
-
- Value = &Data3;
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- Status = EFI_SUCCESS;
-
- switch (OpCode->Operand) {
- //
- // Built-in functions
- //
- case EFI_IFR_EQ_ID_VAL_OP:
- Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
- if (Question == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL);
- if (Status == EFI_UNSUPPORTED) {
- Status = EFI_SUCCESS;
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Value->Value.b = (BOOLEAN)((Result == 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_EQ_ID_ID_OP:
- Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
- if (Question == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
- if (Question2 == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle);
- if (Status == EFI_UNSUPPORTED) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- break;
- }
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Value->Value.b = (BOOLEAN)((Result == 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_EQ_ID_VAL_LIST_OP:
- Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
- if (Question == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value->Value.b = FALSE;
- for (Index = 0; Index < OpCode->ListLength; Index++) {
- if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
- Value->Value.b = TRUE;
- break;
- }
- }
-
- break;
-
- case EFI_IFR_DUP_OP:
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = PushExpression (Value);
- break;
-
- case EFI_IFR_QUESTION_REF1_OP:
- case EFI_IFR_THIS_OP:
- Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
- if (Question == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- Value = &Question->HiiValue;
- break;
-
- case EFI_IFR_SECURITY_OP:
- Value->Value.b = CheckUserPrivilege (&OpCode->Guid);
- break;
-
- case EFI_IFR_GET_OP:
- //
- // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
- //
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- Value->Value.u8 = 0;
- if (OpCode->VarStorage != NULL) {
- switch (OpCode->VarStorage->Type) {
- case EFI_HII_VARSTORE_BUFFER:
- case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
- //
- // Get value from Edit Buffer
- //
- Value->Type = OpCode->ValueType;
- CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
- break;
- case EFI_HII_VARSTORE_NAME_VALUE:
- if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
- //
- // Get value from string except for STRING value.
- //
- Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr, GetSetValueWithEditBuffer);
- if (!EFI_ERROR (Status)) {
- ASSERT (StrPtr != NULL);
- TempLength = StrLen (StrPtr);
- if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
- Value->Type = OpCode->ValueType;
- TempBuffer = (UINT8 *)&Value->Value;
- ZeroMem (TempStr, sizeof (TempStr));
- for (Index = 0; Index < TempLength; Index++) {
- TempStr[0] = StrPtr[TempLength - Index - 1];
- DigitUint8 = (UINT8)StrHexToUint64 (TempStr);
- if ((Index & 1) == 0) {
- TempBuffer[Index/2] = DigitUint8;
- } else {
- TempBuffer[Index/2] = (UINT8)((DigitUint8 << 4) + TempBuffer[Index/2]);
- }
- }
- }
- }
- }
-
- break;
- case EFI_HII_VARSTORE_EFI_VARIABLE:
- //
- // Get value from variable.
- //
- TempLength = OpCode->ValueWidth;
- Value->Type = OpCode->ValueType;
- Status = gRT->GetVariable (
- OpCode->ValueName,
- &OpCode->VarStorage->Guid,
- NULL,
- &TempLength,
- &Value->Value
- );
- if (EFI_ERROR (Status)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- Value->Value.u8 = 0;
- }
-
- break;
- default:
- //
- // Not recognize storage.
- //
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
- } else {
- //
- // For Time/Date Data
- //
- if ((OpCode->ValueType != EFI_IFR_TYPE_DATE) && (OpCode->ValueType != EFI_IFR_TYPE_TIME)) {
- //
- // Only support Data/Time data when storage doesn't exist.
- //
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
-
- Status = gRT->GetTime (&EfiTime, NULL);
- if (!EFI_ERROR (Status)) {
- if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
- switch (OpCode->VarStoreInfo.VarOffset) {
- case 0x00:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
- Value->Value.u16 = EfiTime.Year;
- break;
- case 0x02:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = EfiTime.Month;
- break;
- case 0x03:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = EfiTime.Day;
- break;
- default:
- //
- // Invalid Date field.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- } else {
- switch (OpCode->VarStoreInfo.VarOffset) {
- case 0x00:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = EfiTime.Hour;
- break;
- case 0x01:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = EfiTime.Minute;
- break;
- case 0x02:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = EfiTime.Second;
- break;
- default:
- //
- // Invalid Time field.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
- }
- }
-
- break;
-
- case EFI_IFR_QUESTION_REF3_OP:
- //
- // EFI_IFR_QUESTION_REF3
- // Pop an expression from the expression stack
- //
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Validate the expression value
- //
- if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (OpCode->DevicePath != 0) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
-
- StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle);
- if ((StrPtr != NULL) && (mPathFromText != NULL)) {
- DevicePath = mPathFromText->ConvertTextToDevicePath (StrPtr);
- if ((DevicePath != NULL) && GetQuestionValueFromForm (DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) {
- Value = &QuestionVal;
- }
-
- if (DevicePath != NULL) {
- FreePool (DevicePath);
- }
- }
-
- if (StrPtr != NULL) {
- FreePool (StrPtr);
- }
- } else if (IsZeroGuid (&OpCode->Guid)) {
- if (!GetQuestionValueFromForm (NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value = &QuestionVal;
- } else {
- Question = IdToQuestion (FormSet, Form, Value->Value.u16);
- if (Question == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- //
- // push the questions' value on to the expression stack
- //
- Value = &Question->HiiValue;
- }
-
- break;
-
- case EFI_IFR_RULE_REF_OP:
- //
- // Find expression for this rule
- //
- RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
- if (RuleExpression == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- //
- // Evaluate this rule expression
- //
- Status = EvaluateExpression (FormSet, Form, RuleExpression);
- if (EFI_ERROR (Status) || (RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value = &RuleExpression->Result;
- break;
-
- case EFI_IFR_STRING_REF1_OP:
- Value->Type = EFI_IFR_TYPE_STRING;
- Value->Value.string = OpCode->Value.Value.string;
- break;
-
- //
- // Constant
- //
- case EFI_IFR_TRUE_OP:
- case EFI_IFR_FALSE_OP:
- case EFI_IFR_ONE_OP:
- case EFI_IFR_ONES_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:
- Value = &OpCode->Value;
- break;
-
- //
- // unary-op
- //
- case EFI_IFR_LENGTH_OP:
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if ((Value->Type != EFI_IFR_TYPE_STRING) && !IsTypeInBuffer (Value)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (Value->Type == EFI_IFR_TYPE_STRING) {
- StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
- if (StrPtr == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- Value->Value.u64 = StrLen (StrPtr);
- FreePool (StrPtr);
- } else {
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- Value->Value.u64 = GetLengthForValue (Value);
- FreePool (Value->Buffer);
- }
-
- break;
-
- case EFI_IFR_NOT_OP:
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value->Value.b = (BOOLEAN)(!Value->Value.b);
- break;
-
- case EFI_IFR_QUESTION_REF2_OP:
- //
- // Pop an expression from the expression stack
- //
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Validate the expression value
- //
- if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Question = IdToQuestion (FormSet, Form, Value->Value.u16);
- if (Question == NULL) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value = &Question->HiiValue;
- break;
-
- case EFI_IFR_STRING_REF2_OP:
- //
- // Pop an expression from the expression stack
- //
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Validate the expression value
- //
- if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value->Type = EFI_IFR_TYPE_STRING;
- StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
- if (StrPtr == NULL) {
- //
- // If String not exit, push an empty string
- //
- Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
- } else {
- Index = (UINT16)Value->Value.u64;
- Value->Value.string = Index;
- FreePool (StrPtr);
- }
-
- break;
-
- case EFI_IFR_TO_BOOLEAN_OP:
- //
- // Pop an expression from the expression stack
- //
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Convert an expression to a Boolean
- //
- if (Value->Type <= EFI_IFR_TYPE_DATE) {
- //
- // When converting from an unsigned integer, zero will be converted to
- // FALSE and any other value will be converted to TRUE.
- //
- Value->Value.b = (BOOLEAN)(HiiValueToUINT64 (Value) != 0);
-
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- } else if (Value->Type == EFI_IFR_TYPE_STRING) {
- //
- // When converting from a string, if case-insensitive compare
- // with "true" is True, then push True. If a case-insensitive compare
- // with "false" is True, then push False. Otherwise, push Undefined.
- //
- StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
- if (StrPtr == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- IfrStrToUpper (StrPtr);
- if (StrCmp (StrPtr, L"TRUE") == 0) {
- Value->Value.b = TRUE;
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- } else if (StrCmp (StrPtr, L"FALSE") == 0) {
- Value->Value.b = FALSE;
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- } else {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- }
-
- FreePool (StrPtr);
- } else if (Value->Type == EFI_IFR_TYPE_BUFFER) {
- //
- // When converting from a buffer, if the buffer is all zeroes,
- // then push False. Otherwise push True.
- //
- for (Index = 0; Index < Value->BufferLen; Index++) {
- if (Value->Buffer[Index] != 0) {
- break;
- }
- }
-
- if (Index >= Value->BufferLen) {
- Value->Value.b = FALSE;
- } else {
- Value->Value.b = TRUE;
- }
-
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- FreePool (Value->Buffer);
- }
-
- break;
-
- case EFI_IFR_TO_STRING_OP:
- Status = IfrToString (FormSet, OpCode->Format, Value);
- break;
-
- case EFI_IFR_TO_UINT_OP:
- Status = IfrToUint (FormSet, Value);
- break;
-
- case EFI_IFR_TO_LOWER_OP:
- case EFI_IFR_TO_UPPER_OP:
- Status = InitializeUnicodeCollationProtocol ();
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Value->Type != EFI_IFR_TYPE_STRING) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
- if (StrPtr == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
- mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
- } else {
- mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
- }
-
- Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
- FreePool (StrPtr);
- break;
-
- case EFI_IFR_BITWISE_NOT_OP:
- //
- // Pop an expression from the expression stack
- //
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Value->Type > EFI_IFR_TYPE_DATE) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- Value->Value.u64 = ~HiiValueToUINT64(Value);
- break;
-
- case EFI_IFR_SET_OP:
- //
- // Pop an expression from the expression stack
- //
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Data1.Type = EFI_IFR_TYPE_BOOLEAN;
- Data1.Value.b = FALSE;
- //
- // Set value to var storage buffer
- //
- if (OpCode->VarStorage != NULL) {
- switch (OpCode->VarStorage->Type) {
- case EFI_HII_VARSTORE_BUFFER:
- case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
- CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
- Data1.Value.b = TRUE;
- break;
- case EFI_HII_VARSTORE_NAME_VALUE:
- if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
- NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));
- ASSERT (NameValue != NULL);
- //
- // Convert Buffer to Hex String
- //
- TempBuffer = (UINT8 *)&Value->Value + OpCode->ValueWidth - 1;
- StrPtr = NameValue;
- for (Index = 0; Index < OpCode->ValueWidth; Index++, TempBuffer--) {
- UnicodeValueToStringS (
- StrPtr,
- (OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16) - ((UINTN)StrPtr - (UINTN)NameValue),
- PREFIX_ZERO | RADIX_HEX,
- *TempBuffer,
- 2
- );
- StrPtr += StrnLenS (StrPtr, OpCode->ValueWidth * 2 + 1 - ((UINTN)StrPtr - (UINTN)NameValue) / sizeof (CHAR16));
- }
-
- Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);
- FreePool (NameValue);
- if (!EFI_ERROR (Status)) {
- Data1.Value.b = TRUE;
- }
- }
-
- break;
- case EFI_HII_VARSTORE_EFI_VARIABLE:
- Status = gRT->SetVariable (
- OpCode->ValueName,
- &OpCode->VarStorage->Guid,
- OpCode->VarStorage->Attributes,
- OpCode->ValueWidth,
- &Value->Value
- );
- if (!EFI_ERROR (Status)) {
- Data1.Value.b = TRUE;
- }
-
- break;
- default:
- //
- // Not recognize storage.
- //
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
- } else {
- //
- // For Time/Date Data
- //
- if ((OpCode->ValueType != EFI_IFR_TYPE_DATE) && (OpCode->ValueType != EFI_IFR_TYPE_TIME)) {
- //
- // Only support Data/Time data when storage doesn't exist.
- //
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
-
- Status = gRT->GetTime (&EfiTime, NULL);
- if (!EFI_ERROR (Status)) {
- if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
- switch (OpCode->VarStoreInfo.VarOffset) {
- case 0x00:
- EfiTime.Year = Value->Value.u16;
- break;
- case 0x02:
- EfiTime.Month = Value->Value.u8;
- break;
- case 0x03:
- EfiTime.Day = Value->Value.u8;
- break;
- default:
- //
- // Invalid Date field.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- } else {
- switch (OpCode->VarStoreInfo.VarOffset) {
- case 0x00:
- EfiTime.Hour = Value->Value.u8;
- break;
- case 0x01:
- EfiTime.Minute = Value->Value.u8;
- break;
- case 0x02:
- EfiTime.Second = Value->Value.u8;
- break;
- default:
- //
- // Invalid Time field.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- Status = gRT->SetTime (&EfiTime);
- if (!EFI_ERROR (Status)) {
- Data1.Value.b = TRUE;
- }
- }
- }
-
- Value = &Data1;
- break;
-
- //
- // binary-op
- //
- case EFI_IFR_ADD_OP:
- case EFI_IFR_SUBTRACT_OP:
- case EFI_IFR_MULTIPLY_OP:
- case EFI_IFR_DIVIDE_OP:
- case EFI_IFR_MODULO_OP:
- case EFI_IFR_BITWISE_AND_OP:
- case EFI_IFR_BITWISE_OR_OP:
- case EFI_IFR_SHIFT_LEFT_OP:
- case EFI_IFR_SHIFT_RIGHT_OP:
- //
- // Pop an expression from the expression stack
- //
- Status = PopExpression (&Data2);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Pop another expression from the expression stack
- //
- Status = PopExpression (&Data1);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Data2.Type > EFI_IFR_TYPE_DATE) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (Data1.Type > EFI_IFR_TYPE_DATE) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
-
- switch (OpCode->Operand) {
- case EFI_IFR_ADD_OP:
- Value->Value.u64 = HiiValueToUINT64 (&Data1) + HiiValueToUINT64 (&Data2);
- break;
-
- case EFI_IFR_SUBTRACT_OP:
- Value->Value.u64 = HiiValueToUINT64 (&Data1) - HiiValueToUINT64 (&Data2);
- break;
-
- case EFI_IFR_MULTIPLY_OP:
- Value->Value.u64 = MultU64x32 (HiiValueToUINT64 (&Data1), (UINT32)HiiValueToUINT64 (&Data2));
- break;
-
- case EFI_IFR_DIVIDE_OP:
- Value->Value.u64 = DivU64x32 (HiiValueToUINT64 (&Data1), (UINT32)HiiValueToUINT64 (&Data2));
- break;
-
- case EFI_IFR_MODULO_OP:
- DivU64x32Remainder (HiiValueToUINT64 (&Data1), (UINT32)HiiValueToUINT64 (&Data2), &TempValue);
- Value->Value.u64 = TempValue;
- break;
-
- case EFI_IFR_BITWISE_AND_OP:
- Value->Value.u64 = HiiValueToUINT64 (&Data1) & HiiValueToUINT64 (&Data2);
- break;
-
- case EFI_IFR_BITWISE_OR_OP:
- Value->Value.u64 = HiiValueToUINT64 (&Data1) | HiiValueToUINT64 (&Data2);
- break;
-
- case EFI_IFR_SHIFT_LEFT_OP:
- Value->Value.u64 = LShiftU64 (HiiValueToUINT64 (&Data1), (UINTN)HiiValueToUINT64 (&Data2));
- break;
-
- case EFI_IFR_SHIFT_RIGHT_OP:
- Value->Value.u64 = RShiftU64 (HiiValueToUINT64 (&Data1), (UINTN)HiiValueToUINT64 (&Data2));
- break;
-
- default:
- break;
- }
-
- break;
-
- case EFI_IFR_AND_OP:
- case EFI_IFR_OR_OP:
- //
- // Two Boolean operator
- //
- Status = PopExpression (&Data2);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Pop another expression from the expression stack
- //
- Status = PopExpression (&Data1);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (OpCode->Operand == EFI_IFR_AND_OP) {
- Value->Value.b = (BOOLEAN)(Data1.Value.b && Data2.Value.b);
- } else {
- Value->Value.b = (BOOLEAN)(Data1.Value.b || Data2.Value.b);
- }
-
- break;
-
- case EFI_IFR_EQUAL_OP:
- case EFI_IFR_NOT_EQUAL_OP:
- case EFI_IFR_GREATER_EQUAL_OP:
- case EFI_IFR_GREATER_THAN_OP:
- case EFI_IFR_LESS_EQUAL_OP:
- case EFI_IFR_LESS_THAN_OP:
- //
- // Compare two integer, string, boolean or date/time
- //
- Status = PopExpression (&Data2);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Pop another expression from the expression stack
- //
- Status = PopExpression (&Data1);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) &&
- (Data2.Type != EFI_IFR_TYPE_STRING) &&
- !IsTypeInBuffer (&Data2))
- {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if ((Data1.Type > EFI_IFR_TYPE_BOOLEAN) &&
- (Data1.Type != EFI_IFR_TYPE_STRING) &&
- !IsTypeInBuffer (&Data1))
- {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle);
- if (Data1.Type == EFI_IFR_TYPE_BUFFER) {
- FreePool (Data1.Buffer);
- }
-
- if (Data2.Type == EFI_IFR_TYPE_BUFFER) {
- FreePool (Data2.Buffer);
- }
-
- if (Status == EFI_UNSUPPORTED) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- Status = EFI_SUCCESS;
- break;
- }
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- switch (OpCode->Operand) {
- case EFI_IFR_EQUAL_OP:
- Value->Value.b = (BOOLEAN)((Result == 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_NOT_EQUAL_OP:
- Value->Value.b = (BOOLEAN)((Result != 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_GREATER_EQUAL_OP:
- Value->Value.b = (BOOLEAN)((Result >= 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_GREATER_THAN_OP:
- Value->Value.b = (BOOLEAN)((Result > 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_LESS_EQUAL_OP:
- Value->Value.b = (BOOLEAN)((Result <= 0) ? TRUE : FALSE);
- break;
-
- case EFI_IFR_LESS_THAN_OP:
- Value->Value.b = (BOOLEAN)((Result < 0) ? TRUE : FALSE);
- break;
-
- default:
- break;
- }
-
- break;
-
- case EFI_IFR_MATCH_OP:
- Status = InitializeUnicodeCollationProtocol ();
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = IfrMatch (FormSet, Value);
- break;
-
- case EFI_IFR_MATCH2_OP:
- Status = IfrMatch2 (FormSet, &OpCode->Guid, Value);
- break;
-
- case EFI_IFR_CATENATE_OP:
- Status = IfrCatenate (FormSet, Value);
- break;
-
- //
- // ternary-op
- //
- case EFI_IFR_CONDITIONAL_OP:
- //
- // Pop third expression from the expression stack
- //
- Status = PopExpression (&Data3);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Pop second expression from the expression stack
- //
- Status = PopExpression (&Data2);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Pop first expression from the expression stack
- //
- Status = PopExpression (&Data1);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
- }
-
- if (Data1.Value.b) {
- Value = &Data3;
- } else {
- Value = &Data2;
- }
-
- break;
-
- case EFI_IFR_FIND_OP:
- Status = IfrFind (FormSet, OpCode->Format, Value);
- break;
-
- case EFI_IFR_MID_OP:
- Status = IfrMid (FormSet, Value);
- break;
-
- case EFI_IFR_TOKEN_OP:
- Status = IfrToken (FormSet, Value);
- break;
-
- case EFI_IFR_SPAN_OP:
- Status = IfrSpan (FormSet, OpCode->Flags, Value);
- break;
-
- case EFI_IFR_MAP_OP:
- //
- // Pop the check value
- //
- Status = PopExpression (&Data1);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Check MapExpression list is valid.
- //
- if (OpCode->MapExpressionList.ForwardLink == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Go through map expression list.
- //
- SubExpressionLink = GetFirstNode (&OpCode->MapExpressionList);
- while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
- SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
- //
- // Evaluate the first expression in this pair.
- //
- Status = EvaluateExpression (FormSet, Form, SubExpression);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Compare the expression value with current value
- //
- if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
- //
- // Try get the map value.
- //
- SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
- if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
- Status = EvaluateExpression (FormSet, Form, SubExpression);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Value = &SubExpression->Result;
- break;
- }
-
- //
- // Skip the second expression on this pair.
- //
- SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
- if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Goto the first expression on next pair.
- //
- SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
- }
-
- //
- // No map value is found.
- //
- if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- Value->Value.u8 = 0;
- }
-
- break;
-
- default:
- break;
- }
-
- if (EFI_ERROR (Status) || (Value->Type == EFI_IFR_TYPE_UNDEFINED)) {
- goto Done;
- }
-
- Status = PushExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
-
- //
- // Pop the final result from expression stack
- //
- Value = &Data1;
- Status = PopExpression (Value);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // After evaluating an expression, there should be only one value left on the expression stack
- //
- if (PopExpression (Value) != EFI_ACCESS_DENIED) {
- Status = EFI_INVALID_PARAMETER;
- }
-
-Done:
- RestoreExpressionEvaluationStackOffset (StackOffset);
- if (!EFI_ERROR (Status)) {
- CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
- }
-
- return Status;
-}
-
-/**
- Check whether the result is TRUE or FALSE.
-
- For the EFI_HII_VALUE value type is numeric, return TRUE if the
- value is not 0.
-
- @param Result Input the result data.
-
- @retval TRUE The result is TRUE.
- @retval FALSE The result is FALSE.
-
-**/
-BOOLEAN
-IsTrue (
- IN EFI_HII_VALUE *Result
- )
-{
- switch (Result->Type) {
- case EFI_IFR_TYPE_BOOLEAN:
- return Result->Value.b;
-
- case EFI_IFR_TYPE_NUM_SIZE_8:
- return (BOOLEAN)(Result->Value.u8 != 0);
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- return (BOOLEAN)(Result->Value.u16 != 0);
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- return (BOOLEAN)(Result->Value.u32 != 0);
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- return (BOOLEAN)(Result->Value.u64 != 0);
-
- default:
- return FALSE;
- }
-}
-
-/**
- Return the result of the expression list. Check the expression list and
- return the highest priority express result.
- Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
-
- @param ExpList The input expression list.
- @param Evaluate Whether need to evaluate the expression first.
- @param FormSet FormSet associated with this expression.
- @param Form Form associated with this expression.
-
- @retval EXPRESS_RESULT Return the higher priority express result.
- DisableIf > SuppressIf > GrayOutIf > FALSE
-
-**/
-EXPRESS_RESULT
-EvaluateExpressionList (
- IN FORM_EXPRESSION_LIST *ExpList,
- IN BOOLEAN Evaluate,
- IN FORM_BROWSER_FORMSET *FormSet OPTIONAL,
- IN FORM_BROWSER_FORM *Form OPTIONAL
- )
-{
- UINTN Index;
- EXPRESS_RESULT ReturnVal;
- EXPRESS_RESULT CompareOne;
- EFI_STATUS Status;
-
- if (ExpList == NULL) {
- return ExpressFalse;
- }
-
- ASSERT (ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE);
- Index = 0;
-
- //
- // Check whether need to evaluate the expression first.
- //
- if (Evaluate) {
- while (ExpList->Count > Index) {
- Status = EvaluateExpression (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 (IsTrue (&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;
-}
+/** @file +Utility functions for expression evaluation. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Setup.h" + +// +// Global stack used to evaluate boolean expresions +// +EFI_HII_VALUE *mOpCodeScopeStack = NULL; +EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL; +EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL; + +EFI_HII_VALUE *mExpressionEvaluationStack = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL; +UINTN mExpressionEvaluationStackOffset = 0; + +EFI_HII_VALUE *mCurrentExpressionStack = NULL; +EFI_HII_VALUE *mCurrentExpressionEnd = NULL; +EFI_HII_VALUE *mCurrentExpressionPointer = NULL; + +EFI_HII_VALUE *mMapExpressionListStack = NULL; +EFI_HII_VALUE *mMapExpressionListEnd = NULL; +EFI_HII_VALUE *mMapExpressionListPointer = NULL; + +FORM_EXPRESSION **mFormExpressionStack = NULL; +FORM_EXPRESSION **mFormExpressionEnd = NULL; +FORM_EXPRESSION **mFormExpressionPointer = NULL; + +FORM_EXPRESSION **mStatementExpressionStack = NULL; +FORM_EXPRESSION **mStatementExpressionEnd = NULL; +FORM_EXPRESSION **mStatementExpressionPointer = NULL; + +FORM_EXPRESSION **mOptionExpressionStack = NULL; +FORM_EXPRESSION **mOptionExpressionEnd = NULL; +FORM_EXPRESSION **mOptionExpressionPointer = NULL; + +// +// Unicode collation protocol interface +// +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; +EFI_USER_MANAGER_PROTOCOL *mUserManager = 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); + ASSERT ((*StackPtr)->Buffer != NULL); + } + + *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 FORM_EXPRESSION ***Stack, + IN OUT FORM_EXPRESSION ***StackPtr, + IN OUT FORM_EXPRESSION ***StackEnd, + IN UINTN MemberSize + ) +{ + UINTN Size; + FORM_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 FORM_EXPRESSION ***Stack, + IN OUT FORM_EXPRESSION ***StackPtr, + IN OUT FORM_EXPRESSION ***StackEnd, + IN FORM_EXPRESSION **Data + ) +{ + EFI_STATUS Status; + + // + // Check for a stack overflow condition + // + if (*StackPtr >= *StackEnd) { + // + // Grow the stack + // + Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (FORM_EXPRESSION *)); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + CopyMem (*StackPtr, Data, sizeof (FORM_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 FORM_EXPRESSION **Stack, + IN OUT FORM_EXPRESSION ***StackPtr, + OUT FORM_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 (FORM_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. + +**/ +FORM_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 FORM_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 + ) +{ + FORM_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; +} + +/** + Push an Expression value onto the Stack + + @param Value Expression value 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 +PushExpression ( + IN EFI_HII_VALUE *Value + ) +{ + return PushStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + +/** + Pop an Expression value from the stack. + + @param Value Expression value to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopExpression ( + OUT EFI_HII_VALUE *Value + ) +{ + return PopStack ( + mExpressionEvaluationStack + mExpressionEvaluationStackOffset, + &mExpressionEvaluationStackPointer, + Value + ); +} + +/** + Get current stack offset from stack start. + + @return Stack offset to stack start. +**/ +UINTN +SaveExpressionEvaluationStackOffset ( + VOID + ) +{ + UINTN TempStackOffset; + + TempStackOffset = mExpressionEvaluationStackOffset; + mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack; + return TempStackOffset; +} + +/** + Restore stack offset based on input stack offset + + @param StackOffset Offset to stack start. + +**/ +VOID +RestoreExpressionEvaluationStackOffset ( + UINTN StackOffset + ) +{ + mExpressionEvaluationStackOffset = StackOffset; +} + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + if (Form->FormId == FormId) { + return Form; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + +/** + Search a Question in Form scope using its QuestionId. + + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion2 ( + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + if ((QuestionId == 0) || (Form == NULL)) { + // + // The value of zero is reserved + // + return NULL; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Question->QuestionId == QuestionId) { + return Question; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return NULL; +} + +/** + Search a Question in Formset scope using its QuestionId. + + @param FormSet The formset which contains this form. + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + // + // Search in the form scope first + // + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + // + // Search in the formset scope + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + // + // EFI variable storage may be updated by Callback() asynchronous, + // to keep synchronous, always reload the Question Value. + // + if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); + } + + return Question; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + +/** + Get Expression given its RuleId. + + @param Form The form which contains this Expression. + @param RuleId Id of this Expression. + + @retval Pointer The Expression. + @retval NULL Specified Expression not found in the form. + +**/ +FORM_EXPRESSION * +RuleIdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + if ((Expression->Type == EFI_HII_EXPRESSION_RULE) && (Expression->RuleId == RuleId)) { + return Expression; + } + + Link = GetNextNode (&Form->ExpressionListHead, Link); + } + + return NULL; +} + +/** + Locate the Unicode Collation Protocol interface for later use. + + @retval EFI_SUCCESS Protocol interface initialize success. + @retval Other Protocol interface initialize failed. + +**/ +EFI_STATUS +InitializeUnicodeCollationProtocol ( + VOID + ) +{ + EFI_STATUS Status; + + if (mUnicodeCollation != NULL) { + return EFI_SUCCESS; + } + + // + // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol + // instances first and then select one which support English language. + // Current implementation just pick the first instance. + // + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **)&mUnicodeCollation + ); + return Status; +} + +/** + Convert the input Unicode character to upper. + + @param String Th Unicode character to be converted. + +**/ +VOID +IfrStrToUpper ( + IN CHAR16 *String + ) +{ + while (*String != 0) { + if ((*String >= 'a') && (*String <= 'z')) { + *String = (UINT16)((*String) & ((UINT16) ~0x20)); + } + + String++; + } +} + +/** + Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type. + + EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to + EFI_IFR_TYPE_BUFFER when do the value compare. + + @param Value Expression value to compare on. + + @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. + @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. + +**/ +BOOLEAN +IsTypeInBuffer ( + IN EFI_HII_VALUE *Value + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_BUFFER: + case EFI_IFR_TYPE_DATE: + case EFI_IFR_TYPE_TIME: + case EFI_IFR_TYPE_REF: + return TRUE; + + default: + return FALSE; + } +} + +/** + Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64 + + @param Value Expression value to compare on. + + @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. + @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. + +**/ +BOOLEAN +IsTypeInUINT64 ( + IN EFI_HII_VALUE *Value + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_NUM_SIZE_32: + case EFI_IFR_TYPE_NUM_SIZE_64: + case EFI_IFR_TYPE_BOOLEAN: + return TRUE; + + default: + return FALSE; + } +} + +/** + Return the buffer length for this value. + + EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to + EFI_IFR_TYPE_BUFFER when do the value compare. + + @param Value Expression value to compare on. + + @retval BufLen Return the buffer length. + +**/ +UINT16 +GetLengthForValue ( + IN EFI_HII_VALUE *Value + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_BUFFER: + return Value->BufferLen; + + case EFI_IFR_TYPE_DATE: + return (UINT16)sizeof (EFI_HII_DATE); + + case EFI_IFR_TYPE_TIME: + return (UINT16)sizeof (EFI_HII_TIME); + + case EFI_IFR_TYPE_REF: + return (UINT16)sizeof (EFI_HII_REF); + + default: + return 0; + } +} + +/** + Return the buffer pointer for this value. + + EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to + EFI_IFR_TYPE_BUFFER when do the value compare. + + @param Value Expression value to compare on. + + @retval Buf Return the buffer pointer. + +**/ +UINT8 * +GetBufferForValue ( + IN EFI_HII_VALUE *Value + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_BUFFER: + return Value->Buffer; + + case EFI_IFR_TYPE_DATE: + return (UINT8 *)(&Value->Value.date); + + case EFI_IFR_TYPE_TIME: + return (UINT8 *)(&Value->Value.time); + + case EFI_IFR_TYPE_REF: + return (UINT8 *)(&Value->Value.ref); + + default: + return NULL; + } +} + +/** + Evaluate opcode EFI_IFR_TO_STRING. + + @param FormSet Formset which contains this opcode. + @param Format String format in EFI_IFR_TO_STRING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToString ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *PrintFormat; + CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS]; + UINT8 *TmpBuf; + UINT8 *SrcBuf; + UINTN SrcLen; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + switch (Value.Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_NUM_SIZE_32: + case EFI_IFR_TYPE_NUM_SIZE_64: + BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16); + switch (Format) { + case EFI_IFR_STRING_UNSIGNED_DEC: + case EFI_IFR_STRING_SIGNED_DEC: + PrintFormat = L"%ld"; + break; + + case EFI_IFR_STRING_LOWERCASE_HEX: + PrintFormat = L"%lx"; + break; + + case EFI_IFR_STRING_UPPERCASE_HEX: + PrintFormat = L"%lX"; + break; + + default: + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64); + String = Buffer; + break; + + case EFI_IFR_TYPE_STRING: + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; + + case EFI_IFR_TYPE_BOOLEAN: + String = (Value.Value.b) ? L"True" : L"False"; + break; + + case EFI_IFR_TYPE_BUFFER: + case EFI_IFR_TYPE_DATE: + case EFI_IFR_TYPE_TIME: + case EFI_IFR_TYPE_REF: + // + // + 3 is base on the unicode format, the length may be odd number, + // so need 1 byte to align, also need 2 bytes for L'\0'. + // + if (Value.Type == EFI_IFR_TYPE_BUFFER) { + SrcLen = Value.BufferLen; + SrcBuf = Value.Buffer; + } else { + SrcBuf = GetBufferForValue (&Value); + SrcLen = GetLengthForValue (&Value); + } + + TmpBuf = AllocateZeroPool (SrcLen + 3); + ASSERT (TmpBuf != NULL); + if (Format == EFI_IFR_STRING_ASCII) { + CopyMem (TmpBuf, SrcBuf, SrcLen); + PrintFormat = L"%a"; + } else { + // Format == EFI_IFR_STRING_UNICODE + CopyMem (TmpBuf, SrcBuf, SrcLen * sizeof (CHAR16)); + PrintFormat = L"%s"; + } + + UnicodeSPrint (Buffer, sizeof (Buffer), PrintFormat, TmpBuf); + String = Buffer; + FreePool (TmpBuf); + if (Value.Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Value.Buffer); + } + + break; + + default: + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (String, FormSet->HiiHandle); + return EFI_SUCCESS; +} + +/** + Evaluate opcode EFI_IFR_TO_UINT. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToUint ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *StringPtr; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Value.Type >= EFI_IFR_TYPE_OTHER) && !IsTypeInBuffer (&Value)) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + if (Value.Type == EFI_IFR_TYPE_STRING) { + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + IfrStrToUpper (String); + StringPtr = StrStr (String, L"0X"); + if (StringPtr != NULL) { + // + // Hex string + // + Result->Value.u64 = StrHexToUint64 (String); + } else { + // + // decimal string + // + Result->Value.u64 = StrDecimalToUint64 (String); + } + + FreePool (String); + } else if (IsTypeInBuffer (&Value)) { + if (GetLengthForValue (&Value) > 8) { + if (Value.Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Value.Buffer); + } + + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + ASSERT (GetBufferForValue (&Value) != NULL); + Result->Value.u64 = *(UINT64 *)GetBufferForValue (&Value); + + if (Value.Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Value.Buffer); + } + } else { + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + return Status; +} + +/** + Evaluate opcode EFI_IFR_CATENATE. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrCatenate ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[2]; + CHAR16 *String[2]; + UINTN Index; + CHAR16 *StringPtr; + UINTN Size; + UINT16 Length0; + UINT16 Length1; + UINT8 *TmpBuf; + UINTN MaxLen; + + // + // String[0] - The second string + // String[1] - The first string + // + String[0] = NULL; + String[1] = NULL; + StringPtr = NULL; + Status = EFI_SUCCESS; + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + goto Done; + } + + for (Index = 0; Index < 2; Index++) { + if ((Value[Index].Type != EFI_IFR_TYPE_STRING) && !IsTypeInBuffer (&Value[Index])) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + if (Value[Index].Type == EFI_IFR_TYPE_STRING) { + String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); + if (String[Index] == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + } + + if (Value[0].Type == EFI_IFR_TYPE_STRING) { + Size = StrSize (String[0]); + MaxLen = (StrSize (String[1]) + Size) / sizeof (CHAR16); + StringPtr = AllocatePool (MaxLen * sizeof (CHAR16)); + ASSERT (StringPtr != NULL); + StrCpyS (StringPtr, MaxLen, String[1]); + StrCatS (StringPtr, MaxLen, String[0]); + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); + } else { + Result->Type = EFI_IFR_TYPE_BUFFER; + Length0 = GetLengthForValue (&Value[0]); + Length1 = GetLengthForValue (&Value[1]); + Result->BufferLen = (UINT16)(Length0 + Length1); + + Result->Buffer = AllocateZeroPool (Result->BufferLen); + ASSERT (Result->Buffer != NULL); + + TmpBuf = GetBufferForValue (&Value[0]); + ASSERT (TmpBuf != NULL); + CopyMem (Result->Buffer, TmpBuf, Length0); + TmpBuf = GetBufferForValue (&Value[1]); + ASSERT (TmpBuf != NULL); + CopyMem (&Result->Buffer[Length0], TmpBuf, Length1); + } + +Done: + if (Value[0].Buffer != NULL) { + FreePool (Value[0].Buffer); + } + + if (Value[1].Buffer != NULL) { + FreePool (Value[1].Buffer); + } + + if (String[0] != NULL) { + FreePool (String[0]); + } + + if (String[1] != NULL) { + FreePool (String[1]); + } + + if (StringPtr != NULL) { + FreePool (StringPtr); + } + + return Status; +} + +/** + Evaluate opcode EFI_IFR_MATCH. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMatch ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[2]; + CHAR16 *String[2]; + UINTN Index; + + // + // String[0] - The string to search + // String[1] - pattern + // + String[0] = NULL; + String[1] = NULL; + Status = EFI_SUCCESS; + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + goto Done; + } + + for (Index = 0; Index < 2; Index++) { + if (Value[Index].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); + if (String[Index] == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Result->Type = EFI_IFR_TYPE_BOOLEAN; + Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); + +Done: + if (String[0] != NULL) { + FreePool (String[0]); + } + + if (String[1] != NULL) { + FreePool (String[1]); + } + + return Status; +} + +/** + Evaluate opcode EFI_IFR_MATCH2. + + @param FormSet Formset which contains this opcode. + @param SyntaxType Syntax type for match2. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMatch2 ( + IN FORM_BROWSER_FORMSET *FormSet, + IN EFI_GUID *SyntaxType, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[2]; + CHAR16 *String[2]; + UINTN Index; + UINTN GuidIndex; + EFI_HANDLE *HandleBuffer; + UINTN BufferSize; + EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol; + UINTN RegExSyntaxTypeListSize; + EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList; + UINTN CapturesCount; + + // + // String[0] - The string to search + // String[1] - pattern + // + String[0] = NULL; + String[1] = NULL; + HandleBuffer = NULL; + RegExSyntaxTypeList = NULL; + Status = EFI_SUCCESS; + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + goto Done; + } + + for (Index = 0; Index < 2; Index++) { + if (Value[Index].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); + if (String[Index] == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + BufferSize = 0; + HandleBuffer = NULL; + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiRegularExpressionProtocolGuid, + NULL, + &BufferSize, + HandleBuffer + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuffer = AllocateZeroPool (BufferSize); + if (HandleBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiRegularExpressionProtocolGuid, + NULL, + &BufferSize, + HandleBuffer + ); + } + + if (EFI_ERROR (Status)) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + ASSERT (HandleBuffer != NULL); + for ( Index = 0; Index < BufferSize / sizeof (EFI_HANDLE); Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiRegularExpressionProtocolGuid, + (VOID **)&RegularExpressionProtocol + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + RegExSyntaxTypeListSize = 0; + RegExSyntaxTypeList = NULL; + + Status = RegularExpressionProtocol->GetInfo ( + RegularExpressionProtocol, + &RegExSyntaxTypeListSize, + RegExSyntaxTypeList + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + RegExSyntaxTypeList = AllocateZeroPool (RegExSyntaxTypeListSize); + if (RegExSyntaxTypeList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = RegularExpressionProtocol->GetInfo ( + RegularExpressionProtocol, + &RegExSyntaxTypeListSize, + RegExSyntaxTypeList + ); + } else if (EFI_ERROR (Status)) { + goto Done; + } + + for (GuidIndex = 0; GuidIndex < RegExSyntaxTypeListSize / sizeof (EFI_GUID); GuidIndex++) { + if (CompareGuid (&RegExSyntaxTypeList[GuidIndex], SyntaxType)) { + // + // Find the match type, return the value. + // + Result->Type = EFI_IFR_TYPE_BOOLEAN; + Status = RegularExpressionProtocol->MatchString ( + RegularExpressionProtocol, + String[0], + String[1], + SyntaxType, + &Result->Value.b, + NULL, + &CapturesCount + ); + goto Done; + } + } + + if (RegExSyntaxTypeList != NULL) { + FreePool (RegExSyntaxTypeList); + } + } + + // + // Type specified by SyntaxType is not supported + // in any of the EFI_REGULAR_EXPRESSION_PROTOCOL instances. + // + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + +Done: + if (String[0] != NULL) { + FreePool (String[0]); + } + + if (String[1] != NULL) { + FreePool (String[1]); + } + + if (RegExSyntaxTypeList != NULL) { + FreePool (RegExSyntaxTypeList); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return Status; +} + +/** + Evaluate opcode EFI_IFR_FIND. + + @param FormSet Formset which contains this opcode. + @param Format Case sensitive or insensitive. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrFind ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[3]; + CHAR16 *String[2]; + UINTN Base; + CHAR16 *StringPtr; + UINTN Index; + + ZeroMem (Value, sizeof (Value)); + + if (Format > EFI_IFR_FF_CASE_INSENSITIVE) { + return EFI_INVALID_PARAMETER; + } + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[2]); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Base = (UINTN)Value[0].Value.u64; + + // + // String[0] - sub-string + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); + if (String[Index] == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + if (Format == EFI_IFR_FF_CASE_INSENSITIVE) { + // + // Case insensitive, convert both string to upper case + // + IfrStrToUpper (String[Index]); + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + if (Base >= StrLen (String[1])) { + Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL; + } else { + StringPtr = StrStr (String[1] + Base, String[0]); + Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]); + } + +Done: + if (String[0] != NULL) { + FreePool (String[0]); + } + + if (String[1] != NULL) { + FreePool (String[1]); + } + + return Status; +} + +/** + Evaluate opcode EFI_IFR_MID. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMid ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[3]; + CHAR16 *String; + UINTN Base; + UINTN Length; + CHAR16 *SubString; + UINT16 BufferLen; + UINT8 *Buffer; + + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[2]); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Length = (UINTN)Value[0].Value.u64; + + if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Base = (UINTN)Value[1].Value.u64; + + if ((Value[2].Type != EFI_IFR_TYPE_STRING) && !IsTypeInBuffer (&Value[2])) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + if (Value[2].Type == EFI_IFR_TYPE_STRING) { + String = GetToken (Value[2].Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + if ((Length == 0) || (Base >= StrLen (String))) { + SubString = gEmptyString; + } else { + SubString = String + Base; + if ((Base + Length) < StrLen (String)) { + SubString[Length] = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + + FreePool (String); + } else { + BufferLen = GetLengthForValue (&Value[2]); + Buffer = GetBufferForValue (&Value[2]); + + Result->Type = EFI_IFR_TYPE_BUFFER; + if ((Length == 0) || (Base >= BufferLen)) { + Result->BufferLen = 0; + Result->Buffer = NULL; + } else { + Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length); + Result->Buffer = AllocateZeroPool (Result->BufferLen); + ASSERT (Result->Buffer != NULL); + CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen); + } + + if (Value[2].Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Value[2].Buffer); + } + } + + return Status; +} + +/** + Evaluate opcode EFI_IFR_TOKEN. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToken ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[3]; + CHAR16 *String[2]; + UINTN Count; + CHAR16 *Delimiter; + CHAR16 *SubString; + CHAR16 *StringPtr; + UINTN Index; + + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[2]); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Count = (UINTN)Value[0].Value.u64; + + // + // String[0] - Delimiter + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); + if (String[Index] == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Delimiter = String[0]; + SubString = String[1]; + while (Count > 0) { + SubString = StrStr (SubString, Delimiter); + if (SubString != NULL) { + // + // Skip over the delimiter + // + SubString = SubString + StrLen (Delimiter); + } else { + break; + } + + Count--; + } + + if (SubString == NULL) { + // + // nth delimited sub-string not found, push an empty string + // + SubString = gEmptyString; + } else { + // + // Put a NULL terminator for nth delimited sub-string + // + StringPtr = StrStr (SubString, Delimiter); + if (StringPtr != NULL) { + *StringPtr = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + +Done: + if (String[0] != NULL) { + FreePool (String[0]); + } + + if (String[1] != NULL) { + FreePool (String[1]); + } + + return Status; +} + +/** + Evaluate opcode EFI_IFR_SPAN. + + @param FormSet Formset which contains this opcode. + @param Flags FIRST_MATCHING or FIRST_NON_MATCHING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrSpan ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Flags, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value[3]; + CHAR16 *String[2]; + CHAR16 *Charset; + UINTN Base; + UINTN Index; + CHAR16 *StringPtr; + BOOLEAN Found; + + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[2]); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; + } + + Base = (UINTN)Value[0].Value.u64; + + // + // String[0] - Charset + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); + if (String[Index] == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + if (Base >= StrLen (String[1])) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + goto Done; + } + + Found = FALSE; + StringPtr = String[1] + Base; + Charset = String[0]; + while (*StringPtr != 0 && !Found) { + Index = 0; + while (Charset[Index] != 0) { + if ((*StringPtr >= Charset[Index]) && (*StringPtr <= Charset[Index + 1])) { + if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) { + Found = TRUE; + break; + } + } else { + if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) { + Found = TRUE; + break; + } + } + + // + // Skip characters pair representing low-end of a range and high-end of a range + // + Index += 2; + } + + if (!Found) { + StringPtr++; + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Result->Value.u64 = StringPtr - String[1]; + +Done: + if (String[0] != NULL) { + FreePool (String[0]); + } + + if (String[1] != NULL) { + FreePool (String[1]); + } + + return Status; +} + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +{ + UINT64 Temp; + + Temp = 0; + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Temp = Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Temp = Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Temp = Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + Temp = Value->Value.b; + break; + + case EFI_IFR_TYPE_TIME: + Temp = Value->Value.u32 & 0xffffff; + break; + + case EFI_IFR_TYPE_DATE: + Temp = Value->Value.u32; + break; + + default: + return; + } + + Value->Value.u64 = Temp; +} + +/** + Get UINT64 type value. + + @param Value Input Hii value. + + @retval UINT64 Return the UINT64 type value. + +**/ +UINT64 +HiiValueToUINT64 ( + IN EFI_HII_VALUE *Value + ) +{ + UINT64 RetVal; + + RetVal = 0; + + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + RetVal = Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + RetVal = Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + RetVal = Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + RetVal = Value->Value.b; + break; + + case EFI_IFR_TYPE_DATE: + RetVal = *(UINT64 *)&Value->Value.date; + break; + + case EFI_IFR_TYPE_TIME: + RetVal = (*(UINT64 *)&Value->Value.time) & 0xffffff; + break; + + default: + RetVal = Value->Value.u64; + break; + } + + return RetVal; +} + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +{ + INT64 Temp64; + CHAR16 *Str1; + CHAR16 *Str2; + UINTN Len; + UINT8 *Buf1; + UINT16 Buf1Len; + UINT8 *Buf2; + UINT16 Buf2Len; + + if ((Value1->Type == EFI_IFR_TYPE_STRING) && (Value2->Type == EFI_IFR_TYPE_STRING)) { + if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == Value2->Value.string) { + *Result = 0; + return EFI_SUCCESS; + } + + Str1 = GetToken (Value1->Value.string, HiiHandle); + if (Str1 == NULL) { + // + // String not found + // + return EFI_NOT_FOUND; + } + + Str2 = GetToken (Value2->Value.string, HiiHandle); + if (Str2 == NULL) { + FreePool (Str1); + return EFI_NOT_FOUND; + } + + *Result = StrCmp (Str1, Str2); + + FreePool (Str1); + FreePool (Str2); + + return EFI_SUCCESS; + } + + // + // Take types(date, time, ref, buffer) as buffer + // + if (IsTypeInBuffer (Value1) && IsTypeInBuffer (Value2)) { + Buf1 = GetBufferForValue (Value1); + Buf1Len = GetLengthForValue (Value1); + Buf2 = GetBufferForValue (Value2); + Buf2Len = GetLengthForValue (Value2); + + Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len; + *Result = CompareMem (Buf1, Buf2, Len); + if ((*Result == 0) && (Buf1Len != Buf2Len)) { + // + // In this case, means base on samll number buffer, the data is same + // So which value has more data, which value is bigger. + // + *Result = Buf1Len > Buf2Len ? 1 : -1; + } + + return EFI_SUCCESS; + } + + // + // Take types(integer, boolean) as integer + // + if (IsTypeInUINT64 (Value1) && IsTypeInUINT64 (Value2)) { + Temp64 = HiiValueToUINT64 (Value1) - HiiValueToUINT64 (Value2); + if (Temp64 > 0) { + *Result = 1; + } else if (Temp64 < 0) { + *Result = -1; + } else { + *Result = 0; + } + + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +/** + Check if current user has the privilege specified by the permissions GUID. + + @param[in] Guid A GUID specifying setup access permissions. + + @retval TRUE Current user has the privilege. + @retval FALSE Current user does not have the privilege. +**/ +BOOLEAN +CheckUserPrivilege ( + IN EFI_GUID *Guid + ) +{ + EFI_STATUS Status; + EFI_USER_PROFILE_HANDLE UserProfileHandle; + EFI_USER_INFO_HANDLE UserInfoHandle; + EFI_USER_INFO *UserInfo; + EFI_GUID *UserPermissionsGuid; + UINTN UserInfoSize; + UINTN AccessControlDataSize; + EFI_USER_INFO_ACCESS_CONTROL *AccessControl; + UINTN RemainSize; + + if (mUserManager == NULL) { + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **)&mUserManager + ); + if (EFI_ERROR (Status)) { + /// + /// If the system does not support user management, then it is assumed that + /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY + /// op-code is always TRUE. + /// + return TRUE; + } + } + + Status = mUserManager->Current (mUserManager, &UserProfileHandle); + ASSERT_EFI_ERROR (Status); + + /// + /// Enumerate all user information of the current user profile + /// to look for any EFI_USER_INFO_ACCESS_SETUP record. + /// + + for (UserInfoHandle = NULL; ;) { + Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle); + if (EFI_ERROR (Status)) { + break; + } + + UserInfoSize = 0; + Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + UserInfo = (EFI_USER_INFO *)AllocatePool (UserInfoSize); + if (UserInfo == NULL) { + break; + } + + Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize); + if (EFI_ERROR (Status) || + (UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) || + (UserInfo->InfoSize <= sizeof (EFI_USER_INFO))) + { + FreePool (UserInfo); + continue; + } + + RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO); + AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1); + while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) { + if ((RemainSize < AccessControl->Size) || (AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL))) { + break; + } + + if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) { + /// + /// Check if current user has the privilege specified by the permissions GUID. + /// + + UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1); + AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL); + while (AccessControlDataSize >= sizeof (EFI_GUID)) { + if (CompareGuid (Guid, UserPermissionsGuid)) { + FreePool (UserInfo); + return TRUE; + } + + UserPermissionsGuid++; + AccessControlDataSize -= sizeof (EFI_GUID); + } + } + + RemainSize -= AccessControl->Size; + AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size); + } + + FreePool (UserInfo); + } + + return FALSE; +} + +/** + Get question value from the predefined formset. + + @param DevicePath The driver's device path which produece the formset data. + @param InputHiiHandle The hii handle associate with the formset data. + @param FormSetGuid The formset guid which include the question. + @param QuestionId The question id which need to get value from. + @param Value The return data about question's value. + + @retval TRUE Get the question value success. + @retval FALSE Get the question value failed. +**/ +BOOLEAN +GetQuestionValueFromForm ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_HII_HANDLE InputHiiHandle, + IN EFI_GUID *FormSetGuid, + IN EFI_QUESTION_ID QuestionId, + OUT EFI_HII_VALUE *Value + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + FORM_BROWSER_STATEMENT *Question; + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + BOOLEAN GetTheVal; + LIST_ENTRY *Link; + + // + // The input parameter DevicePath or InputHiiHandle must have one valid input. + // + ASSERT ( + (DevicePath != NULL && InputHiiHandle == NULL) || + (DevicePath == NULL && InputHiiHandle != NULL) + ); + + GetTheVal = TRUE; + HiiHandle = NULL; + Question = NULL; + Form = NULL; + + // + // Get HiiHandle. + // + if (DevicePath != NULL) { + HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid); + if (HiiHandle == NULL) { + return FALSE; + } + } else { + HiiHandle = InputHiiHandle; + } + + ASSERT (HiiHandle != NULL); + + // + // Get the formset data include this question. + // + FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (FormSet != NULL); + Status = InitializeFormSet (HiiHandle, FormSetGuid, FormSet); + if (EFI_ERROR (Status)) { + GetTheVal = FALSE; + goto Done; + } + + // + // Base on the Question Id to get the question info. + // + Question = IdToQuestion (FormSet, NULL, QuestionId); + if (Question == NULL) { + GetTheVal = FALSE; + goto Done; + } + + // + // Search form in the formset scope + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + break; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + Form = NULL; + } + + ASSERT (Form != NULL); + + // + // Get the question value. + // + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + if (EFI_ERROR (Status)) { + GetTheVal = FALSE; + goto Done; + } + + CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE)); + +Done: + // + // Clean the formset structure and restore the global parameter. + // + if (FormSet != NULL) { + DestroyFormSet (FormSet); + } + + return GetTheVal; +} + +/** + Evaluate the result of a HII expression. + + If Expression is NULL, then ASSERT. + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EXPRESSION_OPCODE *OpCode; + FORM_BROWSER_STATEMENT *Question; + FORM_BROWSER_STATEMENT *Question2; + UINT16 Index; + EFI_HII_VALUE Data1; + EFI_HII_VALUE Data2; + EFI_HII_VALUE Data3; + FORM_EXPRESSION *RuleExpression; + EFI_HII_VALUE *Value; + INTN Result; + CHAR16 *StrPtr; + CHAR16 *NameValue; + UINT32 TempValue; + LIST_ENTRY *SubExpressionLink; + FORM_EXPRESSION *SubExpression; + UINTN StackOffset; + UINTN TempLength; + CHAR16 TempStr[5]; + UINT8 DigitUint8; + UINT8 *TempBuffer; + EFI_TIME EfiTime; + EFI_HII_VALUE QuestionVal; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + StrPtr = NULL; + + // + // Save current stack offset. + // + StackOffset = SaveExpressionEvaluationStackOffset (); + + ASSERT (Expression != NULL); + Expression->Result.Type = EFI_IFR_TYPE_OTHER; + + Link = GetFirstNode (&Expression->OpCodeListHead); + while (!IsNull (&Expression->OpCodeListHead, Link)) { + OpCode = EXPRESSION_OPCODE_FROM_LINK (Link); + + Link = GetNextNode (&Expression->OpCodeListHead, Link); + + ZeroMem (&Data1, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data2, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data3, sizeof (EFI_HII_VALUE)); + + Value = &Data3; + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Status = EFI_SUCCESS; + + switch (OpCode->Operand) { + // + // Built-in functions + // + case EFI_IFR_EQ_ID_VAL_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL); + if (Status == EFI_UNSUPPORTED) { + Status = EFI_SUCCESS; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (EFI_ERROR (Status)) { + goto Done; + } + + Value->Value.b = (BOOLEAN)((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_ID_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2); + if (Question2 == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle); + if (Status == EFI_UNSUPPORTED) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + break; + } + + if (EFI_ERROR (Status)) { + goto Done; + } + + Value->Value.b = (BOOLEAN)((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_VAL_LIST_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value->Value.b = FALSE; + for (Index = 0; Index < OpCode->ListLength; Index++) { + if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) { + Value->Value.b = TRUE; + break; + } + } + + break; + + case EFI_IFR_DUP_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PushExpression (Value); + break; + + case EFI_IFR_QUESTION_REF1_OP: + case EFI_IFR_THIS_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + Value = &Question->HiiValue; + break; + + case EFI_IFR_SECURITY_OP: + Value->Value.b = CheckUserPrivilege (&OpCode->Guid); + break; + + case EFI_IFR_GET_OP: + // + // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore. + // + Value->Type = EFI_IFR_TYPE_UNDEFINED; + Value->Value.u8 = 0; + if (OpCode->VarStorage != NULL) { + switch (OpCode->VarStorage->Type) { + case EFI_HII_VARSTORE_BUFFER: + case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + // + // Get value from Edit Buffer + // + Value->Type = OpCode->ValueType; + CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth); + break; + case EFI_HII_VARSTORE_NAME_VALUE: + if (OpCode->ValueType != EFI_IFR_TYPE_STRING) { + // + // Get value from string except for STRING value. + // + Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr, GetSetValueWithEditBuffer); + if (!EFI_ERROR (Status)) { + ASSERT (StrPtr != NULL); + TempLength = StrLen (StrPtr); + if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) { + Value->Type = OpCode->ValueType; + TempBuffer = (UINT8 *)&Value->Value; + ZeroMem (TempStr, sizeof (TempStr)); + for (Index = 0; Index < TempLength; Index++) { + TempStr[0] = StrPtr[TempLength - Index - 1]; + DigitUint8 = (UINT8)StrHexToUint64 (TempStr); + if ((Index & 1) == 0) { + TempBuffer[Index/2] = DigitUint8; + } else { + TempBuffer[Index/2] = (UINT8)((DigitUint8 << 4) + TempBuffer[Index/2]); + } + } + } + } + } + + break; + case EFI_HII_VARSTORE_EFI_VARIABLE: + // + // Get value from variable. + // + TempLength = OpCode->ValueWidth; + Value->Type = OpCode->ValueType; + Status = gRT->GetVariable ( + OpCode->ValueName, + &OpCode->VarStorage->Guid, + NULL, + &TempLength, + &Value->Value + ); + if (EFI_ERROR (Status)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + Value->Value.u8 = 0; + } + + break; + default: + // + // Not recognize storage. + // + Status = EFI_UNSUPPORTED; + goto Done; + } + } else { + // + // For Time/Date Data + // + if ((OpCode->ValueType != EFI_IFR_TYPE_DATE) && (OpCode->ValueType != EFI_IFR_TYPE_TIME)) { + // + // Only support Data/Time data when storage doesn't exist. + // + Status = EFI_UNSUPPORTED; + goto Done; + } + + Status = gRT->GetTime (&EfiTime, NULL); + if (!EFI_ERROR (Status)) { + if (OpCode->ValueType == EFI_IFR_TYPE_DATE) { + switch (OpCode->VarStoreInfo.VarOffset) { + case 0x00: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + Value->Value.u16 = EfiTime.Year; + break; + case 0x02: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = EfiTime.Month; + break; + case 0x03: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = EfiTime.Day; + break; + default: + // + // Invalid Date field. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } else { + switch (OpCode->VarStoreInfo.VarOffset) { + case 0x00: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = EfiTime.Hour; + break; + case 0x01: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = EfiTime.Minute; + break; + case 0x02: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = EfiTime.Second; + break; + default: + // + // Invalid Time field. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + } + } + + break; + + case EFI_IFR_QUESTION_REF3_OP: + // + // EFI_IFR_QUESTION_REF3 + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (OpCode->DevicePath != 0) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + + StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle); + if ((StrPtr != NULL) && (mPathFromText != NULL)) { + DevicePath = mPathFromText->ConvertTextToDevicePath (StrPtr); + if ((DevicePath != NULL) && GetQuestionValueFromForm (DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) { + Value = &QuestionVal; + } + + if (DevicePath != NULL) { + FreePool (DevicePath); + } + } + + if (StrPtr != NULL) { + FreePool (StrPtr); + } + } else if (IsZeroGuid (&OpCode->Guid)) { + if (!GetQuestionValueFromForm (NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value = &QuestionVal; + } else { + Question = IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + // + // push the questions' value on to the expression stack + // + Value = &Question->HiiValue; + } + + break; + + case EFI_IFR_RULE_REF_OP: + // + // Find expression for this rule + // + RuleExpression = RuleIdToExpression (Form, OpCode->RuleId); + if (RuleExpression == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + // + // Evaluate this rule expression + // + Status = EvaluateExpression (FormSet, Form, RuleExpression); + if (EFI_ERROR (Status) || (RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value = &RuleExpression->Result; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type = EFI_IFR_TYPE_STRING; + Value->Value.string = OpCode->Value.Value.string; + break; + + // + // Constant + // + case EFI_IFR_TRUE_OP: + case EFI_IFR_FALSE_OP: + case EFI_IFR_ONE_OP: + case EFI_IFR_ONES_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: + Value = &OpCode->Value; + break; + + // + // unary-op + // + case EFI_IFR_LENGTH_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if ((Value->Type != EFI_IFR_TYPE_STRING) && !IsTypeInBuffer (Value)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (Value->Type == EFI_IFR_TYPE_STRING) { + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = StrLen (StrPtr); + FreePool (StrPtr); + } else { + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = GetLengthForValue (Value); + FreePool (Value->Buffer); + } + + break; + + case EFI_IFR_NOT_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value->Value.b = (BOOLEAN)(!Value->Value.b); + break; + + case EFI_IFR_QUESTION_REF2_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Question = IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question == NULL) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value = &Question->HiiValue; + break; + + case EFI_IFR_STRING_REF2_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value->Type = EFI_IFR_TYPE_STRING; + StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle); + if (StrPtr == NULL) { + // + // If String not exit, push an empty string + // + Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle); + } else { + Index = (UINT16)Value->Value.u64; + Value->Value.string = Index; + FreePool (StrPtr); + } + + break; + + case EFI_IFR_TO_BOOLEAN_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Convert an expression to a Boolean + // + if (Value->Type <= EFI_IFR_TYPE_DATE) { + // + // When converting from an unsigned integer, zero will be converted to + // FALSE and any other value will be converted to TRUE. + // + Value->Value.b = (BOOLEAN)(HiiValueToUINT64 (Value) != 0); + + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } else if (Value->Type == EFI_IFR_TYPE_STRING) { + // + // When converting from a string, if case-insensitive compare + // with "true" is True, then push True. If a case-insensitive compare + // with "false" is True, then push False. Otherwise, push Undefined. + // + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + IfrStrToUpper (StrPtr); + if (StrCmp (StrPtr, L"TRUE") == 0) { + Value->Value.b = TRUE; + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } else if (StrCmp (StrPtr, L"FALSE") == 0) { + Value->Value.b = FALSE; + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } else { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + } + + FreePool (StrPtr); + } else if (Value->Type == EFI_IFR_TYPE_BUFFER) { + // + // When converting from a buffer, if the buffer is all zeroes, + // then push False. Otherwise push True. + // + for (Index = 0; Index < Value->BufferLen; Index++) { + if (Value->Buffer[Index] != 0) { + break; + } + } + + if (Index >= Value->BufferLen) { + Value->Value.b = FALSE; + } else { + Value->Value.b = TRUE; + } + + Value->Type = EFI_IFR_TYPE_BOOLEAN; + FreePool (Value->Buffer); + } + + break; + + case EFI_IFR_TO_STRING_OP: + Status = IfrToString (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_TO_UINT_OP: + Status = IfrToUint (FormSet, Value); + break; + + case EFI_IFR_TO_LOWER_OP: + case EFI_IFR_TO_UPPER_OP: + Status = InitializeUnicodeCollationProtocol (); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value->Type != EFI_IFR_TYPE_STRING) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) { + mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr); + } else { + mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr); + } + + Value->Value.string = NewString (StrPtr, FormSet->HiiHandle); + FreePool (StrPtr); + break; + + case EFI_IFR_BITWISE_NOT_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value->Type > EFI_IFR_TYPE_DATE) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = ~HiiValueToUINT64(Value); + break; + + case EFI_IFR_SET_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + Data1.Type = EFI_IFR_TYPE_BOOLEAN; + Data1.Value.b = FALSE; + // + // Set value to var storage buffer + // + if (OpCode->VarStorage != NULL) { + switch (OpCode->VarStorage->Type) { + case EFI_HII_VARSTORE_BUFFER: + case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth); + Data1.Value.b = TRUE; + break; + case EFI_HII_VARSTORE_NAME_VALUE: + if (OpCode->ValueType != EFI_IFR_TYPE_STRING) { + NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16)); + ASSERT (NameValue != NULL); + // + // Convert Buffer to Hex String + // + TempBuffer = (UINT8 *)&Value->Value + OpCode->ValueWidth - 1; + StrPtr = NameValue; + for (Index = 0; Index < OpCode->ValueWidth; Index++, TempBuffer--) { + UnicodeValueToStringS ( + StrPtr, + (OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16) - ((UINTN)StrPtr - (UINTN)NameValue), + PREFIX_ZERO | RADIX_HEX, + *TempBuffer, + 2 + ); + StrPtr += StrnLenS (StrPtr, OpCode->ValueWidth * 2 + 1 - ((UINTN)StrPtr - (UINTN)NameValue) / sizeof (CHAR16)); + } + + Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL); + FreePool (NameValue); + if (!EFI_ERROR (Status)) { + Data1.Value.b = TRUE; + } + } + + break; + case EFI_HII_VARSTORE_EFI_VARIABLE: + Status = gRT->SetVariable ( + OpCode->ValueName, + &OpCode->VarStorage->Guid, + OpCode->VarStorage->Attributes, + OpCode->ValueWidth, + &Value->Value + ); + if (!EFI_ERROR (Status)) { + Data1.Value.b = TRUE; + } + + break; + default: + // + // Not recognize storage. + // + Status = EFI_UNSUPPORTED; + goto Done; + } + } else { + // + // For Time/Date Data + // + if ((OpCode->ValueType != EFI_IFR_TYPE_DATE) && (OpCode->ValueType != EFI_IFR_TYPE_TIME)) { + // + // Only support Data/Time data when storage doesn't exist. + // + Status = EFI_UNSUPPORTED; + goto Done; + } + + Status = gRT->GetTime (&EfiTime, NULL); + if (!EFI_ERROR (Status)) { + if (OpCode->ValueType == EFI_IFR_TYPE_DATE) { + switch (OpCode->VarStoreInfo.VarOffset) { + case 0x00: + EfiTime.Year = Value->Value.u16; + break; + case 0x02: + EfiTime.Month = Value->Value.u8; + break; + case 0x03: + EfiTime.Day = Value->Value.u8; + break; + default: + // + // Invalid Date field. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } else { + switch (OpCode->VarStoreInfo.VarOffset) { + case 0x00: + EfiTime.Hour = Value->Value.u8; + break; + case 0x01: + EfiTime.Minute = Value->Value.u8; + break; + case 0x02: + EfiTime.Second = Value->Value.u8; + break; + default: + // + // Invalid Time field. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + + Status = gRT->SetTime (&EfiTime); + if (!EFI_ERROR (Status)) { + Data1.Value.b = TRUE; + } + } + } + + Value = &Data1; + break; + + // + // binary-op + // + case EFI_IFR_ADD_OP: + case EFI_IFR_SUBTRACT_OP: + case EFI_IFR_MULTIPLY_OP: + case EFI_IFR_DIVIDE_OP: + case EFI_IFR_MODULO_OP: + case EFI_IFR_BITWISE_AND_OP: + case EFI_IFR_BITWISE_OR_OP: + case EFI_IFR_SHIFT_LEFT_OP: + case EFI_IFR_SHIFT_RIGHT_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Data2.Type > EFI_IFR_TYPE_DATE) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (Data1.Type > EFI_IFR_TYPE_DATE) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + + switch (OpCode->Operand) { + case EFI_IFR_ADD_OP: + Value->Value.u64 = HiiValueToUINT64 (&Data1) + HiiValueToUINT64 (&Data2); + break; + + case EFI_IFR_SUBTRACT_OP: + Value->Value.u64 = HiiValueToUINT64 (&Data1) - HiiValueToUINT64 (&Data2); + break; + + case EFI_IFR_MULTIPLY_OP: + Value->Value.u64 = MultU64x32 (HiiValueToUINT64 (&Data1), (UINT32)HiiValueToUINT64 (&Data2)); + break; + + case EFI_IFR_DIVIDE_OP: + Value->Value.u64 = DivU64x32 (HiiValueToUINT64 (&Data1), (UINT32)HiiValueToUINT64 (&Data2)); + break; + + case EFI_IFR_MODULO_OP: + DivU64x32Remainder (HiiValueToUINT64 (&Data1), (UINT32)HiiValueToUINT64 (&Data2), &TempValue); + Value->Value.u64 = TempValue; + break; + + case EFI_IFR_BITWISE_AND_OP: + Value->Value.u64 = HiiValueToUINT64 (&Data1) & HiiValueToUINT64 (&Data2); + break; + + case EFI_IFR_BITWISE_OR_OP: + Value->Value.u64 = HiiValueToUINT64 (&Data1) | HiiValueToUINT64 (&Data2); + break; + + case EFI_IFR_SHIFT_LEFT_OP: + Value->Value.u64 = LShiftU64 (HiiValueToUINT64 (&Data1), (UINTN)HiiValueToUINT64 (&Data2)); + break; + + case EFI_IFR_SHIFT_RIGHT_OP: + Value->Value.u64 = RShiftU64 (HiiValueToUINT64 (&Data1), (UINTN)HiiValueToUINT64 (&Data2)); + break; + + default: + break; + } + + break; + + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + // + // Two Boolean operator + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (OpCode->Operand == EFI_IFR_AND_OP) { + Value->Value.b = (BOOLEAN)(Data1.Value.b && Data2.Value.b); + } else { + Value->Value.b = (BOOLEAN)(Data1.Value.b || Data2.Value.b); + } + + break; + + case EFI_IFR_EQUAL_OP: + case EFI_IFR_NOT_EQUAL_OP: + case EFI_IFR_GREATER_EQUAL_OP: + case EFI_IFR_GREATER_THAN_OP: + case EFI_IFR_LESS_EQUAL_OP: + case EFI_IFR_LESS_THAN_OP: + // + // Compare two integer, string, boolean or date/time + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + + if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) && + (Data2.Type != EFI_IFR_TYPE_STRING) && + !IsTypeInBuffer (&Data2)) + { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if ((Data1.Type > EFI_IFR_TYPE_BOOLEAN) && + (Data1.Type != EFI_IFR_TYPE_STRING) && + !IsTypeInBuffer (&Data1)) + { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle); + if (Data1.Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Data1.Buffer); + } + + if (Data2.Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Data2.Buffer); + } + + if (Status == EFI_UNSUPPORTED) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; + break; + } + + if (EFI_ERROR (Status)) { + goto Done; + } + + switch (OpCode->Operand) { + case EFI_IFR_EQUAL_OP: + Value->Value.b = (BOOLEAN)((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_NOT_EQUAL_OP: + Value->Value.b = (BOOLEAN)((Result != 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_EQUAL_OP: + Value->Value.b = (BOOLEAN)((Result >= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_THAN_OP: + Value->Value.b = (BOOLEAN)((Result > 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_EQUAL_OP: + Value->Value.b = (BOOLEAN)((Result <= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_THAN_OP: + Value->Value.b = (BOOLEAN)((Result < 0) ? TRUE : FALSE); + break; + + default: + break; + } + + break; + + case EFI_IFR_MATCH_OP: + Status = InitializeUnicodeCollationProtocol (); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = IfrMatch (FormSet, Value); + break; + + case EFI_IFR_MATCH2_OP: + Status = IfrMatch2 (FormSet, &OpCode->Guid, Value); + break; + + case EFI_IFR_CATENATE_OP: + Status = IfrCatenate (FormSet, Value); + break; + + // + // ternary-op + // + case EFI_IFR_CONDITIONAL_OP: + // + // Pop third expression from the expression stack + // + Status = PopExpression (&Data3); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop second expression from the expression stack + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop first expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (Data1.Value.b) { + Value = &Data3; + } else { + Value = &Data2; + } + + break; + + case EFI_IFR_FIND_OP: + Status = IfrFind (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_MID_OP: + Status = IfrMid (FormSet, Value); + break; + + case EFI_IFR_TOKEN_OP: + Status = IfrToken (FormSet, Value); + break; + + case EFI_IFR_SPAN_OP: + Status = IfrSpan (FormSet, OpCode->Flags, Value); + break; + + case EFI_IFR_MAP_OP: + // + // Pop the check value + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Check MapExpression list is valid. + // + if (OpCode->MapExpressionList.ForwardLink == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Go through map expression list. + // + SubExpressionLink = GetFirstNode (&OpCode->MapExpressionList); + while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink); + // + // Evaluate the first expression in this pair. + // + Status = EvaluateExpression (FormSet, Form, SubExpression); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Compare the expression value with current value + // + if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + // + // Try get the map value. + // + SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink); + if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink); + Status = EvaluateExpression (FormSet, Form, SubExpression); + if (EFI_ERROR (Status)) { + goto Done; + } + + Value = &SubExpression->Result; + break; + } + + // + // Skip the second expression on this pair. + // + SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink); + if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Goto the first expression on next pair. + // + SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink); + } + + // + // No map value is found. + // + if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + Value->Value.u8 = 0; + } + + break; + + default: + break; + } + + if (EFI_ERROR (Status) || (Value->Type == EFI_IFR_TYPE_UNDEFINED)) { + goto Done; + } + + Status = PushExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Pop the final result from expression stack + // + Value = &Data1; + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // After evaluating an expression, there should be only one value left on the expression stack + // + if (PopExpression (Value) != EFI_ACCESS_DENIED) { + Status = EFI_INVALID_PARAMETER; + } + +Done: + RestoreExpressionEvaluationStackOffset (StackOffset); + if (!EFI_ERROR (Status)) { + CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); + } + + return Status; +} + +/** + Check whether the result is TRUE or FALSE. + + For the EFI_HII_VALUE value type is numeric, return TRUE if the + value is not 0. + + @param Result Input the result data. + + @retval TRUE The result is TRUE. + @retval FALSE The result is FALSE. + +**/ +BOOLEAN +IsTrue ( + IN EFI_HII_VALUE *Result + ) +{ + switch (Result->Type) { + case EFI_IFR_TYPE_BOOLEAN: + return Result->Value.b; + + case EFI_IFR_TYPE_NUM_SIZE_8: + return (BOOLEAN)(Result->Value.u8 != 0); + + case EFI_IFR_TYPE_NUM_SIZE_16: + return (BOOLEAN)(Result->Value.u16 != 0); + + case EFI_IFR_TYPE_NUM_SIZE_32: + return (BOOLEAN)(Result->Value.u32 != 0); + + case EFI_IFR_TYPE_NUM_SIZE_64: + return (BOOLEAN)(Result->Value.u64 != 0); + + default: + return FALSE; + } +} + +/** + Return the result of the expression list. Check the expression list and + return the highest priority express result. + Priority: DisableIf > SuppressIf > GrayOutIf > FALSE + + @param ExpList The input expression list. + @param Evaluate Whether need to evaluate the expression first. + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + + @retval EXPRESS_RESULT Return the higher priority express result. + DisableIf > SuppressIf > GrayOutIf > FALSE + +**/ +EXPRESS_RESULT +EvaluateExpressionList ( + IN FORM_EXPRESSION_LIST *ExpList, + IN BOOLEAN Evaluate, + IN FORM_BROWSER_FORMSET *FormSet OPTIONAL, + IN FORM_BROWSER_FORM *Form OPTIONAL + ) +{ + UINTN Index; + EXPRESS_RESULT ReturnVal; + EXPRESS_RESULT CompareOne; + EFI_STATUS Status; + + if (ExpList == NULL) { + return ExpressFalse; + } + + ASSERT (ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE); + Index = 0; + + // + // Check whether need to evaluate the expression first. + // + if (Evaluate) { + while (ExpList->Count > Index) { + Status = EvaluateExpression (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 (IsTrue (&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; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h index b56c81eb05..0bace4b26d 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h @@ -1,260 +1,260 @@ -/** @file
-Private structure, MACRO and function definitions for User Interface related functionalities.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EXPRESSION_H_
-#define _EXPRESSION_H_
-
-/**
- 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
- );
-
-/**
- Reset stack pointer to begin of the stack.
-
-**/
-VOID
-ResetCurrentExpressionStack (
- VOID
- );
-
-/**
- Reset stack pointer to begin of the stack.
-
-**/
-VOID
-ResetMapExpressionListStack (
- VOID
- );
-
-/**
- Reset stack pointer to begin of the stack.
-
-**/
-VOID
-ResetScopeStack (
- VOID
- );
-
-/**
- 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
- );
-
-/**
- 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.
-
-**/
-FORM_EXPRESSION **
-GetConditionalExpressionList (
- IN EXPRESS_LEVEL Level
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-/**
- Zero extend integer/boolean/date/time to UINT64 for comparing.
-
- @param Value HII Value to be converted.
-
-**/
-VOID
-ExtendValueToU64 (
- IN EFI_HII_VALUE *Value
- );
-
-/**
- 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 FORM_EXPRESSION *Pointer,
- IN EXPRESS_LEVEL Level
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-/**
- Evaluate the result of a HII expression.
-
- If Expression is NULL, then ASSERT.
-
- @param FormSet FormSet associated with this expression.
- @param Form Form associated with this expression.
- @param Expression Expression to be evaluated.
-
- @retval EFI_SUCCESS The expression evaluated successfuly
- @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
- could not be found.
- @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
- stack.
- @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
- @retval EFI_INVALID_PARAMETER Syntax error with the Expression
-
-**/
-EFI_STATUS
-EvaluateExpression (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_EXPRESSION *Expression
- );
-
-/**
- Return the result of the expression list. Check the expression list and
- return the highest priority express result.
- Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
-
- @param ExpList The input expression list.
- @param Evaluate Whether need to evaluate the expression first.
- @param FormSet FormSet associated with this expression.
- @param Form Form associated with this expression.
-
- @retval EXPRESS_RESULT Return the higher priority express result.
- DisableIf > SuppressIf > GrayOutIf > FALSE
-
-**/
-EXPRESS_RESULT
-EvaluateExpressionList (
- IN FORM_EXPRESSION_LIST *ExpList,
- IN BOOLEAN Evaluate,
- IN FORM_BROWSER_FORMSET *FormSet OPTIONAL,
- IN FORM_BROWSER_FORM *Form OPTIONAL
- );
-
-/**
- Get Form given its FormId.
-
- @param FormSet The formset which contains this form.
- @param FormId Id of this form.
-
- @retval Pointer The form.
- @retval NULL Specified Form is not found in the formset.
-
-**/
-FORM_BROWSER_FORM *
-IdToForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN UINT16 FormId
- );
-
-#endif // _EXPRESSION_H
+/** @file +Private structure, MACRO and function definitions for User Interface related functionalities. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EXPRESSION_H_ +#define _EXPRESSION_H_ + +/** + 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 + ); + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetCurrentExpressionStack ( + VOID + ); + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetMapExpressionListStack ( + VOID + ); + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetScopeStack ( + VOID + ); + +/** + 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 + ); + +/** + 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. + +**/ +FORM_EXPRESSION ** +GetConditionalExpressionList ( + IN EXPRESS_LEVEL Level + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ); + +/** + 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 FORM_EXPRESSION *Pointer, + IN EXPRESS_LEVEL Level + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Evaluate the result of a HII expression. + + If Expression is NULL, then ASSERT. + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ); + +/** + Return the result of the expression list. Check the expression list and + return the highest priority express result. + Priority: DisableIf > SuppressIf > GrayOutIf > FALSE + + @param ExpList The input expression list. + @param Evaluate Whether need to evaluate the expression first. + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + + @retval EXPRESS_RESULT Return the higher priority express result. + DisableIf > SuppressIf > GrayOutIf > FALSE + +**/ +EXPRESS_RESULT +EvaluateExpressionList ( + IN FORM_EXPRESSION_LIST *ExpList, + IN BOOLEAN Evaluate, + IN FORM_BROWSER_FORMSET *FormSet OPTIONAL, + IN FORM_BROWSER_FORM *Form OPTIONAL + ); + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId + ); + +#endif // _EXPRESSION_H diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index ed8f9965be..bb1d9e7f2e 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -1,2750 +1,2750 @@ -/** @file
-Parser for IFR binary encoding.
-
-Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
-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. <RequestElement> ::= '&'<BlockName> | '&'<Label>
-
- @param FormSet Pointer of the current FormSet.
- @param Question The Question to be initialized.
- @param Form Pointer of the current form.
-
- @retval EFI_SUCCESS Function success.
- @retval EFI_INVALID_PARAMETER No storage associated with the Question.
-
-**/
-EFI_STATUS
-InitializeRequestElement (
- IN OUT FORM_BROWSER_FORMSET *FormSet,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN OUT FORM_BROWSER_FORM *Form
- )
-{
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormsetStorage;
- UINTN StrLen;
- UINTN StringSize;
- CHAR16 *NewStr;
- CHAR16 RequestElement[30];
- LIST_ENTRY *Link;
- BOOLEAN Find;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
- UINTN MaxLen;
-
- Storage = Question->Storage;
- if (Storage == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- //
- // <ConfigRequest> is unnecessary for EFI variable storage,
- // GetVariable()/SetVariable() will be used to retrieve/save values
- //
- return EFI_SUCCESS;
- }
-
- //
- // Prepare <RequestElement>
- //
- if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER))
- {
- StrLen = UnicodeSPrint (
- RequestElement,
- 30 * sizeof (CHAR16),
- L"&OFFSET=%04x&WIDTH=%04x",
- Question->VarStoreInfo.VarOffset,
- Question->StorageWidth
- );
- HiiToLower (RequestElement);
- Question->BlockName = AllocateCopyPool ((StrLen + 1) * sizeof (CHAR16), RequestElement);
- } else {
- StrLen = UnicodeSPrint (RequestElement, 30 * sizeof (CHAR16), L"&%s", Question->VariableName);
- }
-
- if ((Question->Operand == EFI_IFR_PASSWORD_OP) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
- //
- // Password with CALLBACK flag is stored in encoded format,
- // so don't need to append it to <ConfigRequest>
- //
- return EFI_SUCCESS;
- }
-
- //
- // Find Formset Storage for this Question
- //
- FormsetStorage = GetFstStgFromVarId (FormSet, Question->VarStoreId);
- ASSERT (FormsetStorage != NULL);
- StringSize = (FormsetStorage->ConfigRequest != NULL) ? StrSize (FormsetStorage->ConfigRequest) : sizeof (CHAR16);
- MaxLen = StringSize / sizeof (CHAR16) + FormsetStorage->SpareStrLen;
-
- //
- // Append <RequestElement> to <ConfigRequest>
- //
- if (StrLen > FormsetStorage->SpareStrLen) {
- //
- // Old String buffer is not sufficient for RequestElement, allocate a new one
- //
- MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
- NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (NewStr != NULL);
- if (FormsetStorage->ConfigRequest != NULL) {
- CopyMem (NewStr, FormsetStorage->ConfigRequest, StringSize);
- FreePool (FormsetStorage->ConfigRequest);
- }
-
- FormsetStorage->ConfigRequest = NewStr;
- FormsetStorage->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
- }
-
- StrCatS (FormsetStorage->ConfigRequest, MaxLen, RequestElement);
- FormsetStorage->ElementCount++;
- FormsetStorage->SpareStrLen -= StrLen;
-
- //
- // Update the Config Request info saved in the form.
- //
- ConfigInfo = NULL;
- Find = FALSE;
- Link = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
-
- if ((ConfigInfo != NULL) && (ConfigInfo->Storage == FormsetStorage->BrowserStorage)) {
- Find = TRUE;
- break;
- }
-
- Link = GetNextNode (&Form->ConfigRequestHead, Link);
- }
-
- if (!Find) {
- ConfigInfo = AllocateZeroPool (sizeof (FORM_BROWSER_CONFIG_REQUEST));
- ASSERT (ConfigInfo != NULL);
- ConfigInfo->Signature = FORM_BROWSER_CONFIG_REQUEST_SIGNATURE;
- ConfigInfo->ConfigRequest = AllocateCopyPool (StrSize (FormsetStorage->ConfigHdr), FormsetStorage->ConfigHdr);
- ASSERT (ConfigInfo->ConfigRequest != NULL);
- ConfigInfo->SpareStrLen = 0;
- ConfigInfo->Storage = FormsetStorage->BrowserStorage;
- InsertTailList (&Form->ConfigRequestHead, &ConfigInfo->Link);
- }
-
- StringSize = (ConfigInfo->ConfigRequest != NULL) ? StrSize (ConfigInfo->ConfigRequest) : sizeof (CHAR16);
- MaxLen = StringSize / sizeof (CHAR16) + ConfigInfo->SpareStrLen;
-
- //
- // Append <RequestElement> to <ConfigRequest>
- //
- if (StrLen > ConfigInfo->SpareStrLen) {
- //
- // Old String buffer is not sufficient for RequestElement, allocate a new one
- //
- MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
- NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (NewStr != NULL);
- if (ConfigInfo->ConfigRequest != NULL) {
- CopyMem (NewStr, ConfigInfo->ConfigRequest, StringSize);
- FreePool (ConfigInfo->ConfigRequest);
- }
-
- ConfigInfo->ConfigRequest = NewStr;
- ConfigInfo->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
- }
-
- StrCatS (ConfigInfo->ConfigRequest, MaxLen, RequestElement);
- ConfigInfo->ElementCount++;
- ConfigInfo->SpareStrLen -= StrLen;
- return EFI_SUCCESS;
-}
-
-/**
- Free resources of a Expression.
-
- @param FormSet Pointer of the Expression
-
-**/
-VOID
-DestroyExpression (
- IN FORM_EXPRESSION *Expression
- )
-{
- LIST_ENTRY *Link;
- EXPRESSION_OPCODE *OpCode;
- LIST_ENTRY *SubExpressionLink;
- FORM_EXPRESSION *SubExpression;
-
- while (!IsListEmpty (&Expression->OpCodeListHead)) {
- Link = GetFirstNode (&Expression->OpCodeListHead);
- OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
- RemoveEntryList (&OpCode->Link);
-
- if (OpCode->ValueList != NULL) {
- FreePool (OpCode->ValueList);
- }
-
- if (OpCode->ValueName != NULL) {
- FreePool (OpCode->ValueName);
- }
-
- if (OpCode->MapExpressionList.ForwardLink != NULL) {
- while (!IsListEmpty (&OpCode->MapExpressionList)) {
- SubExpressionLink = GetFirstNode (&OpCode->MapExpressionList);
- SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
- RemoveEntryList (&SubExpression->Link);
- DestroyExpression (SubExpression);
- }
- }
- }
-
- //
- // Free this Expression
- //
- FreePool (Expression);
-}
-
-/**
- Free resources of a storage.
-
- @param Storage Pointer of the storage
-
-**/
-VOID
-DestroyStorage (
- IN FORMSET_STORAGE *Storage
- )
-{
- if (Storage == NULL) {
- return;
- }
-
- if (Storage->ConfigRequest != NULL) {
- FreePool (Storage->ConfigRequest);
- }
-
- FreePool (Storage);
-}
-
-/**
- Free resources of a Statement.
-
- @param FormSet Pointer of the FormSet
- @param Statement Pointer of the Statement
-
-**/
-VOID
-DestroyStatement (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN OUT FORM_BROWSER_STATEMENT *Statement
- )
-{
- LIST_ENTRY *Link;
- QUESTION_DEFAULT *Default;
- QUESTION_OPTION *Option;
- FORM_EXPRESSION *Expression;
-
- //
- // Free Default value List
- //
- while (!IsListEmpty (&Statement->DefaultListHead)) {
- Link = GetFirstNode (&Statement->DefaultListHead);
- Default = QUESTION_DEFAULT_FROM_LINK (Link);
- RemoveEntryList (&Default->Link);
-
- if (Default->Value.Buffer != NULL) {
- FreePool (Default->Value.Buffer);
- }
-
- FreePool (Default);
- }
-
- //
- // Free Options List
- //
- while (!IsListEmpty (&Statement->OptionListHead)) {
- Link = GetFirstNode (&Statement->OptionListHead);
- Option = QUESTION_OPTION_FROM_LINK (Link);
- if (Option->SuppressExpression != NULL) {
- FreePool (Option->SuppressExpression);
- }
-
- RemoveEntryList (&Option->Link);
-
- FreePool (Option);
- }
-
- //
- // Free Inconsistent List
- //
- while (!IsListEmpty (&Statement->InconsistentListHead)) {
- Link = GetFirstNode (&Statement->InconsistentListHead);
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- RemoveEntryList (&Expression->Link);
-
- DestroyExpression (Expression);
- }
-
- //
- // Free NoSubmit List
- //
- while (!IsListEmpty (&Statement->NoSubmitListHead)) {
- Link = GetFirstNode (&Statement->NoSubmitListHead);
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- RemoveEntryList (&Expression->Link);
-
- DestroyExpression (Expression);
- }
-
- //
- // Free WarningIf List
- //
- while (!IsListEmpty (&Statement->WarningListHead)) {
- Link = GetFirstNode (&Statement->WarningListHead);
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- RemoveEntryList (&Expression->Link);
-
- DestroyExpression (Expression);
- }
-
- if (Statement->Expression != NULL) {
- FreePool (Statement->Expression);
- }
-
- if (Statement->VariableName != NULL) {
- FreePool (Statement->VariableName);
- }
-
- if (Statement->BlockName != NULL) {
- FreePool (Statement->BlockName);
- }
-
- if (Statement->BufferValue != NULL) {
- FreePool (Statement->BufferValue);
- }
-
- if ((Statement->Operand == EFI_IFR_STRING_OP) || (Statement->Operand == EFI_IFR_PASSWORD_OP)) {
- DeleteString (Statement->HiiValue.Value.string, FormSet->HiiHandle);
- }
-}
-
-/**
- Free resources of a Form.
-
- @param FormSet Pointer of the FormSet
- @param Form Pointer of the Form.
-
-**/
-VOID
-DestroyForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN OUT FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_EXPRESSION *Expression;
- FORM_BROWSER_STATEMENT *Statement;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
-
- //
- // Free Form Expressions
- //
- while (!IsListEmpty (&Form->ExpressionListHead)) {
- Link = GetFirstNode (&Form->ExpressionListHead);
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- RemoveEntryList (&Expression->Link);
-
- DestroyExpression (Expression);
- }
-
- //
- // Free Statements/Questions
- //
- while (!IsListEmpty (&Form->StatementListHead)) {
- Link = GetFirstNode (&Form->StatementListHead);
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- RemoveEntryList (&Statement->Link);
-
- DestroyStatement (FormSet, Statement);
- }
-
- //
- // Free ConfigRequest string.
- //
- while (!IsListEmpty (&Form->ConfigRequestHead)) {
- Link = GetFirstNode (&Form->ConfigRequestHead);
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
- RemoveEntryList (&ConfigInfo->Link);
-
- FreePool (ConfigInfo->ConfigRequest);
- FreePool (ConfigInfo);
- }
-
- if (Form->SuppressExpression != NULL) {
- FreePool (Form->SuppressExpression);
- }
-
- UiFreeMenuList (&Form->FormViewListHead);
-
- //
- // Free this Form
- //
- FreePool (Form);
-}
-
-/**
- Free resources allocated for a FormSet.
-
- @param FormSet Pointer of the FormSet
-
-**/
-VOID
-DestroyFormSet (
- IN OUT FORM_BROWSER_FORMSET *FormSet
- )
-{
- LIST_ENTRY *Link;
- FORMSET_STORAGE *Storage;
- FORMSET_DEFAULTSTORE *DefaultStore;
- FORM_EXPRESSION *Expression;
- FORM_BROWSER_FORM *Form;
-
- if (FormSet->IfrBinaryData == NULL) {
- //
- // Uninitialized FormSet
- //
- FreePool (FormSet);
- return;
- }
-
- //
- // Free IFR binary buffer
- //
- FreePool (FormSet->IfrBinaryData);
-
- //
- // Free FormSet Storage
- //
- if (FormSet->StorageListHead.ForwardLink != NULL) {
- while (!IsListEmpty (&FormSet->StorageListHead)) {
- Link = GetFirstNode (&FormSet->StorageListHead);
- Storage = FORMSET_STORAGE_FROM_LINK (Link);
- RemoveEntryList (&Storage->Link);
-
- DestroyStorage (Storage);
- }
- }
-
- //
- // Free FormSet Default Store
- //
- if (FormSet->DefaultStoreListHead.ForwardLink != NULL) {
- while (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
- Link = GetFirstNode (&FormSet->DefaultStoreListHead);
- DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link);
- RemoveEntryList (&DefaultStore->Link);
-
- FreePool (DefaultStore);
- }
- }
-
- //
- // Free Formset Expressions
- //
- while (!IsListEmpty (&FormSet->ExpressionListHead)) {
- Link = GetFirstNode (&FormSet->ExpressionListHead);
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- RemoveEntryList (&Expression->Link);
-
- DestroyExpression (Expression);
- }
-
- //
- // Free Forms
- //
- if (FormSet->FormListHead.ForwardLink != NULL) {
- while (!IsListEmpty (&FormSet->FormListHead)) {
- Link = GetFirstNode (&FormSet->FormListHead);
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- RemoveEntryList (&Form->Link);
-
- DestroyForm (FormSet, Form);
- }
- }
-
- if (FormSet->StatementBuffer != NULL) {
- FreePool (FormSet->StatementBuffer);
- }
-
- if (FormSet->ExpressionBuffer != NULL) {
- FreePool (FormSet->ExpressionBuffer);
- }
-
- FreePool (FormSet);
-}
-
-/**
- Tell whether this Operand is an Expression OpCode or not
-
- @param Operand Operand of an IFR OpCode.
-
- @retval TRUE This is an Expression OpCode.
- @retval FALSE Not an Expression OpCode.
-
-**/
-BOOLEAN
-IsExpressionOpCode (
- IN UINT8 Operand
- )
-{
- if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) ||
- ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP)) ||
- ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) ||
- (Operand == EFI_IFR_CATENATE_OP) ||
- (Operand == EFI_IFR_TO_LOWER_OP) ||
- (Operand == EFI_IFR_TO_UPPER_OP) ||
- (Operand == EFI_IFR_MAP_OP) ||
- (Operand == EFI_IFR_VERSION_OP) ||
- (Operand == EFI_IFR_SECURITY_OP) ||
- (Operand == EFI_IFR_MATCH2_OP))
- {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Tell whether this Operand is an Statement OpCode.
-
- @param Operand Operand of an IFR OpCode.
-
- @retval TRUE This is an Statement OpCode.
- @retval FALSE Not an Statement OpCode.
-
-**/
-BOOLEAN
-IsStatementOpCode (
- IN UINT8 Operand
- )
-{
- if ((Operand == EFI_IFR_SUBTITLE_OP) ||
- (Operand == EFI_IFR_TEXT_OP) ||
- (Operand == EFI_IFR_RESET_BUTTON_OP) ||
- (Operand == EFI_IFR_REF_OP) ||
- (Operand == EFI_IFR_ACTION_OP) ||
- (Operand == EFI_IFR_NUMERIC_OP) ||
- (Operand == EFI_IFR_ORDERED_LIST_OP) ||
- (Operand == EFI_IFR_CHECKBOX_OP) ||
- (Operand == EFI_IFR_STRING_OP) ||
- (Operand == EFI_IFR_PASSWORD_OP) ||
- (Operand == EFI_IFR_DATE_OP) ||
- (Operand == EFI_IFR_TIME_OP) ||
- (Operand == EFI_IFR_GUID_OP) ||
- (Operand == EFI_IFR_ONE_OF_OP))
- {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Tell whether this Operand is an known OpCode.
-
- @param Operand Operand of an IFR OpCode.
-
- @retval TRUE This is an Statement OpCode.
- @retval FALSE Not an Statement OpCode.
-
-**/
-BOOLEAN
-IsUnKnownOpCode (
- IN UINT8 Operand
- )
-{
- return Operand > EFI_IFR_MATCH2_OP ? TRUE : FALSE;
-}
-
-/**
- Calculate number of Statemens(Questions) and Expression OpCodes.
-
- @param FormSet The FormSet to be counted.
- @param NumberOfStatement Number of Statemens(Questions)
- @param NumberOfExpression Number of Expression OpCodes
-
-**/
-VOID
-CountOpCodes (
- IN FORM_BROWSER_FORMSET *FormSet,
- OUT UINTN *NumberOfStatement,
- OUT UINTN *NumberOfExpression
- )
-{
- UINTN StatementCount;
- UINTN ExpressionCount;
- UINT8 *OpCodeData;
- UINTN Offset;
- UINTN OpCodeLen;
-
- Offset = 0;
- StatementCount = 0;
- ExpressionCount = 0;
-
- while (Offset < FormSet->IfrBinaryLength) {
- OpCodeData = FormSet->IfrBinaryData + Offset;
- OpCodeLen = ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
- Offset += OpCodeLen;
-
- if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode)) {
- ExpressionCount++;
- } else {
- StatementCount++;
- }
- }
-
- *NumberOfStatement = StatementCount;
- *NumberOfExpression = ExpressionCount;
-}
-
-/**
- Parse opcodes in the formset IFR binary.
-
- @param FormSet Pointer of the FormSet data structure.
-
- @retval EFI_SUCCESS Opcode parse success.
- @retval Other Opcode parse fail.
-
-**/
-EFI_STATUS
-ParseOpCodes (
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- EFI_STATUS Status;
- FORM_BROWSER_FORM *CurrentForm;
- FORM_BROWSER_STATEMENT *CurrentStatement;
- FORM_BROWSER_STATEMENT *ParentStatement;
- EXPRESSION_OPCODE *ExpressionOpCode;
- FORM_EXPRESSION *CurrentExpression;
- UINT8 Operand;
- UINT8 Scope;
- UINTN OpCodeOffset;
- UINTN OpCodeLength;
- UINT8 *OpCodeData;
- UINT8 ScopeOpCode;
- FORMSET_STORAGE *Storage;
- FORMSET_DEFAULTSTORE *DefaultStore;
- QUESTION_DEFAULT *CurrentDefault;
- QUESTION_OPTION *CurrentOption;
- UINT8 Width;
- UINTN NumberOfStatement;
- UINTN NumberOfExpression;
- EFI_IMAGE_ID *ImageId;
- BOOLEAN SuppressForQuestion;
- BOOLEAN SuppressForOption;
- UINT16 DepthOfDisable;
- BOOLEAN OpCodeDisabled;
- BOOLEAN SingleOpCodeExpression;
- BOOLEAN InScopeDefault;
- EFI_HII_VALUE *Value;
- EFI_IFR_FORM_MAP_METHOD *MapMethod;
- UINT8 MapScopeDepth;
- LIST_ENTRY *Link;
- FORMSET_STORAGE *VarStorage;
- LIST_ENTRY *MapExpressionList;
- EFI_VARSTORE_ID TempVarstoreId;
- BOOLEAN InScopeDisable;
- INTN ConditionalExprCount;
- BOOLEAN InUnknownScope;
- UINT8 UnknownDepth;
- FORMSET_DEFAULTSTORE *PreDefaultStore;
- LIST_ENTRY *DefaultLink;
- BOOLEAN HaveInserted;
- UINT16 TotalBits;
- BOOLEAN QuestionReferBitField;
-
- SuppressForQuestion = FALSE;
- SuppressForOption = FALSE;
- InScopeDisable = FALSE;
- DepthOfDisable = 0;
- OpCodeDisabled = FALSE;
- SingleOpCodeExpression = FALSE;
- InScopeDefault = FALSE;
- CurrentExpression = NULL;
- CurrentDefault = NULL;
- CurrentOption = NULL;
- ImageId = NULL;
- MapMethod = NULL;
- MapScopeDepth = 0;
- Link = NULL;
- VarStorage = NULL;
- MapExpressionList = NULL;
- TempVarstoreId = 0;
- ConditionalExprCount = 0;
- InUnknownScope = FALSE;
- UnknownDepth = 0;
- QuestionReferBitField = FALSE;
-
- //
- // Get the number of Statements and Expressions
- //
- CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);
-
- mStatementIndex = 0;
- mUsedQuestionId = 1;
- FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
- if (FormSet->StatementBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- mExpressionOpCodeIndex = 0;
- FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE));
- if (FormSet->ExpressionBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- InitializeListHead (&FormSet->StatementListOSF);
- InitializeListHead (&FormSet->StorageListHead);
- InitializeListHead (&FormSet->SaveFailStorageListHead);
- InitializeListHead (&FormSet->DefaultStoreListHead);
- InitializeListHead (&FormSet->FormListHead);
- InitializeListHead (&FormSet->ExpressionListHead);
- ResetCurrentExpressionStack ();
- ResetMapExpressionListStack ();
-
- CurrentForm = NULL;
- CurrentStatement = NULL;
- ParentStatement = NULL;
-
- ResetScopeStack ();
-
- OpCodeOffset = 0;
- while (OpCodeOffset < FormSet->IfrBinaryLength) {
- OpCodeData = FormSet->IfrBinaryData + OpCodeOffset;
-
- OpCodeLength = ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
- OpCodeOffset += OpCodeLength;
- Operand = ((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode;
- Scope = ((EFI_IFR_OP_HEADER *)OpCodeData)->Scope;
-
- if (InUnknownScope) {
- if (Operand == EFI_IFR_END_OP) {
- UnknownDepth--;
-
- if (UnknownDepth == 0) {
- InUnknownScope = FALSE;
- }
- } else {
- if (Scope != 0) {
- UnknownDepth++;
- }
- }
-
- continue;
- }
-
- if (IsUnKnownOpCode (Operand)) {
- if (Scope != 0) {
- InUnknownScope = TRUE;
- UnknownDepth++;
- }
-
- continue;
- }
-
- //
- // If scope bit set, push onto scope stack
- //
- if (Scope != 0) {
- PushScope (Operand);
- }
-
- if (OpCodeDisabled) {
- //
- // DisableIf Expression is evaluated to be TRUE, try to find its end.
- // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END
- //
- if (Operand == EFI_IFR_DISABLE_IF_OP) {
- DepthOfDisable++;
- } else if (Operand == EFI_IFR_END_OP) {
- Status = PopScope (&ScopeOpCode);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) {
- if (DepthOfDisable == 0) {
- InScopeDisable = FALSE;
- OpCodeDisabled = FALSE;
- } else {
- DepthOfDisable--;
- }
- }
- }
-
- continue;
- }
-
- if (IsExpressionOpCode (Operand)) {
- ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex];
- mExpressionOpCodeIndex++;
-
- ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE;
- ExpressionOpCode->Operand = Operand;
- Value = &ExpressionOpCode->Value;
-
- switch (Operand) {
- case EFI_IFR_EQ_ID_VAL_OP:
- CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
-
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
- CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *)OpCodeData)->Value, sizeof (UINT16));
- break;
-
- case EFI_IFR_EQ_ID_ID_OP:
- CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *)OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID));
- CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *)OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID));
- break;
-
- case EFI_IFR_EQ_ID_VAL_LIST_OP:
- CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
- CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->ListLength, sizeof (UINT16));
- ExpressionOpCode->ValueList = AllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->ValueList);
- break;
-
- case EFI_IFR_TO_STRING_OP:
- case EFI_IFR_FIND_OP:
- ExpressionOpCode->Format = ((EFI_IFR_TO_STRING *)OpCodeData)->Format;
- break;
-
- case EFI_IFR_STRING_REF1_OP:
- Value->Type = EFI_IFR_TYPE_STRING;
- CopyMem (&Value->Value.string, &((EFI_IFR_STRING_REF1 *)OpCodeData)->StringId, sizeof (EFI_STRING_ID));
- break;
-
- case EFI_IFR_RULE_REF_OP:
- ExpressionOpCode->RuleId = ((EFI_IFR_RULE_REF *)OpCodeData)->RuleId;
- break;
-
- case EFI_IFR_SPAN_OP:
- ExpressionOpCode->Flags = ((EFI_IFR_SPAN *)OpCodeData)->Flags;
- break;
-
- case EFI_IFR_THIS_OP:
- ASSERT (ParentStatement != NULL);
- ExpressionOpCode->QuestionId = ParentStatement->QuestionId;
- break;
-
- case EFI_IFR_SECURITY_OP:
- CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *)OpCodeData)->Permissions, sizeof (EFI_GUID));
- break;
-
- case EFI_IFR_MATCH2_OP:
- CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_MATCH2 *)OpCodeData)->SyntaxType, sizeof (EFI_GUID));
- break;
-
- case EFI_IFR_GET_OP:
- case EFI_IFR_SET_OP:
- CopyMem (&TempVarstoreId, &((EFI_IFR_GET *)OpCodeData)->VarStoreId, sizeof (TempVarstoreId));
- if (TempVarstoreId != 0) {
- if (FormSet->StorageListHead.ForwardLink != NULL) {
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- VarStorage = FORMSET_STORAGE_FROM_LINK (Link);
- if (VarStorage->VarStoreId == ((EFI_IFR_GET *)OpCodeData)->VarStoreId) {
- ExpressionOpCode->VarStorage = VarStorage->BrowserStorage;
- break;
- }
-
- Link = GetNextNode (&FormSet->StorageListHead, Link);
- }
- }
-
- if (ExpressionOpCode->VarStorage == NULL) {
- //
- // VarStorage is not found.
- //
- return EFI_INVALID_PARAMETER;
- }
- }
-
- ExpressionOpCode->ValueType = ((EFI_IFR_GET *)OpCodeData)->VarStoreType;
- switch (ExpressionOpCode->ValueType) {
- case EFI_IFR_TYPE_BOOLEAN:
- case EFI_IFR_TYPE_NUM_SIZE_8:
- ExpressionOpCode->ValueWidth = 1;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- case EFI_IFR_TYPE_STRING:
- ExpressionOpCode->ValueWidth = 2;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- ExpressionOpCode->ValueWidth = 4;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- ExpressionOpCode->ValueWidth = 8;
- break;
-
- case EFI_IFR_TYPE_DATE:
- ExpressionOpCode->ValueWidth = (UINT8)sizeof (EFI_IFR_DATE);
- break;
-
- case EFI_IFR_TYPE_TIME:
- ExpressionOpCode->ValueWidth = (UINT8)sizeof (EFI_IFR_TIME);
- break;
-
- case EFI_IFR_TYPE_REF:
- ExpressionOpCode->ValueWidth = (UINT8)sizeof (EFI_IFR_REF);
- break;
-
- case EFI_IFR_TYPE_OTHER:
- case EFI_IFR_TYPE_UNDEFINED:
- case EFI_IFR_TYPE_ACTION:
- case EFI_IFR_TYPE_BUFFER:
- default:
- //
- // Invalid value type for Get/Set opcode.
- //
- return EFI_INVALID_PARAMETER;
- }
-
- CopyMem (&ExpressionOpCode->VarStoreInfo.VarName, &((EFI_IFR_GET *)OpCodeData)->VarStoreInfo.VarName, sizeof (EFI_STRING_ID));
- CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *)OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16));
- if ((ExpressionOpCode->VarStorage != NULL) &&
- ((ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) ||
- (ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)))
- {
- ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->HiiHandle);
- if (ExpressionOpCode->ValueName == NULL) {
- //
- // String ID is invalid.
- //
- return EFI_INVALID_PARAMETER;
- }
- }
-
- break;
-
- case EFI_IFR_QUESTION_REF1_OP:
- CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
- break;
-
- case EFI_IFR_QUESTION_REF3_OP:
- if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) {
- CopyMem (&ExpressionOpCode->DevicePath, &((EFI_IFR_QUESTION_REF3_2 *)OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
-
- if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) {
- CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_QUESTION_REF3_3 *)OpCodeData)->Guid, sizeof (EFI_GUID));
- }
- }
-
- break;
-
- //
- // constant
- //
- case EFI_IFR_TRUE_OP:
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- Value->Value.b = TRUE;
- break;
-
- case EFI_IFR_FALSE_OP:
- Value->Type = EFI_IFR_TYPE_BOOLEAN;
- Value->Value.b = FALSE;
- break;
-
- case EFI_IFR_ONE_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = 1;
- break;
-
- case EFI_IFR_ZERO_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = 0;
- break;
-
- case EFI_IFR_ONES_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- Value->Value.u64 = 0xffffffffffffffffULL;
- break;
-
- case EFI_IFR_UINT8_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- Value->Value.u8 = ((EFI_IFR_UINT8 *)OpCodeData)->Value;
- break;
-
- case EFI_IFR_UINT16_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
- CopyMem (&Value->Value.u16, &((EFI_IFR_UINT16 *)OpCodeData)->Value, sizeof (UINT16));
- break;
-
- case EFI_IFR_UINT32_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
- CopyMem (&Value->Value.u32, &((EFI_IFR_UINT32 *)OpCodeData)->Value, sizeof (UINT32));
- break;
-
- case EFI_IFR_UINT64_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- CopyMem (&Value->Value.u64, &((EFI_IFR_UINT64 *)OpCodeData)->Value, sizeof (UINT64));
- break;
-
- case EFI_IFR_UNDEFINED_OP:
- Value->Type = EFI_IFR_TYPE_UNDEFINED;
- break;
-
- case EFI_IFR_VERSION_OP:
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
- Value->Value.u16 = EFI_IFR_SPECIFICATION_VERSION;
- break;
-
- default:
- break;
- }
-
- //
- // Create sub expression nested in MAP opcode
- //
- if ((CurrentExpression == NULL) && (MapScopeDepth > 0)) {
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- ASSERT (MapExpressionList != NULL);
- InsertTailList (MapExpressionList, &CurrentExpression->Link);
- if (Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
- }
-
- ASSERT (CurrentExpression != NULL);
- InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link);
- if (Operand == EFI_IFR_MAP_OP) {
- //
- // Store current Map Expression List.
- //
- if (MapExpressionList != NULL) {
- PushMapExpressionList (MapExpressionList);
- }
-
- //
- // Initialize new Map Expression List.
- //
- MapExpressionList = &ExpressionOpCode->MapExpressionList;
- InitializeListHead (MapExpressionList);
- //
- // Store current expression.
- //
- PushCurrentExpression (CurrentExpression);
- CurrentExpression = NULL;
- MapScopeDepth++;
- } else if (SingleOpCodeExpression) {
- //
- // There are two cases to indicate the end of an Expression:
- // for single OpCode expression: one Expression OpCode
- // for expression consists of more than one OpCode: EFI_IFR_END
- //
- SingleOpCodeExpression = FALSE;
-
- if (InScopeDisable && (CurrentForm == NULL)) {
- //
- // This is DisableIf expression for Form, it should be a constant expression
- //
- Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- OpCodeDisabled = IsTrue (&CurrentExpression->Result);
- }
-
- CurrentExpression = NULL;
- }
-
- continue;
- }
-
- //
- // Parse the Opcode
- //
- switch (Operand) {
- case EFI_IFR_FORM_SET_OP:
- //
- // Check the formset GUID
- //
- if (CompareMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *)OpCodeData)->Guid, sizeof (EFI_GUID)) != 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *)OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
- CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *)OpCodeData)->Help, sizeof (EFI_STRING_ID));
- FormSet->OpCode = (EFI_IFR_OP_HEADER *)OpCodeData;// save the opcode address of formset
-
- if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
- //
- // The formset OpCode contains ClassGuid
- //
- FormSet->NumberOfClassGuid = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
- CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID));
- }
-
- break;
-
- case EFI_IFR_FORM_OP:
- //
- // Create a new Form for this FormSet
- //
- CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
- ASSERT (CurrentForm != NULL);
- CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
- InitializeListHead (&CurrentForm->ExpressionListHead);
- InitializeListHead (&CurrentForm->StatementListHead);
- InitializeListHead (&CurrentForm->ConfigRequestHead);
- InitializeListHead (&CurrentForm->FormViewListHead);
-
- CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
- CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *)OpCodeData)->FormId, sizeof (UINT16));
- CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *)OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));
-
- ConditionalExprCount = GetConditionalExpressionCount (ExpressForm);
- if ( ConditionalExprCount > 0) {
- //
- // Form is inside of suppressif
- //
- CurrentForm->SuppressExpression = (FORM_EXPRESSION_LIST *)AllocatePool (
- (UINTN)(sizeof (FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof (FORM_EXPRESSION *)))
- );
- ASSERT (CurrentForm->SuppressExpression != NULL);
- CurrentForm->SuppressExpression->Count = (UINTN)ConditionalExprCount;
- CurrentForm->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
- CopyMem (CurrentForm->SuppressExpression->Expression, GetConditionalExpressionList (ExpressForm), (UINTN)(sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
- }
-
- if (Scope != 0) {
- //
- // Enter scope of a Form, suppressif will be used for Question or Option
- //
- SuppressForQuestion = TRUE;
- }
-
- //
- // Insert into Form list of this FormSet
- //
- InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
- break;
-
- case EFI_IFR_FORM_MAP_OP:
- //
- // Create a new Form for this FormSet
- //
- CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
- ASSERT (CurrentForm != NULL);
- CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
- InitializeListHead (&CurrentForm->ExpressionListHead);
- InitializeListHead (&CurrentForm->StatementListHead);
- InitializeListHead (&CurrentForm->ConfigRequestHead);
- InitializeListHead (&CurrentForm->FormViewListHead);
-
- CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *)OpCodeData)->FormId, sizeof (UINT16));
-
- MapMethod = (EFI_IFR_FORM_MAP_METHOD *)(OpCodeData + sizeof (EFI_IFR_FORM_MAP));
- //
- // FormMap Form must contain at least one Map Method.
- //
- if (((EFI_IFR_OP_HEADER *)OpCodeData)->Length < ((UINTN)(UINT8 *)(MapMethod + 1) - (UINTN)OpCodeData)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Try to find the standard form map method.
- //
- while (((UINTN)(UINT8 *)MapMethod - (UINTN)OpCodeData) < ((EFI_IFR_OP_HEADER *)OpCodeData)->Length) {
- if (CompareGuid ((EFI_GUID *)(VOID *)&MapMethod->MethodIdentifier, &gEfiHiiStandardFormGuid)) {
- CopyMem (&CurrentForm->FormTitle, &MapMethod->MethodTitle, sizeof (EFI_STRING_ID));
- CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
- break;
- }
-
- MapMethod++;
- }
-
- //
- // If the standard form map method is not found, the first map method title will be used.
- //
- if (CurrentForm->FormTitle == 0) {
- MapMethod = (EFI_IFR_FORM_MAP_METHOD *)(OpCodeData + sizeof (EFI_IFR_FORM_MAP));
- CopyMem (&CurrentForm->FormTitle, &MapMethod->MethodTitle, sizeof (EFI_STRING_ID));
- }
-
- ConditionalExprCount = GetConditionalExpressionCount (ExpressForm);
- if ( ConditionalExprCount > 0) {
- //
- // Form is inside of suppressif
- //
- CurrentForm->SuppressExpression = (FORM_EXPRESSION_LIST *)AllocatePool (
- (UINTN)(sizeof (FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof (FORM_EXPRESSION *)))
- );
- ASSERT (CurrentForm->SuppressExpression != NULL);
- CurrentForm->SuppressExpression->Count = (UINTN)ConditionalExprCount;
- CurrentForm->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
- CopyMem (CurrentForm->SuppressExpression->Expression, GetConditionalExpressionList (ExpressForm), (UINTN)(sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
- }
-
- if (Scope != 0) {
- //
- // Enter scope of a Form, suppressif will be used for Question or Option
- //
- SuppressForQuestion = TRUE;
- }
-
- //
- // Insert into Form list of this FormSet
- //
- InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
- break;
-
- //
- // Storage
- //
- case EFI_IFR_VARSTORE_OP:
- //
- // Create a buffer Storage for this FormSet
- //
- Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_BUFFER, OpCodeData);
- CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *)OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
- break;
-
- case EFI_IFR_VARSTORE_NAME_VALUE_OP:
- //
- // Create a name/value Storage for this FormSet
- //
- Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_NAME_VALUE, OpCodeData);
- CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *)OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
- break;
-
- case EFI_IFR_VARSTORE_EFI_OP:
- //
- // Create a EFI variable Storage for this FormSet
- //
- if (OpCodeLength < sizeof (EFI_IFR_VARSTORE_EFI)) {
- //
- // Create efi varstore with format follow UEFI spec before 2.3.1.
- //
- Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_EFI_VARIABLE, OpCodeData);
- } else {
- //
- // Create efi varstore with format follow UEFI spec 2.3.1 and later.
- //
- Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER, OpCodeData);
- }
-
- CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *)OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
- break;
-
- //
- // DefaultStore
- //
- case EFI_IFR_DEFAULTSTORE_OP:
- HaveInserted = FALSE;
- DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE));
- ASSERT (DefaultStore != NULL);
- DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE;
-
- CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *)OpCodeData)->DefaultId, sizeof (UINT16));
- CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *)OpCodeData)->DefaultName, sizeof (EFI_STRING_ID));
- //
- // Insert it to the DefaultStore list of this Formset with ascending order.
- //
- if (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
- DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
- while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
- PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultLink);
- DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
- if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) {
- InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link);
- HaveInserted = TRUE;
- break;
- }
- }
- }
-
- if (!HaveInserted) {
- InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link);
- }
-
- break;
-
- //
- // Statements
- //
- case EFI_IFR_SUBTITLE_OP:
- CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
-
- CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *)OpCodeData)->Flags;
- CurrentStatement->FakeQuestionId = mUsedQuestionId++;
- break;
-
- case EFI_IFR_TEXT_OP:
- CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
- CurrentStatement->FakeQuestionId = mUsedQuestionId++;
- CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *)OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
- break;
-
- case EFI_IFR_RESET_BUTTON_OP:
- CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
- CurrentStatement->FakeQuestionId = mUsedQuestionId++;
- CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *)OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
- break;
-
- //
- // Questions
- //
- case EFI_IFR_ACTION_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION;
-
- if (OpCodeLength == sizeof (EFI_IFR_ACTION_1)) {
- //
- // No QuestionConfig present, so no configuration string will be processed
- //
- CurrentStatement->QuestionConfig = 0;
- } else {
- CopyMem (&CurrentStatement->QuestionConfig, &((EFI_IFR_ACTION *)OpCodeData)->QuestionConfig, sizeof (EFI_STRING_ID));
- }
-
- break;
-
- case EFI_IFR_REF_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
- Value = &CurrentStatement->HiiValue;
- Value->Type = EFI_IFR_TYPE_REF;
- if (OpCodeLength >= sizeof (EFI_IFR_REF)) {
- CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *)OpCodeData)->FormId, sizeof (EFI_FORM_ID));
-
- if (OpCodeLength >= sizeof (EFI_IFR_REF2)) {
- CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
-
- if (OpCodeLength >= sizeof (EFI_IFR_REF3)) {
- CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *)OpCodeData)->FormSetId, sizeof (EFI_GUID));
-
- if (OpCodeLength >= sizeof (EFI_IFR_REF4)) {
- CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *)OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
- }
- }
- }
- }
-
- CurrentStatement->StorageWidth = (UINT16)sizeof (EFI_HII_REF);
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
- break;
-
- case EFI_IFR_ONE_OF_OP:
- case EFI_IFR_NUMERIC_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
-
- CurrentStatement->Flags = ((EFI_IFR_ONE_OF *)OpCodeData)->Flags;
- Value = &CurrentStatement->HiiValue;
-
- if (QuestionReferBitField) {
- //
- // Get the bit var store info (bit/byte offset, bit/byte offset)
- //
- CurrentStatement->QuestionReferToBitField = TRUE;
- CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
- CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
- CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
- TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
- CurrentStatement->StorageWidth = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1);
-
- //
- // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type)
- //
- CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MinValue;
- CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MaxValue;
- CurrentStatement->Step = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.Step;
-
- //
- // Update the Flag and type of Minimum/Maximum/Step according to the actual width of bit field,
- // in order to make Browser handle these question with bit varstore correctly.
- //
- ((EFI_IFR_NUMERIC *)OpCodeData)->Flags &= EDKII_IFR_DISPLAY_BIT;
- ((EFI_IFR_NUMERIC *)OpCodeData)->Flags >>= 2;
- switch (CurrentStatement->StorageWidth) {
- case 1:
- ((EFI_IFR_NUMERIC *)OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_8;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MinValue = (UINT8)CurrentStatement->Minimum;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MaxValue = (UINT8)CurrentStatement->Maximum;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.Step = (UINT8)CurrentStatement->Step;
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- break;
- case 2:
- ((EFI_IFR_NUMERIC *)OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_16;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MinValue = (UINT16)CurrentStatement->Minimum;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MaxValue = (UINT16)CurrentStatement->Maximum;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.Step = (UINT16)CurrentStatement->Step;
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
- break;
- case 3:
- case 4:
- ((EFI_IFR_NUMERIC *)OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_32;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MinValue = (UINT32)CurrentStatement->Minimum;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MaxValue = (UINT32)CurrentStatement->Maximum;
- ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.Step = (UINT32)CurrentStatement->Step;
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
- break;
- default:
- break;
- }
- } else {
- switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) {
- case EFI_IFR_NUMERIC_SIZE_1:
- CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MinValue;
- CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MaxValue;
- CurrentStatement->Step = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.Step;
- CurrentStatement->StorageWidth = (UINT16)sizeof (UINT8);
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
- break;
-
- case EFI_IFR_NUMERIC_SIZE_2:
- CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MinValue, sizeof (UINT16));
- CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MaxValue, sizeof (UINT16));
- CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.Step, sizeof (UINT16));
- CurrentStatement->StorageWidth = (UINT16)sizeof (UINT16);
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
- break;
-
- case EFI_IFR_NUMERIC_SIZE_4:
- CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MinValue, sizeof (UINT32));
- CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MaxValue, sizeof (UINT32));
- CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.Step, sizeof (UINT32));
- CurrentStatement->StorageWidth = (UINT16)sizeof (UINT32);
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
- break;
-
- case EFI_IFR_NUMERIC_SIZE_8:
- CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u64.MinValue, sizeof (UINT64));
- CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u64.MaxValue, sizeof (UINT64));
- CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u64.Step, sizeof (UINT64));
- CurrentStatement->StorageWidth = (UINT16)sizeof (UINT64);
- Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
- break;
-
- default:
- break;
- }
- }
-
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
-
- if ((Operand == EFI_IFR_ONE_OF_OP) && (Scope != 0)) {
- SuppressForOption = TRUE;
- }
-
- break;
-
- case EFI_IFR_ORDERED_LIST_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
-
- CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *)OpCodeData)->Flags;
- CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *)OpCodeData)->MaxContainers;
-
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER;
- CurrentStatement->BufferValue = NULL;
-
- if (Scope != 0) {
- SuppressForOption = TRUE;
- }
-
- break;
-
- case EFI_IFR_CHECKBOX_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
-
- CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *)OpCodeData)->Flags;
- CurrentStatement->StorageWidth = (UINT16)sizeof (BOOLEAN);
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN;
-
- if (QuestionReferBitField) {
- //
- // Get the bit var store info (bit/byte offset, bit/byte offset)
- //
- CurrentStatement->QuestionReferToBitField = TRUE;
- CurrentStatement->BitStorageWidth = 1;
- CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
- CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
- TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
- CurrentStatement->StorageWidth = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1);
- }
-
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
-
- break;
-
- case EFI_IFR_STRING_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
- //
- // MinSize is the minimum number of characters that can be accepted for this opcode,
- // MaxSize is the maximum number of characters that can be accepted for this opcode.
- // The characters are stored as Unicode, so the storage width should multiply 2.
- //
- CurrentStatement->Minimum = ((EFI_IFR_STRING *)OpCodeData)->MinSize;
- CurrentStatement->Maximum = ((EFI_IFR_STRING *)OpCodeData)->MaxSize;
- CurrentStatement->StorageWidth = (UINT16)((UINTN)CurrentStatement->Maximum * sizeof (CHAR16));
- CurrentStatement->Flags = ((EFI_IFR_STRING *)OpCodeData)->Flags;
-
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
- CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16));
- CurrentStatement->HiiValue.Value.string = NewString ((CHAR16 *)CurrentStatement->BufferValue, FormSet->HiiHandle);
-
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
- break;
-
- case EFI_IFR_PASSWORD_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
- //
- // MinSize is the minimum number of characters that can be accepted for this opcode,
- // MaxSize is the maximum number of characters that can be accepted for this opcode.
- // The characters are stored as Unicode, so the storage width should multiply 2.
- //
- CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *)OpCodeData)->MinSize, sizeof (UINT16));
- CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *)OpCodeData)->MaxSize, sizeof (UINT16));
- CurrentStatement->StorageWidth = (UINT16)((UINTN)CurrentStatement->Maximum * sizeof (CHAR16));
-
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
- CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16)));
- CurrentStatement->HiiValue.Value.string = NewString ((CHAR16 *)CurrentStatement->BufferValue, FormSet->HiiHandle);
-
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
- break;
-
- case EFI_IFR_DATE_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
-
- CurrentStatement->Flags = ((EFI_IFR_DATE *)OpCodeData)->Flags;
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE;
-
- if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) {
- CurrentStatement->StorageWidth = (UINT16)sizeof (EFI_HII_DATE);
-
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
- } else {
- //
- // Don't assign storage for RTC type of date/time
- //
- CurrentStatement->Storage = NULL;
- CurrentStatement->StorageWidth = 0;
- }
-
- break;
-
- case EFI_IFR_TIME_OP:
- CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
- ASSERT (CurrentStatement != NULL);
-
- CurrentStatement->Flags = ((EFI_IFR_TIME *)OpCodeData)->Flags;
- CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME;
-
- if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) {
- CurrentStatement->StorageWidth = (UINT16)sizeof (EFI_HII_TIME);
-
- InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
- } else {
- //
- // Don't assign storage for RTC type of date/time
- //
- CurrentStatement->Storage = NULL;
- CurrentStatement->StorageWidth = 0;
- }
-
- break;
-
- //
- // Default
- //
- case EFI_IFR_DEFAULT_OP:
- //
- // EFI_IFR_DEFAULT appear in scope of a Question,
- // It creates a default value for the current question.
- // A Question may have more than one Default value which have different default types.
- //
- CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
- ASSERT (CurrentDefault != NULL);
- CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
-
- CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *)OpCodeData)->Type;
- CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *)OpCodeData)->DefaultId, sizeof (UINT16));
- if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) {
- CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF (EFI_IFR_DEFAULT, Value));
- CurrentDefault->Value.Buffer = AllocateCopyPool (CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *)OpCodeData)->Value);
- ASSERT (CurrentDefault->Value.Buffer != NULL);
- } else {
- CopyMem (&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *)OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_DEFAULT, Value));
- ExtendValueToU64 (&CurrentDefault->Value);
- }
-
- //
- // Insert to Default Value list of current Question
- //
- InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link);
-
- if (Scope != 0) {
- InScopeDefault = TRUE;
- }
-
- break;
-
- //
- // Option
- //
- case EFI_IFR_ONE_OF_OPTION_OP:
- ASSERT (ParentStatement != NULL);
- if ((ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) {
- //
- // It's keep the default value for ordered list opcode.
- //
- CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
- ASSERT (CurrentDefault != NULL);
- CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
-
- CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER;
- if ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
- CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
- } else {
- CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
- }
-
- CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
- CurrentDefault->Value.Buffer = AllocateCopyPool (CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value);
- ASSERT (CurrentDefault->Value.Buffer != NULL);
-
- //
- // Insert to Default Value list of current Question
- //
- InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link);
- break;
- }
-
- //
- // EFI_IFR_ONE_OF_OPTION appear in scope of a Question.
- // It create a selection for use in current Question.
- //
- CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
- ASSERT (CurrentOption != NULL);
- CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;
- CurrentOption->OpCode = (EFI_IFR_ONE_OF_OPTION *)OpCodeData;
-
- CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags;
- CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Type;
- CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Option, sizeof (EFI_STRING_ID));
- CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
- ExtendValueToU64 (&CurrentOption->Value);
-
- ConditionalExprCount = GetConditionalExpressionCount (ExpressOption);
- if ( ConditionalExprCount > 0) {
- //
- // Form is inside of suppressif
- //
- CurrentOption->SuppressExpression = (FORM_EXPRESSION_LIST *)AllocatePool (
- (UINTN)(sizeof (FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof (FORM_EXPRESSION *)))
- );
- ASSERT (CurrentOption->SuppressExpression != NULL);
- CurrentOption->SuppressExpression->Count = (UINTN)ConditionalExprCount;
- CurrentOption->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
- CopyMem (CurrentOption->SuppressExpression->Expression, GetConditionalExpressionList (ExpressOption), (UINTN)(sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
- }
-
- //
- // Insert to Option list of current Question
- //
- InsertTailList (&ParentStatement->OptionListHead, &CurrentOption->Link);
- //
- // Now we know the Storage width of nested Ordered List
- //
- if ((ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (ParentStatement->BufferValue == NULL)) {
- Width = 1;
- switch (CurrentOption->Value.Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- Width = 1;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- Width = 2;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- Width = 4;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- Width = 8;
- break;
-
- default:
- //
- // Invalid type for Ordered List
- //
- break;
- }
-
- ParentStatement->StorageWidth = (UINT16)(ParentStatement->MaxContainers * Width);
- ParentStatement->BufferValue = AllocateZeroPool (ParentStatement->StorageWidth);
- ParentStatement->ValueType = CurrentOption->Value.Type;
- if (ParentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
- ParentStatement->HiiValue.Buffer = ParentStatement->BufferValue;
- ParentStatement->HiiValue.BufferLen = ParentStatement->StorageWidth;
- }
-
- InitializeRequestElement (FormSet, ParentStatement, CurrentForm);
- }
-
- break;
-
- //
- // Conditional
- //
- case EFI_IFR_NO_SUBMIT_IF_OP:
- case EFI_IFR_INCONSISTENT_IF_OP:
- //
- // Create an Expression node
- //
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *)OpCodeData)->Error, sizeof (EFI_STRING_ID));
-
- if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {
- CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;
- InsertTailList (&ParentStatement->NoSubmitListHead, &CurrentExpression->Link);
- } else {
- CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;
- InsertTailList (&ParentStatement->InconsistentListHead, &CurrentExpression->Link);
- }
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_WARNING_IF_OP:
- //
- // Create an Expression node
- //
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *)OpCodeData)->Warning, sizeof (EFI_STRING_ID));
- CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *)OpCodeData)->TimeOut;
- CurrentExpression->Type = EFI_HII_EXPRESSION_WARNING_IF;
- InsertTailList (&ParentStatement->WarningListHead, &CurrentExpression->Link);
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_SUPPRESS_IF_OP:
- //
- // Question and Option will appear in scope of this OpCode
- //
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;
-
- if (CurrentForm == NULL) {
- InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link);
- } else {
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
- }
-
- if (SuppressForOption) {
- PushConditionalExpression (CurrentExpression, ExpressOption);
- } else if (SuppressForQuestion) {
- PushConditionalExpression (CurrentExpression, ExpressStatement);
- } else {
- PushConditionalExpression (CurrentExpression, ExpressForm);
- }
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_GRAY_OUT_IF_OP:
- //
- // Questions will appear in scope of this OpCode
- //
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
- PushConditionalExpression (CurrentExpression, ExpressStatement);
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_DISABLE_IF_OP:
- //
- // The DisableIf expression should only rely on constant, so it could be
- // evaluated at initialization and it will not be queued
- //
- CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
- ASSERT (CurrentExpression != NULL);
- CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE;
- CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF;
- InitializeListHead (&CurrentExpression->OpCodeListHead);
-
- if (CurrentForm != NULL) {
- //
- // This is DisableIf for Question, enqueue it to Form expression list
- //
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
- PushConditionalExpression (CurrentExpression, ExpressStatement);
- }
-
- OpCodeDisabled = FALSE;
- InScopeDisable = TRUE;
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- //
- // Expression
- //
- case EFI_IFR_VALUE_OP:
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
-
- if (InScopeDefault) {
- //
- // Used for default (EFI_IFR_DEFAULT)
- //
- CurrentDefault->ValueExpression = CurrentExpression;
- } else {
- //
- // If used for a question, then the question will be read-only
- //
- //
- // Make sure CurrentStatement is not NULL.
- // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
- // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
- //
- ASSERT (ParentStatement != NULL);
- ParentStatement->ValueExpression = CurrentExpression;
- }
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_RULE_OP:
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;
-
- CurrentExpression->RuleId = ((EFI_IFR_RULE *)OpCodeData)->RuleId;
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_READ_OP:
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CurrentExpression->Type = EFI_HII_EXPRESSION_READ;
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
-
- //
- // Make sure CurrentStatement is not NULL.
- // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
- // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
- //
- ASSERT (ParentStatement != NULL);
- ParentStatement->ReadExpression = CurrentExpression;
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- case EFI_IFR_WRITE_OP:
- CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
- CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;
- InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
-
- //
- // Make sure CurrentStatement is not NULL.
- // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
- // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
- //
- ASSERT (ParentStatement != NULL);
- ParentStatement->WriteExpression = CurrentExpression;
-
- //
- // Take a look at next OpCode to see whether current expression consists
- // of single OpCode
- //
- if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) {
- SingleOpCodeExpression = TRUE;
- }
-
- break;
-
- //
- // Image
- //
- case EFI_IFR_IMAGE_OP:
- //
- // Get ScopeOpcode from top of stack
- //
- PopScope (&ScopeOpCode);
- PushScope (ScopeOpCode);
-
- switch (ScopeOpCode) {
- case EFI_IFR_FORM_SET_OP:
- ImageId = &FormSet->ImageId;
- break;
-
- case EFI_IFR_FORM_OP:
- case EFI_IFR_FORM_MAP_OP:
- ASSERT (CurrentForm != NULL);
- ImageId = &CurrentForm->ImageId;
- break;
-
- case EFI_IFR_ONE_OF_OPTION_OP:
- ASSERT (CurrentOption != NULL);
- ImageId = &CurrentOption->ImageId;
- break;
-
- default:
- //
- // Make sure CurrentStatement is not NULL.
- // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
- // file is wrongly generated by tools such as VFR Compiler.
- //
- ASSERT (ParentStatement != NULL);
- ImageId = &ParentStatement->ImageId;
- break;
- }
-
- ASSERT (ImageId != NULL);
- CopyMem (ImageId, &((EFI_IFR_IMAGE *)OpCodeData)->Id, sizeof (EFI_IMAGE_ID));
- break;
-
- //
- // Refresh
- //
- case EFI_IFR_REFRESH_OP:
- ASSERT (ParentStatement != NULL);
- ParentStatement->RefreshInterval = ((EFI_IFR_REFRESH *)OpCodeData)->RefreshInterval;
- break;
-
- //
- // Refresh guid.
- //
- case EFI_IFR_REFRESH_ID_OP:
- //
- // Get ScopeOpcode from top of stack
- //
- PopScope (&ScopeOpCode);
- PushScope (ScopeOpCode);
-
- switch (ScopeOpCode) {
- case EFI_IFR_FORM_OP:
- case EFI_IFR_FORM_MAP_OP:
- ASSERT (CurrentForm != NULL);
- CopyMem (&CurrentForm->RefreshGuid, &((EFI_IFR_REFRESH_ID *)OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID));
- break;
-
- default:
- ASSERT (ParentStatement != NULL);
- CopyMem (&ParentStatement->RefreshGuid, &((EFI_IFR_REFRESH_ID *)OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID));
- break;
- }
-
- break;
-
- //
- // Modal tag
- //
- case EFI_IFR_MODAL_TAG_OP:
- ASSERT (CurrentForm != NULL);
- CurrentForm->ModalForm = TRUE;
- break;
-
- //
- // Lock tag, used by form and statement.
- //
- case EFI_IFR_LOCKED_OP:
- //
- // Get ScopeOpcode from top of stack
- //
- PopScope (&ScopeOpCode);
- PushScope (ScopeOpCode);
- switch (ScopeOpCode) {
- case EFI_IFR_FORM_OP:
- case EFI_IFR_FORM_MAP_OP:
- ASSERT (CurrentForm != NULL);
- CurrentForm->Locked = TRUE;
- break;
-
- default:
- ASSERT (ParentStatement != NULL);
- ParentStatement->Locked = TRUE;
- }
-
- break;
-
- //
- // Vendor specific
- //
- case EFI_IFR_GUID_OP:
- CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
- if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
- Scope = 0;
- QuestionReferBitField = TRUE;
- }
-
- break;
-
- //
- // Scope End
- //
- case EFI_IFR_END_OP:
- QuestionReferBitField = FALSE;
- Status = PopScope (&ScopeOpCode);
- if (EFI_ERROR (Status)) {
- ResetScopeStack ();
- return Status;
- }
-
- //
- // Parent statement end tag found, update ParentStatement info.
- //
- if (IsStatementOpCode (ScopeOpCode) && (ParentStatement != NULL) && (ParentStatement->Operand == ScopeOpCode)) {
- ParentStatement = ParentStatement->ParentStatement;
- }
-
- switch (ScopeOpCode) {
- case EFI_IFR_FORM_SET_OP:
- //
- // End of FormSet, update FormSet IFR binary length
- // to stop parsing substantial OpCodes
- //
- FormSet->IfrBinaryLength = OpCodeOffset;
- break;
-
- case EFI_IFR_FORM_OP:
- case EFI_IFR_FORM_MAP_OP:
- //
- // End of Form
- //
- CurrentForm = NULL;
- SuppressForQuestion = FALSE;
- break;
-
- case EFI_IFR_ONE_OF_OPTION_OP:
- //
- // End of Option
- //
- CurrentOption = NULL;
- break;
-
- case EFI_IFR_NO_SUBMIT_IF_OP:
- case EFI_IFR_INCONSISTENT_IF_OP:
- case EFI_IFR_WARNING_IF_OP:
- //
- // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF
- //
- break;
-
- case EFI_IFR_SUPPRESS_IF_OP:
- if (SuppressForOption) {
- PopConditionalExpression (ExpressOption);
- } else if (SuppressForQuestion) {
- PopConditionalExpression (ExpressStatement);
- } else {
- PopConditionalExpression (ExpressForm);
- }
-
- break;
-
- case EFI_IFR_GRAY_OUT_IF_OP:
- PopConditionalExpression (ExpressStatement);
- break;
-
- case EFI_IFR_DISABLE_IF_OP:
- if (CurrentForm != NULL) {
- PopConditionalExpression (ExpressStatement);
- }
-
- InScopeDisable = FALSE;
- OpCodeDisabled = FALSE;
- break;
-
- case EFI_IFR_ONE_OF_OP:
- case EFI_IFR_ORDERED_LIST_OP:
- SuppressForOption = FALSE;
- break;
-
- case EFI_IFR_DEFAULT_OP:
- InScopeDefault = FALSE;
- break;
-
- case EFI_IFR_MAP_OP:
- //
- // Get current Map Expression List.
- //
- Status = PopMapExpressionList ((VOID **)&MapExpressionList);
- if (Status == EFI_ACCESS_DENIED) {
- MapExpressionList = NULL;
- }
-
- //
- // Get current expression.
- //
- Status = PopCurrentExpression ((VOID **)&CurrentExpression);
- ASSERT_EFI_ERROR (Status);
- ASSERT (MapScopeDepth > 0);
- MapScopeDepth--;
- break;
-
- default:
- if (IsExpressionOpCode (ScopeOpCode)) {
- if (InScopeDisable && (CurrentForm == NULL)) {
- //
- // This is DisableIf expression for Form, it should be a constant expression
- //
- ASSERT (CurrentExpression != NULL);
- Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- OpCodeDisabled = IsTrue (&CurrentExpression->Result);
-
- //
- // DisableIf Expression is only used once and not queued, free it
- //
- DestroyExpression (CurrentExpression);
- }
-
- //
- // End of current Expression
- //
- CurrentExpression = NULL;
- }
-
- break;
- }
-
- break;
-
- default:
- break;
- }
-
- if (IsStatementOpCode (Operand)) {
- CurrentStatement->ParentStatement = ParentStatement;
- if (Scope != 0) {
- //
- // Scope != 0, other statements or options may nest in this statement.
- // Update the ParentStatement info.
- //
- ParentStatement = CurrentStatement;
- }
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file +Parser for IFR binary encoding. + +Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR> +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. <RequestElement> ::= '&'<BlockName> | '&'<Label> + + @param FormSet Pointer of the current FormSet. + @param Question The Question to be initialized. + @param Form Pointer of the current form. + + @retval EFI_SUCCESS Function success. + @retval EFI_INVALID_PARAMETER No storage associated with the Question. + +**/ +EFI_STATUS +InitializeRequestElement ( + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN OUT FORM_BROWSER_FORM *Form + ) +{ + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormsetStorage; + UINTN StrLen; + UINTN StringSize; + CHAR16 *NewStr; + CHAR16 RequestElement[30]; + LIST_ENTRY *Link; + BOOLEAN Find; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + UINTN MaxLen; + + Storage = Question->Storage; + if (Storage == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + // + // <ConfigRequest> is unnecessary for EFI variable storage, + // GetVariable()/SetVariable() will be used to retrieve/save values + // + return EFI_SUCCESS; + } + + // + // Prepare <RequestElement> + // + if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) + { + StrLen = UnicodeSPrint ( + RequestElement, + 30 * sizeof (CHAR16), + L"&OFFSET=%04x&WIDTH=%04x", + Question->VarStoreInfo.VarOffset, + Question->StorageWidth + ); + HiiToLower (RequestElement); + Question->BlockName = AllocateCopyPool ((StrLen + 1) * sizeof (CHAR16), RequestElement); + } else { + StrLen = UnicodeSPrint (RequestElement, 30 * sizeof (CHAR16), L"&%s", Question->VariableName); + } + + if ((Question->Operand == EFI_IFR_PASSWORD_OP) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) { + // + // Password with CALLBACK flag is stored in encoded format, + // so don't need to append it to <ConfigRequest> + // + return EFI_SUCCESS; + } + + // + // Find Formset Storage for this Question + // + FormsetStorage = GetFstStgFromVarId (FormSet, Question->VarStoreId); + ASSERT (FormsetStorage != NULL); + StringSize = (FormsetStorage->ConfigRequest != NULL) ? StrSize (FormsetStorage->ConfigRequest) : sizeof (CHAR16); + MaxLen = StringSize / sizeof (CHAR16) + FormsetStorage->SpareStrLen; + + // + // Append <RequestElement> to <ConfigRequest> + // + if (StrLen > FormsetStorage->SpareStrLen) { + // + // Old String buffer is not sufficient for RequestElement, allocate a new one + // + MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL; + NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (NewStr != NULL); + if (FormsetStorage->ConfigRequest != NULL) { + CopyMem (NewStr, FormsetStorage->ConfigRequest, StringSize); + FreePool (FormsetStorage->ConfigRequest); + } + + FormsetStorage->ConfigRequest = NewStr; + FormsetStorage->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; + } + + StrCatS (FormsetStorage->ConfigRequest, MaxLen, RequestElement); + FormsetStorage->ElementCount++; + FormsetStorage->SpareStrLen -= StrLen; + + // + // Update the Config Request info saved in the form. + // + ConfigInfo = NULL; + Find = FALSE; + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + + if ((ConfigInfo != NULL) && (ConfigInfo->Storage == FormsetStorage->BrowserStorage)) { + Find = TRUE; + break; + } + + Link = GetNextNode (&Form->ConfigRequestHead, Link); + } + + if (!Find) { + ConfigInfo = AllocateZeroPool (sizeof (FORM_BROWSER_CONFIG_REQUEST)); + ASSERT (ConfigInfo != NULL); + ConfigInfo->Signature = FORM_BROWSER_CONFIG_REQUEST_SIGNATURE; + ConfigInfo->ConfigRequest = AllocateCopyPool (StrSize (FormsetStorage->ConfigHdr), FormsetStorage->ConfigHdr); + ASSERT (ConfigInfo->ConfigRequest != NULL); + ConfigInfo->SpareStrLen = 0; + ConfigInfo->Storage = FormsetStorage->BrowserStorage; + InsertTailList (&Form->ConfigRequestHead, &ConfigInfo->Link); + } + + StringSize = (ConfigInfo->ConfigRequest != NULL) ? StrSize (ConfigInfo->ConfigRequest) : sizeof (CHAR16); + MaxLen = StringSize / sizeof (CHAR16) + ConfigInfo->SpareStrLen; + + // + // Append <RequestElement> to <ConfigRequest> + // + if (StrLen > ConfigInfo->SpareStrLen) { + // + // Old String buffer is not sufficient for RequestElement, allocate a new one + // + MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL; + NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (NewStr != NULL); + if (ConfigInfo->ConfigRequest != NULL) { + CopyMem (NewStr, ConfigInfo->ConfigRequest, StringSize); + FreePool (ConfigInfo->ConfigRequest); + } + + ConfigInfo->ConfigRequest = NewStr; + ConfigInfo->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; + } + + StrCatS (ConfigInfo->ConfigRequest, MaxLen, RequestElement); + ConfigInfo->ElementCount++; + ConfigInfo->SpareStrLen -= StrLen; + return EFI_SUCCESS; +} + +/** + Free resources of a Expression. + + @param FormSet Pointer of the Expression + +**/ +VOID +DestroyExpression ( + IN FORM_EXPRESSION *Expression + ) +{ + LIST_ENTRY *Link; + EXPRESSION_OPCODE *OpCode; + LIST_ENTRY *SubExpressionLink; + FORM_EXPRESSION *SubExpression; + + while (!IsListEmpty (&Expression->OpCodeListHead)) { + Link = GetFirstNode (&Expression->OpCodeListHead); + OpCode = EXPRESSION_OPCODE_FROM_LINK (Link); + RemoveEntryList (&OpCode->Link); + + if (OpCode->ValueList != NULL) { + FreePool (OpCode->ValueList); + } + + if (OpCode->ValueName != NULL) { + FreePool (OpCode->ValueName); + } + + if (OpCode->MapExpressionList.ForwardLink != NULL) { + while (!IsListEmpty (&OpCode->MapExpressionList)) { + SubExpressionLink = GetFirstNode (&OpCode->MapExpressionList); + SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink); + RemoveEntryList (&SubExpression->Link); + DestroyExpression (SubExpression); + } + } + } + + // + // Free this Expression + // + FreePool (Expression); +} + +/** + Free resources of a storage. + + @param Storage Pointer of the storage + +**/ +VOID +DestroyStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + if (Storage == NULL) { + return; + } + + if (Storage->ConfigRequest != NULL) { + FreePool (Storage->ConfigRequest); + } + + FreePool (Storage); +} + +/** + Free resources of a Statement. + + @param FormSet Pointer of the FormSet + @param Statement Pointer of the Statement + +**/ +VOID +DestroyStatement ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_STATEMENT *Statement + ) +{ + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + FORM_EXPRESSION *Expression; + + // + // Free Default value List + // + while (!IsListEmpty (&Statement->DefaultListHead)) { + Link = GetFirstNode (&Statement->DefaultListHead); + Default = QUESTION_DEFAULT_FROM_LINK (Link); + RemoveEntryList (&Default->Link); + + if (Default->Value.Buffer != NULL) { + FreePool (Default->Value.Buffer); + } + + FreePool (Default); + } + + // + // Free Options List + // + while (!IsListEmpty (&Statement->OptionListHead)) { + Link = GetFirstNode (&Statement->OptionListHead); + Option = QUESTION_OPTION_FROM_LINK (Link); + if (Option->SuppressExpression != NULL) { + FreePool (Option->SuppressExpression); + } + + RemoveEntryList (&Option->Link); + + FreePool (Option); + } + + // + // Free Inconsistent List + // + while (!IsListEmpty (&Statement->InconsistentListHead)) { + Link = GetFirstNode (&Statement->InconsistentListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free NoSubmit List + // + while (!IsListEmpty (&Statement->NoSubmitListHead)) { + Link = GetFirstNode (&Statement->NoSubmitListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free WarningIf List + // + while (!IsListEmpty (&Statement->WarningListHead)) { + Link = GetFirstNode (&Statement->WarningListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + if (Statement->Expression != NULL) { + FreePool (Statement->Expression); + } + + if (Statement->VariableName != NULL) { + FreePool (Statement->VariableName); + } + + if (Statement->BlockName != NULL) { + FreePool (Statement->BlockName); + } + + if (Statement->BufferValue != NULL) { + FreePool (Statement->BufferValue); + } + + if ((Statement->Operand == EFI_IFR_STRING_OP) || (Statement->Operand == EFI_IFR_PASSWORD_OP)) { + DeleteString (Statement->HiiValue.Value.string, FormSet->HiiHandle); + } +} + +/** + Free resources of a Form. + + @param FormSet Pointer of the FormSet + @param Form Pointer of the Form. + +**/ +VOID +DestroyForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + FORM_BROWSER_STATEMENT *Statement; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + + // + // Free Form Expressions + // + while (!IsListEmpty (&Form->ExpressionListHead)) { + Link = GetFirstNode (&Form->ExpressionListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free Statements/Questions + // + while (!IsListEmpty (&Form->StatementListHead)) { + Link = GetFirstNode (&Form->StatementListHead); + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + RemoveEntryList (&Statement->Link); + + DestroyStatement (FormSet, Statement); + } + + // + // Free ConfigRequest string. + // + while (!IsListEmpty (&Form->ConfigRequestHead)) { + Link = GetFirstNode (&Form->ConfigRequestHead); + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + RemoveEntryList (&ConfigInfo->Link); + + FreePool (ConfigInfo->ConfigRequest); + FreePool (ConfigInfo); + } + + if (Form->SuppressExpression != NULL) { + FreePool (Form->SuppressExpression); + } + + UiFreeMenuList (&Form->FormViewListHead); + + // + // Free this Form + // + FreePool (Form); +} + +/** + Free resources allocated for a FormSet. + + @param FormSet Pointer of the FormSet + +**/ +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORMSET_DEFAULTSTORE *DefaultStore; + FORM_EXPRESSION *Expression; + FORM_BROWSER_FORM *Form; + + if (FormSet->IfrBinaryData == NULL) { + // + // Uninitialized FormSet + // + FreePool (FormSet); + return; + } + + // + // Free IFR binary buffer + // + FreePool (FormSet->IfrBinaryData); + + // + // Free FormSet Storage + // + if (FormSet->StorageListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->StorageListHead)) { + Link = GetFirstNode (&FormSet->StorageListHead); + Storage = FORMSET_STORAGE_FROM_LINK (Link); + RemoveEntryList (&Storage->Link); + + DestroyStorage (Storage); + } + } + + // + // Free FormSet Default Store + // + if (FormSet->DefaultStoreListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->DefaultStoreListHead)) { + Link = GetFirstNode (&FormSet->DefaultStoreListHead); + DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link); + RemoveEntryList (&DefaultStore->Link); + + FreePool (DefaultStore); + } + } + + // + // Free Formset Expressions + // + while (!IsListEmpty (&FormSet->ExpressionListHead)) { + Link = GetFirstNode (&FormSet->ExpressionListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free Forms + // + if (FormSet->FormListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->FormListHead)) { + Link = GetFirstNode (&FormSet->FormListHead); + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + RemoveEntryList (&Form->Link); + + DestroyForm (FormSet, Form); + } + } + + if (FormSet->StatementBuffer != NULL) { + FreePool (FormSet->StatementBuffer); + } + + if (FormSet->ExpressionBuffer != NULL) { + FreePool (FormSet->ExpressionBuffer); + } + + FreePool (FormSet); +} + +/** + Tell whether this Operand is an Expression OpCode or not + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Expression OpCode. + @retval FALSE Not an Expression OpCode. + +**/ +BOOLEAN +IsExpressionOpCode ( + IN UINT8 Operand + ) +{ + if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) || + ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP)) || + ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) || + (Operand == EFI_IFR_CATENATE_OP) || + (Operand == EFI_IFR_TO_LOWER_OP) || + (Operand == EFI_IFR_TO_UPPER_OP) || + (Operand == EFI_IFR_MAP_OP) || + (Operand == EFI_IFR_VERSION_OP) || + (Operand == EFI_IFR_SECURITY_OP) || + (Operand == EFI_IFR_MATCH2_OP)) + { + return TRUE; + } else { + return FALSE; + } +} + +/** + Tell whether this Operand is an Statement OpCode. + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Statement OpCode. + @retval FALSE Not an Statement OpCode. + +**/ +BOOLEAN +IsStatementOpCode ( + IN UINT8 Operand + ) +{ + if ((Operand == EFI_IFR_SUBTITLE_OP) || + (Operand == EFI_IFR_TEXT_OP) || + (Operand == EFI_IFR_RESET_BUTTON_OP) || + (Operand == EFI_IFR_REF_OP) || + (Operand == EFI_IFR_ACTION_OP) || + (Operand == EFI_IFR_NUMERIC_OP) || + (Operand == EFI_IFR_ORDERED_LIST_OP) || + (Operand == EFI_IFR_CHECKBOX_OP) || + (Operand == EFI_IFR_STRING_OP) || + (Operand == EFI_IFR_PASSWORD_OP) || + (Operand == EFI_IFR_DATE_OP) || + (Operand == EFI_IFR_TIME_OP) || + (Operand == EFI_IFR_GUID_OP) || + (Operand == EFI_IFR_ONE_OF_OP)) + { + return TRUE; + } else { + return FALSE; + } +} + +/** + Tell whether this Operand is an known OpCode. + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Statement OpCode. + @retval FALSE Not an Statement OpCode. + +**/ +BOOLEAN +IsUnKnownOpCode ( + IN UINT8 Operand + ) +{ + return Operand > EFI_IFR_MATCH2_OP ? TRUE : FALSE; +} + +/** + Calculate number of Statemens(Questions) and Expression OpCodes. + + @param FormSet The FormSet to be counted. + @param NumberOfStatement Number of Statemens(Questions) + @param NumberOfExpression Number of Expression OpCodes + +**/ +VOID +CountOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT UINTN *NumberOfStatement, + OUT UINTN *NumberOfExpression + ) +{ + UINTN StatementCount; + UINTN ExpressionCount; + UINT8 *OpCodeData; + UINTN Offset; + UINTN OpCodeLen; + + Offset = 0; + StatementCount = 0; + ExpressionCount = 0; + + while (Offset < FormSet->IfrBinaryLength) { + OpCodeData = FormSet->IfrBinaryData + Offset; + OpCodeLen = ((EFI_IFR_OP_HEADER *)OpCodeData)->Length; + Offset += OpCodeLen; + + if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode)) { + ExpressionCount++; + } else { + StatementCount++; + } + } + + *NumberOfStatement = StatementCount; + *NumberOfExpression = ExpressionCount; +} + +/** + Parse opcodes in the formset IFR binary. + + @param FormSet Pointer of the FormSet data structure. + + @retval EFI_SUCCESS Opcode parse success. + @retval Other Opcode parse fail. + +**/ +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + FORM_BROWSER_FORM *CurrentForm; + FORM_BROWSER_STATEMENT *CurrentStatement; + FORM_BROWSER_STATEMENT *ParentStatement; + EXPRESSION_OPCODE *ExpressionOpCode; + FORM_EXPRESSION *CurrentExpression; + UINT8 Operand; + UINT8 Scope; + UINTN OpCodeOffset; + UINTN OpCodeLength; + UINT8 *OpCodeData; + UINT8 ScopeOpCode; + FORMSET_STORAGE *Storage; + FORMSET_DEFAULTSTORE *DefaultStore; + QUESTION_DEFAULT *CurrentDefault; + QUESTION_OPTION *CurrentOption; + UINT8 Width; + UINTN NumberOfStatement; + UINTN NumberOfExpression; + EFI_IMAGE_ID *ImageId; + BOOLEAN SuppressForQuestion; + BOOLEAN SuppressForOption; + UINT16 DepthOfDisable; + BOOLEAN OpCodeDisabled; + BOOLEAN SingleOpCodeExpression; + BOOLEAN InScopeDefault; + EFI_HII_VALUE *Value; + EFI_IFR_FORM_MAP_METHOD *MapMethod; + UINT8 MapScopeDepth; + LIST_ENTRY *Link; + FORMSET_STORAGE *VarStorage; + LIST_ENTRY *MapExpressionList; + EFI_VARSTORE_ID TempVarstoreId; + BOOLEAN InScopeDisable; + INTN ConditionalExprCount; + BOOLEAN InUnknownScope; + UINT8 UnknownDepth; + FORMSET_DEFAULTSTORE *PreDefaultStore; + LIST_ENTRY *DefaultLink; + BOOLEAN HaveInserted; + UINT16 TotalBits; + BOOLEAN QuestionReferBitField; + + SuppressForQuestion = FALSE; + SuppressForOption = FALSE; + InScopeDisable = FALSE; + DepthOfDisable = 0; + OpCodeDisabled = FALSE; + SingleOpCodeExpression = FALSE; + InScopeDefault = FALSE; + CurrentExpression = NULL; + CurrentDefault = NULL; + CurrentOption = NULL; + ImageId = NULL; + MapMethod = NULL; + MapScopeDepth = 0; + Link = NULL; + VarStorage = NULL; + MapExpressionList = NULL; + TempVarstoreId = 0; + ConditionalExprCount = 0; + InUnknownScope = FALSE; + UnknownDepth = 0; + QuestionReferBitField = FALSE; + + // + // Get the number of Statements and Expressions + // + CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression); + + mStatementIndex = 0; + mUsedQuestionId = 1; + FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT)); + if (FormSet->StatementBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mExpressionOpCodeIndex = 0; + FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE)); + if (FormSet->ExpressionBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&FormSet->StatementListOSF); + InitializeListHead (&FormSet->StorageListHead); + InitializeListHead (&FormSet->SaveFailStorageListHead); + InitializeListHead (&FormSet->DefaultStoreListHead); + InitializeListHead (&FormSet->FormListHead); + InitializeListHead (&FormSet->ExpressionListHead); + ResetCurrentExpressionStack (); + ResetMapExpressionListStack (); + + CurrentForm = NULL; + CurrentStatement = NULL; + ParentStatement = NULL; + + ResetScopeStack (); + + OpCodeOffset = 0; + while (OpCodeOffset < FormSet->IfrBinaryLength) { + OpCodeData = FormSet->IfrBinaryData + OpCodeOffset; + + OpCodeLength = ((EFI_IFR_OP_HEADER *)OpCodeData)->Length; + OpCodeOffset += OpCodeLength; + Operand = ((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode; + Scope = ((EFI_IFR_OP_HEADER *)OpCodeData)->Scope; + + if (InUnknownScope) { + if (Operand == EFI_IFR_END_OP) { + UnknownDepth--; + + if (UnknownDepth == 0) { + InUnknownScope = FALSE; + } + } else { + if (Scope != 0) { + UnknownDepth++; + } + } + + continue; + } + + if (IsUnKnownOpCode (Operand)) { + if (Scope != 0) { + InUnknownScope = TRUE; + UnknownDepth++; + } + + continue; + } + + // + // If scope bit set, push onto scope stack + // + if (Scope != 0) { + PushScope (Operand); + } + + if (OpCodeDisabled) { + // + // DisableIf Expression is evaluated to be TRUE, try to find its end. + // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END + // + if (Operand == EFI_IFR_DISABLE_IF_OP) { + DepthOfDisable++; + } else if (Operand == EFI_IFR_END_OP) { + Status = PopScope (&ScopeOpCode); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) { + if (DepthOfDisable == 0) { + InScopeDisable = FALSE; + OpCodeDisabled = FALSE; + } else { + DepthOfDisable--; + } + } + } + + continue; + } + + if (IsExpressionOpCode (Operand)) { + ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex]; + mExpressionOpCodeIndex++; + + ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE; + ExpressionOpCode->Operand = Operand; + Value = &ExpressionOpCode->Value; + + switch (Operand) { + case EFI_IFR_EQ_ID_VAL_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *)OpCodeData)->Value, sizeof (UINT16)); + break; + + case EFI_IFR_EQ_ID_ID_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *)OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID)); + CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *)OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID)); + break; + + case EFI_IFR_EQ_ID_VAL_LIST_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->ListLength, sizeof (UINT16)); + ExpressionOpCode->ValueList = AllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->ValueList); + break; + + case EFI_IFR_TO_STRING_OP: + case EFI_IFR_FIND_OP: + ExpressionOpCode->Format = ((EFI_IFR_TO_STRING *)OpCodeData)->Format; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type = EFI_IFR_TYPE_STRING; + CopyMem (&Value->Value.string, &((EFI_IFR_STRING_REF1 *)OpCodeData)->StringId, sizeof (EFI_STRING_ID)); + break; + + case EFI_IFR_RULE_REF_OP: + ExpressionOpCode->RuleId = ((EFI_IFR_RULE_REF *)OpCodeData)->RuleId; + break; + + case EFI_IFR_SPAN_OP: + ExpressionOpCode->Flags = ((EFI_IFR_SPAN *)OpCodeData)->Flags; + break; + + case EFI_IFR_THIS_OP: + ASSERT (ParentStatement != NULL); + ExpressionOpCode->QuestionId = ParentStatement->QuestionId; + break; + + case EFI_IFR_SECURITY_OP: + CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *)OpCodeData)->Permissions, sizeof (EFI_GUID)); + break; + + case EFI_IFR_MATCH2_OP: + CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_MATCH2 *)OpCodeData)->SyntaxType, sizeof (EFI_GUID)); + break; + + case EFI_IFR_GET_OP: + case EFI_IFR_SET_OP: + CopyMem (&TempVarstoreId, &((EFI_IFR_GET *)OpCodeData)->VarStoreId, sizeof (TempVarstoreId)); + if (TempVarstoreId != 0) { + if (FormSet->StorageListHead.ForwardLink != NULL) { + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + VarStorage = FORMSET_STORAGE_FROM_LINK (Link); + if (VarStorage->VarStoreId == ((EFI_IFR_GET *)OpCodeData)->VarStoreId) { + ExpressionOpCode->VarStorage = VarStorage->BrowserStorage; + break; + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + } + + if (ExpressionOpCode->VarStorage == NULL) { + // + // VarStorage is not found. + // + return EFI_INVALID_PARAMETER; + } + } + + ExpressionOpCode->ValueType = ((EFI_IFR_GET *)OpCodeData)->VarStoreType; + switch (ExpressionOpCode->ValueType) { + case EFI_IFR_TYPE_BOOLEAN: + case EFI_IFR_TYPE_NUM_SIZE_8: + ExpressionOpCode->ValueWidth = 1; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_STRING: + ExpressionOpCode->ValueWidth = 2; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + ExpressionOpCode->ValueWidth = 4; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + ExpressionOpCode->ValueWidth = 8; + break; + + case EFI_IFR_TYPE_DATE: + ExpressionOpCode->ValueWidth = (UINT8)sizeof (EFI_IFR_DATE); + break; + + case EFI_IFR_TYPE_TIME: + ExpressionOpCode->ValueWidth = (UINT8)sizeof (EFI_IFR_TIME); + break; + + case EFI_IFR_TYPE_REF: + ExpressionOpCode->ValueWidth = (UINT8)sizeof (EFI_IFR_REF); + break; + + case EFI_IFR_TYPE_OTHER: + case EFI_IFR_TYPE_UNDEFINED: + case EFI_IFR_TYPE_ACTION: + case EFI_IFR_TYPE_BUFFER: + default: + // + // Invalid value type for Get/Set opcode. + // + return EFI_INVALID_PARAMETER; + } + + CopyMem (&ExpressionOpCode->VarStoreInfo.VarName, &((EFI_IFR_GET *)OpCodeData)->VarStoreInfo.VarName, sizeof (EFI_STRING_ID)); + CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *)OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16)); + if ((ExpressionOpCode->VarStorage != NULL) && + ((ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) || + (ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE))) + { + ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->HiiHandle); + if (ExpressionOpCode->ValueName == NULL) { + // + // String ID is invalid. + // + return EFI_INVALID_PARAMETER; + } + } + + break; + + case EFI_IFR_QUESTION_REF1_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + break; + + case EFI_IFR_QUESTION_REF3_OP: + if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) { + CopyMem (&ExpressionOpCode->DevicePath, &((EFI_IFR_QUESTION_REF3_2 *)OpCodeData)->DevicePath, sizeof (EFI_STRING_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) { + CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_QUESTION_REF3_3 *)OpCodeData)->Guid, sizeof (EFI_GUID)); + } + } + + break; + + // + // constant + // + case EFI_IFR_TRUE_OP: + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Value->Value.b = TRUE; + break; + + case EFI_IFR_FALSE_OP: + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Value->Value.b = FALSE; + break; + + case EFI_IFR_ONE_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = 1; + break; + + case EFI_IFR_ZERO_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = 0; + break; + + case EFI_IFR_ONES_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = 0xffffffffffffffffULL; + break; + + case EFI_IFR_UINT8_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = ((EFI_IFR_UINT8 *)OpCodeData)->Value; + break; + + case EFI_IFR_UINT16_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + CopyMem (&Value->Value.u16, &((EFI_IFR_UINT16 *)OpCodeData)->Value, sizeof (UINT16)); + break; + + case EFI_IFR_UINT32_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + CopyMem (&Value->Value.u32, &((EFI_IFR_UINT32 *)OpCodeData)->Value, sizeof (UINT32)); + break; + + case EFI_IFR_UINT64_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + CopyMem (&Value->Value.u64, &((EFI_IFR_UINT64 *)OpCodeData)->Value, sizeof (UINT64)); + break; + + case EFI_IFR_UNDEFINED_OP: + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + + case EFI_IFR_VERSION_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + Value->Value.u16 = EFI_IFR_SPECIFICATION_VERSION; + break; + + default: + break; + } + + // + // Create sub expression nested in MAP opcode + // + if ((CurrentExpression == NULL) && (MapScopeDepth > 0)) { + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + ASSERT (MapExpressionList != NULL); + InsertTailList (MapExpressionList, &CurrentExpression->Link); + if (Scope == 0) { + SingleOpCodeExpression = TRUE; + } + } + + ASSERT (CurrentExpression != NULL); + InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link); + if (Operand == EFI_IFR_MAP_OP) { + // + // Store current Map Expression List. + // + if (MapExpressionList != NULL) { + PushMapExpressionList (MapExpressionList); + } + + // + // Initialize new Map Expression List. + // + MapExpressionList = &ExpressionOpCode->MapExpressionList; + InitializeListHead (MapExpressionList); + // + // Store current expression. + // + PushCurrentExpression (CurrentExpression); + CurrentExpression = NULL; + MapScopeDepth++; + } else if (SingleOpCodeExpression) { + // + // There are two cases to indicate the end of an Expression: + // for single OpCode expression: one Expression OpCode + // for expression consists of more than one OpCode: EFI_IFR_END + // + SingleOpCodeExpression = FALSE; + + if (InScopeDisable && (CurrentForm == NULL)) { + // + // This is DisableIf expression for Form, it should be a constant expression + // + Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + OpCodeDisabled = IsTrue (&CurrentExpression->Result); + } + + CurrentExpression = NULL; + } + + continue; + } + + // + // Parse the Opcode + // + switch (Operand) { + case EFI_IFR_FORM_SET_OP: + // + // Check the formset GUID + // + if (CompareMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *)OpCodeData)->Guid, sizeof (EFI_GUID)) != 0) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *)OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID)); + CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *)OpCodeData)->Help, sizeof (EFI_STRING_ID)); + FormSet->OpCode = (EFI_IFR_OP_HEADER *)OpCodeData;// save the opcode address of formset + + if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) { + // + // The formset OpCode contains ClassGuid + // + FormSet->NumberOfClassGuid = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3); + CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID)); + } + + break; + + case EFI_IFR_FORM_OP: + // + // Create a new Form for this FormSet + // + CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM)); + ASSERT (CurrentForm != NULL); + CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE; + InitializeListHead (&CurrentForm->ExpressionListHead); + InitializeListHead (&CurrentForm->StatementListHead); + InitializeListHead (&CurrentForm->ConfigRequestHead); + InitializeListHead (&CurrentForm->FormViewListHead); + + CurrentForm->FormType = STANDARD_MAP_FORM_TYPE; + CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *)OpCodeData)->FormId, sizeof (UINT16)); + CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *)OpCodeData)->FormTitle, sizeof (EFI_STRING_ID)); + + ConditionalExprCount = GetConditionalExpressionCount (ExpressForm); + if ( ConditionalExprCount > 0) { + // + // Form is inside of suppressif + // + CurrentForm->SuppressExpression = (FORM_EXPRESSION_LIST *)AllocatePool ( + (UINTN)(sizeof (FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof (FORM_EXPRESSION *))) + ); + ASSERT (CurrentForm->SuppressExpression != NULL); + CurrentForm->SuppressExpression->Count = (UINTN)ConditionalExprCount; + CurrentForm->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE; + CopyMem (CurrentForm->SuppressExpression->Expression, GetConditionalExpressionList (ExpressForm), (UINTN)(sizeof (FORM_EXPRESSION *) * ConditionalExprCount)); + } + + if (Scope != 0) { + // + // Enter scope of a Form, suppressif will be used for Question or Option + // + SuppressForQuestion = TRUE; + } + + // + // Insert into Form list of this FormSet + // + InsertTailList (&FormSet->FormListHead, &CurrentForm->Link); + break; + + case EFI_IFR_FORM_MAP_OP: + // + // Create a new Form for this FormSet + // + CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM)); + ASSERT (CurrentForm != NULL); + CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE; + InitializeListHead (&CurrentForm->ExpressionListHead); + InitializeListHead (&CurrentForm->StatementListHead); + InitializeListHead (&CurrentForm->ConfigRequestHead); + InitializeListHead (&CurrentForm->FormViewListHead); + + CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *)OpCodeData)->FormId, sizeof (UINT16)); + + MapMethod = (EFI_IFR_FORM_MAP_METHOD *)(OpCodeData + sizeof (EFI_IFR_FORM_MAP)); + // + // FormMap Form must contain at least one Map Method. + // + if (((EFI_IFR_OP_HEADER *)OpCodeData)->Length < ((UINTN)(UINT8 *)(MapMethod + 1) - (UINTN)OpCodeData)) { + return EFI_INVALID_PARAMETER; + } + + // + // Try to find the standard form map method. + // + while (((UINTN)(UINT8 *)MapMethod - (UINTN)OpCodeData) < ((EFI_IFR_OP_HEADER *)OpCodeData)->Length) { + if (CompareGuid ((EFI_GUID *)(VOID *)&MapMethod->MethodIdentifier, &gEfiHiiStandardFormGuid)) { + CopyMem (&CurrentForm->FormTitle, &MapMethod->MethodTitle, sizeof (EFI_STRING_ID)); + CurrentForm->FormType = STANDARD_MAP_FORM_TYPE; + break; + } + + MapMethod++; + } + + // + // If the standard form map method is not found, the first map method title will be used. + // + if (CurrentForm->FormTitle == 0) { + MapMethod = (EFI_IFR_FORM_MAP_METHOD *)(OpCodeData + sizeof (EFI_IFR_FORM_MAP)); + CopyMem (&CurrentForm->FormTitle, &MapMethod->MethodTitle, sizeof (EFI_STRING_ID)); + } + + ConditionalExprCount = GetConditionalExpressionCount (ExpressForm); + if ( ConditionalExprCount > 0) { + // + // Form is inside of suppressif + // + CurrentForm->SuppressExpression = (FORM_EXPRESSION_LIST *)AllocatePool ( + (UINTN)(sizeof (FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof (FORM_EXPRESSION *))) + ); + ASSERT (CurrentForm->SuppressExpression != NULL); + CurrentForm->SuppressExpression->Count = (UINTN)ConditionalExprCount; + CurrentForm->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE; + CopyMem (CurrentForm->SuppressExpression->Expression, GetConditionalExpressionList (ExpressForm), (UINTN)(sizeof (FORM_EXPRESSION *) * ConditionalExprCount)); + } + + if (Scope != 0) { + // + // Enter scope of a Form, suppressif will be used for Question or Option + // + SuppressForQuestion = TRUE; + } + + // + // Insert into Form list of this FormSet + // + InsertTailList (&FormSet->FormListHead, &CurrentForm->Link); + break; + + // + // Storage + // + case EFI_IFR_VARSTORE_OP: + // + // Create a buffer Storage for this FormSet + // + Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_BUFFER, OpCodeData); + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *)OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + break; + + case EFI_IFR_VARSTORE_NAME_VALUE_OP: + // + // Create a name/value Storage for this FormSet + // + Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_NAME_VALUE, OpCodeData); + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *)OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + break; + + case EFI_IFR_VARSTORE_EFI_OP: + // + // Create a EFI variable Storage for this FormSet + // + if (OpCodeLength < sizeof (EFI_IFR_VARSTORE_EFI)) { + // + // Create efi varstore with format follow UEFI spec before 2.3.1. + // + Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_EFI_VARIABLE, OpCodeData); + } else { + // + // Create efi varstore with format follow UEFI spec 2.3.1 and later. + // + Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER, OpCodeData); + } + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *)OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + break; + + // + // DefaultStore + // + case EFI_IFR_DEFAULTSTORE_OP: + HaveInserted = FALSE; + DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE)); + ASSERT (DefaultStore != NULL); + DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE; + + CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *)OpCodeData)->DefaultId, sizeof (UINT16)); + CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *)OpCodeData)->DefaultName, sizeof (EFI_STRING_ID)); + // + // Insert it to the DefaultStore list of this Formset with ascending order. + // + if (!IsListEmpty (&FormSet->DefaultStoreListHead)) { + DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead); + while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) { + PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultLink); + DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink); + if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) { + InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link); + HaveInserted = TRUE; + break; + } + } + } + + if (!HaveInserted) { + InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link); + } + + break; + + // + // Statements + // + case EFI_IFR_SUBTITLE_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + + CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *)OpCodeData)->Flags; + CurrentStatement->FakeQuestionId = mUsedQuestionId++; + break; + + case EFI_IFR_TEXT_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + CurrentStatement->FakeQuestionId = mUsedQuestionId++; + CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *)OpCodeData)->TextTwo, sizeof (EFI_STRING_ID)); + break; + + case EFI_IFR_RESET_BUTTON_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + CurrentStatement->FakeQuestionId = mUsedQuestionId++; + CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *)OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID)); + break; + + // + // Questions + // + case EFI_IFR_ACTION_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION; + + if (OpCodeLength == sizeof (EFI_IFR_ACTION_1)) { + // + // No QuestionConfig present, so no configuration string will be processed + // + CurrentStatement->QuestionConfig = 0; + } else { + CopyMem (&CurrentStatement->QuestionConfig, &((EFI_IFR_ACTION *)OpCodeData)->QuestionConfig, sizeof (EFI_STRING_ID)); + } + + break; + + case EFI_IFR_REF_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + Value = &CurrentStatement->HiiValue; + Value->Type = EFI_IFR_TYPE_REF; + if (OpCodeLength >= sizeof (EFI_IFR_REF)) { + CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *)OpCodeData)->FormId, sizeof (EFI_FORM_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF2)) { + CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *)OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF3)) { + CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *)OpCodeData)->FormSetId, sizeof (EFI_GUID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF4)) { + CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *)OpCodeData)->DevicePath, sizeof (EFI_STRING_ID)); + } + } + } + } + + CurrentStatement->StorageWidth = (UINT16)sizeof (EFI_HII_REF); + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + + CurrentStatement->Flags = ((EFI_IFR_ONE_OF *)OpCodeData)->Flags; + Value = &CurrentStatement->HiiValue; + + if (QuestionReferBitField) { + // + // Get the bit var store info (bit/byte offset, bit/byte offset) + // + CurrentStatement->QuestionReferToBitField = TRUE; + CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT; + CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset; + CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8; + TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth; + CurrentStatement->StorageWidth = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1); + + // + // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type) + // + CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MinValue; + CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MaxValue; + CurrentStatement->Step = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.Step; + + // + // Update the Flag and type of Minimum/Maximum/Step according to the actual width of bit field, + // in order to make Browser handle these question with bit varstore correctly. + // + ((EFI_IFR_NUMERIC *)OpCodeData)->Flags &= EDKII_IFR_DISPLAY_BIT; + ((EFI_IFR_NUMERIC *)OpCodeData)->Flags >>= 2; + switch (CurrentStatement->StorageWidth) { + case 1: + ((EFI_IFR_NUMERIC *)OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_8; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MinValue = (UINT8)CurrentStatement->Minimum; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MaxValue = (UINT8)CurrentStatement->Maximum; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.Step = (UINT8)CurrentStatement->Step; + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + break; + case 2: + ((EFI_IFR_NUMERIC *)OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_16; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MinValue = (UINT16)CurrentStatement->Minimum; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MaxValue = (UINT16)CurrentStatement->Maximum; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.Step = (UINT16)CurrentStatement->Step; + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + break; + case 3: + case 4: + ((EFI_IFR_NUMERIC *)OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_32; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MinValue = (UINT32)CurrentStatement->Minimum; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MaxValue = (UINT32)CurrentStatement->Maximum; + ((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.Step = (UINT32)CurrentStatement->Step; + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + break; + default: + break; + } + } else { + switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MinValue; + CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.MaxValue; + CurrentStatement->Step = ((EFI_IFR_NUMERIC *)OpCodeData)->data.u8.Step; + CurrentStatement->StorageWidth = (UINT16)sizeof (UINT8); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MinValue, sizeof (UINT16)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.MaxValue, sizeof (UINT16)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u16.Step, sizeof (UINT16)); + CurrentStatement->StorageWidth = (UINT16)sizeof (UINT16); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MinValue, sizeof (UINT32)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.MaxValue, sizeof (UINT32)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u32.Step, sizeof (UINT32)); + CurrentStatement->StorageWidth = (UINT16)sizeof (UINT32); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u64.MinValue, sizeof (UINT64)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u64.MaxValue, sizeof (UINT64)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *)OpCodeData)->data.u64.Step, sizeof (UINT64)); + CurrentStatement->StorageWidth = (UINT16)sizeof (UINT64); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + break; + + default: + break; + } + } + + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + + if ((Operand == EFI_IFR_ONE_OF_OP) && (Scope != 0)) { + SuppressForOption = TRUE; + } + + break; + + case EFI_IFR_ORDERED_LIST_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + + CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *)OpCodeData)->Flags; + CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *)OpCodeData)->MaxContainers; + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER; + CurrentStatement->BufferValue = NULL; + + if (Scope != 0) { + SuppressForOption = TRUE; + } + + break; + + case EFI_IFR_CHECKBOX_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + + CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *)OpCodeData)->Flags; + CurrentStatement->StorageWidth = (UINT16)sizeof (BOOLEAN); + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN; + + if (QuestionReferBitField) { + // + // Get the bit var store info (bit/byte offset, bit/byte offset) + // + CurrentStatement->QuestionReferToBitField = TRUE; + CurrentStatement->BitStorageWidth = 1; + CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset; + CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8; + TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth; + CurrentStatement->StorageWidth = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1); + } + + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + + break; + + case EFI_IFR_STRING_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + // + // MinSize is the minimum number of characters that can be accepted for this opcode, + // MaxSize is the maximum number of characters that can be accepted for this opcode. + // The characters are stored as Unicode, so the storage width should multiply 2. + // + CurrentStatement->Minimum = ((EFI_IFR_STRING *)OpCodeData)->MinSize; + CurrentStatement->Maximum = ((EFI_IFR_STRING *)OpCodeData)->MaxSize; + CurrentStatement->StorageWidth = (UINT16)((UINTN)CurrentStatement->Maximum * sizeof (CHAR16)); + CurrentStatement->Flags = ((EFI_IFR_STRING *)OpCodeData)->Flags; + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16)); + CurrentStatement->HiiValue.Value.string = NewString ((CHAR16 *)CurrentStatement->BufferValue, FormSet->HiiHandle); + + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + break; + + case EFI_IFR_PASSWORD_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + // + // MinSize is the minimum number of characters that can be accepted for this opcode, + // MaxSize is the maximum number of characters that can be accepted for this opcode. + // The characters are stored as Unicode, so the storage width should multiply 2. + // + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *)OpCodeData)->MinSize, sizeof (UINT16)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *)OpCodeData)->MaxSize, sizeof (UINT16)); + CurrentStatement->StorageWidth = (UINT16)((UINTN)CurrentStatement->Maximum * sizeof (CHAR16)); + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING; + CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16))); + CurrentStatement->HiiValue.Value.string = NewString ((CHAR16 *)CurrentStatement->BufferValue, FormSet->HiiHandle); + + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + break; + + case EFI_IFR_DATE_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + + CurrentStatement->Flags = ((EFI_IFR_DATE *)OpCodeData)->Flags; + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE; + + if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) { + CurrentStatement->StorageWidth = (UINT16)sizeof (EFI_HII_DATE); + + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + } else { + // + // Don't assign storage for RTC type of date/time + // + CurrentStatement->Storage = NULL; + CurrentStatement->StorageWidth = 0; + } + + break; + + case EFI_IFR_TIME_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + ASSERT (CurrentStatement != NULL); + + CurrentStatement->Flags = ((EFI_IFR_TIME *)OpCodeData)->Flags; + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME; + + if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) { + CurrentStatement->StorageWidth = (UINT16)sizeof (EFI_HII_TIME); + + InitializeRequestElement (FormSet, CurrentStatement, CurrentForm); + } else { + // + // Don't assign storage for RTC type of date/time + // + CurrentStatement->Storage = NULL; + CurrentStatement->StorageWidth = 0; + } + + break; + + // + // Default + // + case EFI_IFR_DEFAULT_OP: + // + // EFI_IFR_DEFAULT appear in scope of a Question, + // It creates a default value for the current question. + // A Question may have more than one Default value which have different default types. + // + CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT)); + ASSERT (CurrentDefault != NULL); + CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE; + + CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *)OpCodeData)->Type; + CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *)OpCodeData)->DefaultId, sizeof (UINT16)); + if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) { + CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF (EFI_IFR_DEFAULT, Value)); + CurrentDefault->Value.Buffer = AllocateCopyPool (CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *)OpCodeData)->Value); + ASSERT (CurrentDefault->Value.Buffer != NULL); + } else { + CopyMem (&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *)OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_DEFAULT, Value)); + ExtendValueToU64 (&CurrentDefault->Value); + } + + // + // Insert to Default Value list of current Question + // + InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link); + + if (Scope != 0) { + InScopeDefault = TRUE; + } + + break; + + // + // Option + // + case EFI_IFR_ONE_OF_OPTION_OP: + ASSERT (ParentStatement != NULL); + if ((ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) { + // + // It's keep the default value for ordered list opcode. + // + CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT)); + ASSERT (CurrentDefault != NULL); + CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE; + + CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER; + if ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) { + CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; + } else { + CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; + } + + CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); + CurrentDefault->Value.Buffer = AllocateCopyPool (CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value); + ASSERT (CurrentDefault->Value.Buffer != NULL); + + // + // Insert to Default Value list of current Question + // + InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link); + break; + } + + // + // EFI_IFR_ONE_OF_OPTION appear in scope of a Question. + // It create a selection for use in current Question. + // + CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION)); + ASSERT (CurrentOption != NULL); + CurrentOption->Signature = QUESTION_OPTION_SIGNATURE; + CurrentOption->OpCode = (EFI_IFR_ONE_OF_OPTION *)OpCodeData; + + CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags; + CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Type; + CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Option, sizeof (EFI_STRING_ID)); + CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); + ExtendValueToU64 (&CurrentOption->Value); + + ConditionalExprCount = GetConditionalExpressionCount (ExpressOption); + if ( ConditionalExprCount > 0) { + // + // Form is inside of suppressif + // + CurrentOption->SuppressExpression = (FORM_EXPRESSION_LIST *)AllocatePool ( + (UINTN)(sizeof (FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof (FORM_EXPRESSION *))) + ); + ASSERT (CurrentOption->SuppressExpression != NULL); + CurrentOption->SuppressExpression->Count = (UINTN)ConditionalExprCount; + CurrentOption->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE; + CopyMem (CurrentOption->SuppressExpression->Expression, GetConditionalExpressionList (ExpressOption), (UINTN)(sizeof (FORM_EXPRESSION *) * ConditionalExprCount)); + } + + // + // Insert to Option list of current Question + // + InsertTailList (&ParentStatement->OptionListHead, &CurrentOption->Link); + // + // Now we know the Storage width of nested Ordered List + // + if ((ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (ParentStatement->BufferValue == NULL)) { + Width = 1; + switch (CurrentOption->Value.Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Width = 1; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Width = 2; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Width = 4; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Width = 8; + break; + + default: + // + // Invalid type for Ordered List + // + break; + } + + ParentStatement->StorageWidth = (UINT16)(ParentStatement->MaxContainers * Width); + ParentStatement->BufferValue = AllocateZeroPool (ParentStatement->StorageWidth); + ParentStatement->ValueType = CurrentOption->Value.Type; + if (ParentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { + ParentStatement->HiiValue.Buffer = ParentStatement->BufferValue; + ParentStatement->HiiValue.BufferLen = ParentStatement->StorageWidth; + } + + InitializeRequestElement (FormSet, ParentStatement, CurrentForm); + } + + break; + + // + // Conditional + // + case EFI_IFR_NO_SUBMIT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + // + // Create an Expression node + // + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *)OpCodeData)->Error, sizeof (EFI_STRING_ID)); + + if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) { + CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF; + InsertTailList (&ParentStatement->NoSubmitListHead, &CurrentExpression->Link); + } else { + CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF; + InsertTailList (&ParentStatement->InconsistentListHead, &CurrentExpression->Link); + } + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_WARNING_IF_OP: + // + // Create an Expression node + // + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *)OpCodeData)->Warning, sizeof (EFI_STRING_ID)); + CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *)OpCodeData)->TimeOut; + CurrentExpression->Type = EFI_HII_EXPRESSION_WARNING_IF; + InsertTailList (&ParentStatement->WarningListHead, &CurrentExpression->Link); + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_SUPPRESS_IF_OP: + // + // Question and Option will appear in scope of this OpCode + // + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF; + + if (CurrentForm == NULL) { + InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link); + } else { + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + } + + if (SuppressForOption) { + PushConditionalExpression (CurrentExpression, ExpressOption); + } else if (SuppressForQuestion) { + PushConditionalExpression (CurrentExpression, ExpressStatement); + } else { + PushConditionalExpression (CurrentExpression, ExpressForm); + } + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_GRAY_OUT_IF_OP: + // + // Questions will appear in scope of this OpCode + // + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + PushConditionalExpression (CurrentExpression, ExpressStatement); + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_DISABLE_IF_OP: + // + // The DisableIf expression should only rely on constant, so it could be + // evaluated at initialization and it will not be queued + // + CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION)); + ASSERT (CurrentExpression != NULL); + CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE; + CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF; + InitializeListHead (&CurrentExpression->OpCodeListHead); + + if (CurrentForm != NULL) { + // + // This is DisableIf for Question, enqueue it to Form expression list + // + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + PushConditionalExpression (CurrentExpression, ExpressStatement); + } + + OpCodeDisabled = FALSE; + InScopeDisable = TRUE; + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + // + // Expression + // + case EFI_IFR_VALUE_OP: + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + if (InScopeDefault) { + // + // Used for default (EFI_IFR_DEFAULT) + // + CurrentDefault->ValueExpression = CurrentExpression; + } else { + // + // If used for a question, then the question will be read-only + // + // + // Make sure CurrentStatement is not NULL. + // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR + // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler. + // + ASSERT (ParentStatement != NULL); + ParentStatement->ValueExpression = CurrentExpression; + } + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_RULE_OP: + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CurrentExpression->Type = EFI_HII_EXPRESSION_RULE; + + CurrentExpression->RuleId = ((EFI_IFR_RULE *)OpCodeData)->RuleId; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_READ_OP: + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CurrentExpression->Type = EFI_HII_EXPRESSION_READ; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + // + // Make sure CurrentStatement is not NULL. + // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR + // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler. + // + ASSERT (ParentStatement != NULL); + ParentStatement->ReadExpression = CurrentExpression; + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + case EFI_IFR_WRITE_OP: + CurrentExpression = CreateExpression (CurrentForm, OpCodeData); + CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + // + // Make sure CurrentStatement is not NULL. + // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR + // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler. + // + ASSERT (ParentStatement != NULL); + ParentStatement->WriteExpression = CurrentExpression; + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *)(OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + + break; + + // + // Image + // + case EFI_IFR_IMAGE_OP: + // + // Get ScopeOpcode from top of stack + // + PopScope (&ScopeOpCode); + PushScope (ScopeOpCode); + + switch (ScopeOpCode) { + case EFI_IFR_FORM_SET_OP: + ImageId = &FormSet->ImageId; + break; + + case EFI_IFR_FORM_OP: + case EFI_IFR_FORM_MAP_OP: + ASSERT (CurrentForm != NULL); + ImageId = &CurrentForm->ImageId; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + ASSERT (CurrentOption != NULL); + ImageId = &CurrentOption->ImageId; + break; + + default: + // + // Make sure CurrentStatement is not NULL. + // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR + // file is wrongly generated by tools such as VFR Compiler. + // + ASSERT (ParentStatement != NULL); + ImageId = &ParentStatement->ImageId; + break; + } + + ASSERT (ImageId != NULL); + CopyMem (ImageId, &((EFI_IFR_IMAGE *)OpCodeData)->Id, sizeof (EFI_IMAGE_ID)); + break; + + // + // Refresh + // + case EFI_IFR_REFRESH_OP: + ASSERT (ParentStatement != NULL); + ParentStatement->RefreshInterval = ((EFI_IFR_REFRESH *)OpCodeData)->RefreshInterval; + break; + + // + // Refresh guid. + // + case EFI_IFR_REFRESH_ID_OP: + // + // Get ScopeOpcode from top of stack + // + PopScope (&ScopeOpCode); + PushScope (ScopeOpCode); + + switch (ScopeOpCode) { + case EFI_IFR_FORM_OP: + case EFI_IFR_FORM_MAP_OP: + ASSERT (CurrentForm != NULL); + CopyMem (&CurrentForm->RefreshGuid, &((EFI_IFR_REFRESH_ID *)OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID)); + break; + + default: + ASSERT (ParentStatement != NULL); + CopyMem (&ParentStatement->RefreshGuid, &((EFI_IFR_REFRESH_ID *)OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID)); + break; + } + + break; + + // + // Modal tag + // + case EFI_IFR_MODAL_TAG_OP: + ASSERT (CurrentForm != NULL); + CurrentForm->ModalForm = TRUE; + break; + + // + // Lock tag, used by form and statement. + // + case EFI_IFR_LOCKED_OP: + // + // Get ScopeOpcode from top of stack + // + PopScope (&ScopeOpCode); + PushScope (ScopeOpCode); + switch (ScopeOpCode) { + case EFI_IFR_FORM_OP: + case EFI_IFR_FORM_MAP_OP: + ASSERT (CurrentForm != NULL); + CurrentForm->Locked = TRUE; + break; + + default: + ASSERT (ParentStatement != NULL); + ParentStatement->Locked = TRUE; + } + + break; + + // + // Vendor specific + // + case EFI_IFR_GUID_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) { + Scope = 0; + QuestionReferBitField = TRUE; + } + + break; + + // + // Scope End + // + case EFI_IFR_END_OP: + QuestionReferBitField = FALSE; + Status = PopScope (&ScopeOpCode); + if (EFI_ERROR (Status)) { + ResetScopeStack (); + return Status; + } + + // + // Parent statement end tag found, update ParentStatement info. + // + if (IsStatementOpCode (ScopeOpCode) && (ParentStatement != NULL) && (ParentStatement->Operand == ScopeOpCode)) { + ParentStatement = ParentStatement->ParentStatement; + } + + switch (ScopeOpCode) { + case EFI_IFR_FORM_SET_OP: + // + // End of FormSet, update FormSet IFR binary length + // to stop parsing substantial OpCodes + // + FormSet->IfrBinaryLength = OpCodeOffset; + break; + + case EFI_IFR_FORM_OP: + case EFI_IFR_FORM_MAP_OP: + // + // End of Form + // + CurrentForm = NULL; + SuppressForQuestion = FALSE; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + // + // End of Option + // + CurrentOption = NULL; + break; + + case EFI_IFR_NO_SUBMIT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + case EFI_IFR_WARNING_IF_OP: + // + // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF + // + break; + + case EFI_IFR_SUPPRESS_IF_OP: + if (SuppressForOption) { + PopConditionalExpression (ExpressOption); + } else if (SuppressForQuestion) { + PopConditionalExpression (ExpressStatement); + } else { + PopConditionalExpression (ExpressForm); + } + + break; + + case EFI_IFR_GRAY_OUT_IF_OP: + PopConditionalExpression (ExpressStatement); + break; + + case EFI_IFR_DISABLE_IF_OP: + if (CurrentForm != NULL) { + PopConditionalExpression (ExpressStatement); + } + + InScopeDisable = FALSE; + OpCodeDisabled = FALSE; + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_ORDERED_LIST_OP: + SuppressForOption = FALSE; + break; + + case EFI_IFR_DEFAULT_OP: + InScopeDefault = FALSE; + break; + + case EFI_IFR_MAP_OP: + // + // Get current Map Expression List. + // + Status = PopMapExpressionList ((VOID **)&MapExpressionList); + if (Status == EFI_ACCESS_DENIED) { + MapExpressionList = NULL; + } + + // + // Get current expression. + // + Status = PopCurrentExpression ((VOID **)&CurrentExpression); + ASSERT_EFI_ERROR (Status); + ASSERT (MapScopeDepth > 0); + MapScopeDepth--; + break; + + default: + if (IsExpressionOpCode (ScopeOpCode)) { + if (InScopeDisable && (CurrentForm == NULL)) { + // + // This is DisableIf expression for Form, it should be a constant expression + // + ASSERT (CurrentExpression != NULL); + Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + OpCodeDisabled = IsTrue (&CurrentExpression->Result); + + // + // DisableIf Expression is only used once and not queued, free it + // + DestroyExpression (CurrentExpression); + } + + // + // End of current Expression + // + CurrentExpression = NULL; + } + + break; + } + + break; + + default: + break; + } + + if (IsStatementOpCode (Operand)) { + CurrentStatement->ParentStatement = ParentStatement; + if (Scope != 0) { + // + // Scope != 0, other statements or options may nest in this statement. + // Update the ParentStatement info. + // + ParentStatement = CurrentStatement; + } + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c index de7e79e8ab..840121ad49 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -1,2687 +1,2687 @@ -/** @file
-Utility functions for UI presentation.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 - 2022 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Setup.h"
-
-BOOLEAN mHiiPackageListUpdated;
-UI_MENU_SELECTION *gCurrentSelection;
-EFI_HII_HANDLE mCurrentHiiHandle = NULL;
-EFI_GUID mCurrentFormSetGuid = {
- 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-UINT16 mCurrentFormId = 0;
-EFI_EVENT mValueChangedEvent = NULL;
-LIST_ENTRY mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);
-UINT16 mCurFakeQestId;
-FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
-BOOLEAN mFinishRetrieveCall = FALSE;
-
-/**
- Check whether the ConfigAccess protocol is available.
-
- @param FormSet FormSet of which the ConfigAcces protocol need to be checked.
-
- @retval EFI_SUCCESS The function executed successfully.
-
-**/
-EFI_STATUS
-CheckConfigAccess (
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->HandleProtocol (
- FormSet->DriverHandle,
- &gEfiHiiConfigAccessProtocolGuid,
- (VOID **)&FormSet->ConfigAccess
- );
- if (EFI_ERROR (Status)) {
- //
- // Configuration Driver don't attach ConfigAccess protocol to its HII package
- // list, then there will be no configuration action required.
- // Or the ConfigAccess protocol has been uninstalled.
- //
- FormSet->ConfigAccess = NULL;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Evaluate all expressions in a Form.
-
- @param FormSet FormSet this Form belongs to.
- @param Form The Form.
-
- @retval EFI_SUCCESS The expression evaluated successfuly
-
-**/
-EFI_STATUS
-EvaluateFormExpressions (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- FORM_EXPRESSION *Expression;
-
- Link = GetFirstNode (&Form->ExpressionListHead);
- while (!IsNull (&Form->ExpressionListHead, Link)) {
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- Link = GetNextNode (&Form->ExpressionListHead, Link);
-
- if ((Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) ||
- (Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) ||
- (Expression->Type == EFI_HII_EXPRESSION_WARNING_IF) ||
- (Expression->Type == EFI_HII_EXPRESSION_WRITE) ||
- ((Expression->Type == EFI_HII_EXPRESSION_READ) && (Form->FormType != STANDARD_MAP_FORM_TYPE)))
- {
- //
- // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.
- //
- continue;
- }
-
- Status = EvaluateExpression (FormSet, Form, Expression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Base on the opcode buffer info to get the display statement.
-
- @param OpCode The input opcode buffer for this statement.
-
- @retval Statement The statement use this opcode buffer.
-
-**/
-FORM_DISPLAY_ENGINE_STATEMENT *
-GetDisplayStatement (
- IN EFI_IFR_OP_HEADER *OpCode
- )
-{
- FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
- LIST_ENTRY *Link;
-
- Link = GetFirstNode (&gDisplayFormData.StatementListHead);
- while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {
- DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
-
- if (DisplayStatement->OpCode == OpCode) {
- return DisplayStatement;
- }
-
- Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Free the refresh event list.
-
-**/
-VOID
-FreeRefreshEvent (
- VOID
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
-
- while (!IsListEmpty (&mRefreshEventList)) {
- Link = GetFirstNode (&mRefreshEventList);
- EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);
- RemoveEntryList (&EventNode->Link);
-
- gBS->CloseEvent (EventNode->RefreshEvent);
-
- FreePool (EventNode);
- }
-}
-
-/**
- Check whether this statement value is changed. If yes, update the statement value and return TRUE;
- else return FALSE.
-
- @param Statement The statement need to check.
-
-**/
-VOID
-UpdateStatement (
- IN OUT FORM_BROWSER_STATEMENT *Statement
- )
-{
- GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
-
- //
- // Reset FormPackage update flag
- //
- mHiiPackageListUpdated = FALSE;
-
- //
- // Question value may be changed, need invoke its Callback()
- //
- ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
-
- if (mHiiPackageListUpdated) {
- //
- // Package list is updated, force to reparse IFR binary of target Formset
- //
- mHiiPackageListUpdated = FALSE;
- gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
- }
-}
-
-/**
- Refresh the question which has refresh guid event attribute.
-
- @param Event The event which has this function related.
- @param Context The input context info related to this event or the status code return to the caller.
-**/
-VOID
-EFIAPI
-RefreshEventNotifyForStatement (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- FORM_BROWSER_STATEMENT *Statement;
-
- Statement = (FORM_BROWSER_STATEMENT *)Context;
- UpdateStatement (Statement);
- gBS->SignalEvent (mValueChangedEvent);
-}
-
-/**
- Refresh the questions within this form.
-
- @param Event The event which has this function related.
- @param Context The input context info related to this event or the status code return to the caller.
-**/
-VOID
-EFIAPI
-RefreshEventNotifyForForm (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
-
- gBS->SignalEvent (mValueChangedEvent);
-}
-
-/**
- Create refresh hook event for statement which has refresh event or interval.
-
- @param Statement The statement need to check.
-
-**/
-VOID
-CreateRefreshEventForStatement (
- IN FORM_BROWSER_STATEMENT *Statement
- )
-{
- EFI_STATUS Status;
- EFI_EVENT RefreshEvent;
- FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
-
- //
- // If question has refresh guid, create the notify function.
- //
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- RefreshEventNotifyForStatement,
- Statement,
- &Statement->RefreshGuid,
- &RefreshEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
- ASSERT (EventNode != NULL);
- EventNode->RefreshEvent = RefreshEvent;
- InsertTailList (&mRefreshEventList, &EventNode->Link);
-}
-
-/**
- Create refresh hook event for form which has refresh event or interval.
-
- @param Form The form need to check.
-
-**/
-VOID
-CreateRefreshEventForForm (
- IN FORM_BROWSER_FORM *Form
- )
-{
- EFI_STATUS Status;
- EFI_EVENT RefreshEvent;
- FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
-
- //
- // If question has refresh guid, create the notify function.
- //
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- RefreshEventNotifyForForm,
- Form,
- &Form->RefreshGuid,
- &RefreshEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
- ASSERT (EventNode != NULL);
- EventNode->RefreshEvent = RefreshEvent;
- InsertTailList (&mRefreshEventList, &EventNode->Link);
-}
-
-/**
-
- Initialize the Display statement structure data.
-
- @param DisplayStatement Pointer to the display Statement data strucure.
- @param Statement The statement need to check.
-**/
-VOID
-InitializeDisplayStatement (
- IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,
- IN FORM_BROWSER_STATEMENT *Statement
- )
-{
- LIST_ENTRY *Link;
- QUESTION_OPTION *Option;
- DISPLAY_QUESTION_OPTION *DisplayOption;
- FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement;
-
- DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
- DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
- DisplayStatement->OpCode = Statement->OpCode;
- InitializeListHead (&DisplayStatement->NestStatementList);
- InitializeListHead (&DisplayStatement->OptionListHead);
-
- if ((EvaluateExpressionList (Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {
- DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;
- }
-
- if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {
- DisplayStatement->Attribute |= HII_DISPLAY_READONLY;
- }
-
- //
- // Initilize the option list in statement.
- //
- Link = GetFirstNode (&Statement->OptionListHead);
- while (!IsNull (&Statement->OptionListHead, Link)) {
- Option = QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Statement->OptionListHead, Link);
- if ((Option->SuppressExpression != NULL) &&
- ((EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress)))
- {
- continue;
- }
-
- DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));
- ASSERT (DisplayOption != NULL);
-
- DisplayOption->ImageId = Option->ImageId;
- DisplayOption->Signature = DISPLAY_QUESTION_OPTION_SIGNATURE;
- DisplayOption->OptionOpCode = Option->OpCode;
- InsertTailList (&DisplayStatement->OptionListHead, &DisplayOption->Link);
- }
-
- CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));
-
- //
- // Some special op code need an extra buffer to save the data.
- // Such as string, password, orderedlist...
- //
- if (Statement->BufferValue != NULL) {
- //
- // Ordered list opcode may not initilized, get default value here.
- //
- if ((Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) && (GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0)) {
- GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);
- }
-
- DisplayStatement->CurrentValue.Buffer = AllocateCopyPool (Statement->StorageWidth, Statement->BufferValue);
- DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;
- }
-
- DisplayStatement->SettingChangedFlag = Statement->ValueChanged;
-
- //
- // Get the highlight statement for current form.
- //
- if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||
- ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId)))
- {
- gDisplayFormData.HighLightedStatement = DisplayStatement;
- }
-
- //
- // Create the refresh event process function.
- //
- if (!IsZeroGuid (&Statement->RefreshGuid)) {
- CreateRefreshEventForStatement (Statement);
- }
-
- //
- // For RTC type of date/time, set default refresh interval to be 1 second.
- //
- if (((Statement->Operand == EFI_IFR_DATE_OP) || (Statement->Operand == EFI_IFR_TIME_OP)) && (Statement->Storage == NULL)) {
- Statement->RefreshInterval = 1;
- }
-
- //
- // Create the refresh guid hook event.
- // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.
- //
- if ((!IsZeroGuid (&Statement->RefreshGuid)) || (Statement->RefreshInterval != 0)) {
- gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
- }
-
- //
- // Save the password check function for later use.
- //
- if (Statement->Operand == EFI_IFR_PASSWORD_OP) {
- DisplayStatement->PasswordCheck = PasswordCheck;
- }
-
- //
- // If this statement is nest in the subtitle, insert to the host statement.
- // else insert to the form it belongs to.
- //
- if (Statement->ParentStatement != NULL) {
- ParentStatement = GetDisplayStatement (Statement->ParentStatement->OpCode);
- ASSERT (ParentStatement != NULL);
- InsertTailList (&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink);
- } else {
- InsertTailList (&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
- }
-}
-
-/**
- Process for the refresh interval statement.
-
- @param Event The Event need to be process
- @param Context The context of the event.
-
-**/
-VOID
-EFIAPI
-RefreshIntervalProcess (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- FORM_BROWSER_STATEMENT *Statement;
- LIST_ENTRY *Link;
-
- Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
- while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
-
- if (Statement->RefreshInterval == 0) {
- continue;
- }
-
- UpdateStatement (Statement);
- }
-
- gBS->SignalEvent (mValueChangedEvent);
-}
-
-/**
-
- Make a copy of the global hotkey info.
-
-**/
-VOID
-UpdateHotkeyList (
- VOID
- )
-{
- BROWSER_HOT_KEY *HotKey;
- BROWSER_HOT_KEY *CopyKey;
- LIST_ENTRY *Link;
-
- Link = GetFirstNode (&gBrowserHotKeyList);
- while (!IsNull (&gBrowserHotKeyList, Link)) {
- HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
-
- CopyKey = AllocateCopyPool (sizeof (BROWSER_HOT_KEY), HotKey);
- ASSERT (CopyKey != NULL);
- CopyKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), HotKey->KeyData);
- ASSERT (CopyKey->KeyData != NULL);
- CopyKey->HelpString = AllocateCopyPool (StrSize (HotKey->HelpString), HotKey->HelpString);
- ASSERT (CopyKey->HelpString != NULL);
-
- InsertTailList (&gDisplayFormData.HotKeyListHead, &CopyKey->Link);
-
- Link = GetNextNode (&gBrowserHotKeyList, Link);
- }
-}
-
-/**
-
- Get the extra question attribute from override question list.
-
- @param QuestionId The question id for this request question.
-
- @retval The attribute for this question or NULL if not found this
- question in the list.
-
-**/
-UINT32
-ProcessQuestionExtraAttr (
- IN EFI_QUESTION_ID QuestionId
- )
-{
- LIST_ENTRY *Link;
- QUESTION_ATTRIBUTE_OVERRIDE *QuestionDesc;
-
- //
- // Return HII_DISPLAY_NONE if input a invalid question id.
- //
- if (QuestionId == 0) {
- return HII_DISPLAY_NONE;
- }
-
- Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
- while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) {
- QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link);
- Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link);
-
- if ((QuestionDesc->QuestionId == QuestionId) &&
- (QuestionDesc->FormId == gCurrentSelection->FormId) &&
- (QuestionDesc->HiiHandle == gCurrentSelection->Handle) &&
- CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid))
- {
- return QuestionDesc->Attribute;
- }
- }
-
- return HII_DISPLAY_NONE;
-}
-
-/**
-
- Enum all statement in current form, find all the statement can be display and
- add to the display form.
-
-**/
-VOID
-AddStatementToDisplayForm (
- VOID
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Statement;
- FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
- UINT8 MinRefreshInterval;
- EFI_EVENT RefreshIntervalEvent;
- FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
- BOOLEAN FormEditable;
- UINT32 ExtraAttribute;
-
- MinRefreshInterval = 0;
- FormEditable = FALSE;
-
- //
- // Process the statement outside the form, these statements are not recognized
- // by browser core.
- //
- Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);
- while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);
-
- DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
- ASSERT (DisplayStatement != NULL);
- DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
- DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
- DisplayStatement->OpCode = Statement->OpCode;
-
- InitializeListHead (&DisplayStatement->NestStatementList);
- InitializeListHead (&DisplayStatement->OptionListHead);
-
- InsertTailList (&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
- }
-
- //
- // treat formset as statement outside the form,get its opcode.
- //
- DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
- ASSERT (DisplayStatement != NULL);
-
- DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
- DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
- DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode;
-
- InitializeListHead (&DisplayStatement->NestStatementList);
- InitializeListHead (&DisplayStatement->OptionListHead);
-
- InsertTailList (&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
-
- //
- // Process the statement in this form.
- //
- Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
- while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
-
- //
- // This statement can't be show, skip it.
- //
- if (EvaluateExpressionList (Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {
- continue;
- }
-
- //
- // Check the extra attribute.
- //
- ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId);
- if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) {
- continue;
- }
-
- DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
- ASSERT (DisplayStatement != NULL);
-
- //
- // Initialize this statement and add it to the display form.
- //
- InitializeDisplayStatement (DisplayStatement, Statement);
-
- //
- // Set the extra attribute.
- //
- DisplayStatement->Attribute |= ExtraAttribute;
-
- if (Statement->Storage != NULL) {
- FormEditable = TRUE;
- }
-
- //
- // Get the minimal refresh interval value for later use.
- //
- if ((Statement->RefreshInterval != 0) &&
- ((MinRefreshInterval == 0) || (Statement->RefreshInterval < MinRefreshInterval)))
- {
- MinRefreshInterval = Statement->RefreshInterval;
- }
- }
-
- //
- // Create the periodic timer for refresh interval statement.
- //
- if (MinRefreshInterval != 0) {
- Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);
- ASSERT_EFI_ERROR (Status);
- Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);
- ASSERT_EFI_ERROR (Status);
-
- EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
- ASSERT (EventNode != NULL);
- EventNode->RefreshEvent = RefreshIntervalEvent;
- InsertTailList (&mRefreshEventList, &EventNode->Link);
- }
-
- //
- // Create the refresh event process function for Form.
- //
- if (!IsZeroGuid (&gCurrentSelection->Form->RefreshGuid)) {
- CreateRefreshEventForForm (gCurrentSelection->Form);
- if (gDisplayFormData.FormRefreshEvent == NULL) {
- gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
- }
- }
-
- //
- // Update hotkey list field.
- //
- if ((gBrowserSettingScope == SystemLevel) || FormEditable) {
- UpdateHotkeyList ();
- }
-}
-
-/**
-
- Initialize the SettingChangedFlag variable in the display form.
-
-**/
-VOID
-UpdateDataChangedFlag (
- VOID
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORMSET *LocalFormSet;
-
- gDisplayFormData.SettingChangedFlag = FALSE;
-
- if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {
- gDisplayFormData.SettingChangedFlag = TRUE;
- return;
- }
-
- //
- // Base on the system level to check whether need to show the NV flag.
- //
- switch (gBrowserSettingScope) {
- case SystemLevel:
- //
- // Check the maintain list to see whether there is any change.
- //
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- if (IsNvUpdateRequiredForFormSet (LocalFormSet)) {
- gDisplayFormData.SettingChangedFlag = TRUE;
- return;
- }
-
- Link = GetNextNode (&gBrowserFormSetList, Link);
- }
-
- break;
-
- case FormSetLevel:
- if (IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet)) {
- gDisplayFormData.SettingChangedFlag = TRUE;
- return;
- }
-
- break;
-
- default:
- break;
- }
-}
-
-/**
-
- Initialize the Display form structure data.
-
-**/
-VOID
-InitializeDisplayFormData (
- VOID
- )
-{
- EFI_STATUS Status;
-
- gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;
- gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1;
- gDisplayFormData.ImageId = 0;
- gDisplayFormData.AnimationId = 0;
-
- InitializeListHead (&gDisplayFormData.StatementListHead);
- InitializeListHead (&gDisplayFormData.StatementListOSF);
- InitializeListHead (&gDisplayFormData.HotKeyListHead);
-
- Status = gBS->CreateEvent (
- EVT_NOTIFY_WAIT,
- TPL_CALLBACK,
- EfiEventEmptyFunction,
- NULL,
- &mValueChangedEvent
- );
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
-
- Free the kotkey info saved in form data.
-
-**/
-VOID
-FreeHotkeyList (
- VOID
- )
-{
- BROWSER_HOT_KEY *HotKey;
- LIST_ENTRY *Link;
-
- while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {
- Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);
- HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
-
- RemoveEntryList (&HotKey->Link);
-
- FreePool (HotKey->KeyData);
- FreePool (HotKey->HelpString);
- FreePool (HotKey);
- }
-}
-
-/**
-
- Update the Display form structure data.
-
-**/
-VOID
-UpdateDisplayFormData (
- VOID
- )
-{
- gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle;
- gDisplayFormData.FormId = gCurrentSelection->FormId;
- gDisplayFormData.HiiHandle = gCurrentSelection->Handle;
- CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);
-
- gDisplayFormData.Attribute = 0;
- gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;
- gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0;
-
- gDisplayFormData.FormRefreshEvent = NULL;
- gDisplayFormData.HighLightedStatement = NULL;
-
- UpdateDataChangedFlag ();
-
- AddStatementToDisplayForm ();
-}
-
-/**
-
- Free the Display Statement structure data.
-
- @param StatementList Point to the statement list which need to be free.
-
-**/
-VOID
-FreeStatementData (
- LIST_ENTRY *StatementList
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *OptionLink;
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- DISPLAY_QUESTION_OPTION *Option;
-
- //
- // Free Statements/Questions
- //
- while (!IsListEmpty (StatementList)) {
- Link = GetFirstNode (StatementList);
- Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
-
- //
- // Free Options List
- //
- while (!IsListEmpty (&Statement->OptionListHead)) {
- OptionLink = GetFirstNode (&Statement->OptionListHead);
- Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);
- RemoveEntryList (&Option->Link);
- FreePool (Option);
- }
-
- //
- // Free nest statement List
- //
- if (!IsListEmpty (&Statement->NestStatementList)) {
- FreeStatementData (&Statement->NestStatementList);
- }
-
- RemoveEntryList (&Statement->DisplayLink);
- FreePool (Statement);
- }
-}
-
-/**
-
- Free the Display form structure data.
-
-**/
-VOID
-FreeDisplayFormData (
- VOID
- )
-{
- FreeStatementData (&gDisplayFormData.StatementListHead);
- FreeStatementData (&gDisplayFormData.StatementListOSF);
-
- FreeRefreshEvent ();
-
- FreeHotkeyList ();
-}
-
-/**
-
- Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
-
- @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
-
- @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
-
-**/
-FORM_BROWSER_STATEMENT *
-GetBrowserStatement (
- IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
- )
-{
- FORM_BROWSER_STATEMENT *Statement;
- LIST_ENTRY *Link;
-
- Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
- while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-
- if (Statement->OpCode == DisplayStatement->OpCode) {
- return Statement;
- }
-
- Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Update the ValueChanged status for questions in this form.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
-**/
-VOID
-UpdateStatementStatusForForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&Form->StatementListHead, Link);
-
- //
- // For password opcode, not set the the value changed flag.
- //
- if (Question->Operand == EFI_IFR_PASSWORD_OP) {
- continue;
- }
-
- IsQuestionValueChanged (FormSet, Form, Question, GetSetValueWithBuffer);
- }
-}
-
-/**
- Update the ValueChanged status for questions in this formset.
-
- @param FormSet FormSet data structure.
-
-**/
-VOID
-UpdateStatementStatusForFormSet (
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORM *Form;
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->FormListHead, Link);
-
- UpdateStatementStatusForForm (FormSet, Form);
- }
-}
-
-/**
- Update the ValueChanged status for questions.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param SettingScope Setting Scope for Default action.
-
-**/
-VOID
-UpdateStatementStatus (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN BROWSER_SETTING_SCOPE SettingScope
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORMSET *LocalFormSet;
-
- switch (SettingScope) {
- case SystemLevel:
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserFormSetList, Link);
- if (!ValidateFormSet (LocalFormSet)) {
- continue;
- }
-
- UpdateStatementStatusForFormSet (LocalFormSet);
- }
-
- break;
-
- case FormSetLevel:
- UpdateStatementStatusForFormSet (FormSet);
- break;
-
- case FormLevel:
- UpdateStatementStatusForForm (FormSet, Form);
- break;
-
- default:
- break;
- }
-}
-
-/**
-
- Process the action request in user input.
-
- @param Action The user input action request info.
- @param DefaultId The user input default Id info.
-
- @retval EFI_SUCESSS This function always return successfully for now.
-
-**/
-EFI_STATUS
-ProcessAction (
- IN UINT32 Action,
- IN UINT16 DefaultId
- )
-{
- //
- // This is caused by use press ESC, and it should not combine with other action type.
- //
- if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
- FindNextMenu (gCurrentSelection, FormLevel);
- return EFI_SUCCESS;
- }
-
- //
- // Below is normal hotkey trigged action, these action maybe combine with each other.
- //
- if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
- DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
- }
-
- if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
- ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
- UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
- }
-
- if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
- SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
- }
-
- if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
- gResetRequiredFormLevel = TRUE;
- gResetRequiredSystemLevel = TRUE;
- }
-
- if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
- //
- // Form Exit without saving, Similar to ESC Key.
- // FormSet Exit without saving, Exit SendForm.
- // System Exit without saving, CallExitHandler and Exit SendForm.
- //
- DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
- if ((gBrowserSettingScope == FormLevel) || (gBrowserSettingScope == FormSetLevel)) {
- FindNextMenu (gCurrentSelection, gBrowserSettingScope);
- } else if (gBrowserSettingScope == SystemLevel) {
- if (ExitHandlerFunction != NULL) {
- ExitHandlerFunction ();
- }
-
- gCurrentSelection->Action = UI_ACTION_EXIT;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Check whether the formset guid is in this Hii package list.
-
- @param HiiHandle The HiiHandle for this HII package list.
- @param FormSetGuid The formset guid for the request formset.
-
- @retval TRUE Find the formset guid.
- @retval FALSE Not found the formset guid.
-
-**/
-BOOLEAN
-GetFormsetGuidFromHiiHandle (
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_GUID *FormSetGuid
- )
-{
- EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
- UINTN BufferSize;
- UINT32 Offset;
- UINT32 Offset2;
- UINT32 PackageListLength;
- EFI_HII_PACKAGE_HEADER PackageHeader;
- UINT8 *Package;
- UINT8 *OpCodeData;
- EFI_STATUS Status;
- BOOLEAN FindGuid;
-
- BufferSize = 0;
- HiiPackageList = NULL;
- FindGuid = FALSE;
-
- Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- HiiPackageList = AllocatePool (BufferSize);
- ASSERT (HiiPackageList != NULL);
-
- Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
- }
-
- if (EFI_ERROR (Status) || (HiiPackageList == NULL)) {
- return FALSE;
- }
-
- //
- // Get Form package from this HII package List
- //
- Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
- Offset2 = 0;
- CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
-
- while (Offset < PackageListLength) {
- Package = ((UINT8 *)HiiPackageList) + Offset;
- CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
- Offset += PackageHeader.Length;
-
- if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
- //
- // Search FormSet in this Form Package
- //
- Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
- while (Offset2 < PackageHeader.Length) {
- OpCodeData = Package + Offset2;
-
- if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
- if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
- FindGuid = TRUE;
- break;
- }
- }
-
- Offset2 += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
- }
- }
-
- if (FindGuid) {
- break;
- }
- }
-
- FreePool (HiiPackageList);
-
- return FindGuid;
-}
-
-/**
- Find HII Handle in the HII database associated with given Device Path.
-
- If DevicePath is NULL, then ASSERT.
-
- @param DevicePath Device Path associated with the HII package list
- handle.
- @param FormsetGuid The formset guid for this formset.
-
- @retval Handle HII package list Handle associated with the Device
- Path.
- @retval NULL Hii Package list handle is not found.
-
-**/
-EFI_HII_HANDLE
-DevicePathToHiiHandle (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- IN EFI_GUID *FormsetGuid
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
- UINTN Index;
- EFI_HANDLE Handle;
- EFI_HANDLE DriverHandle;
- EFI_HII_HANDLE *HiiHandles;
- EFI_HII_HANDLE HiiHandle;
-
- ASSERT (DevicePath != NULL);
-
- TmpDevicePath = DevicePath;
- //
- // Locate Device Path Protocol handle buffer
- //
- Status = gBS->LocateDevicePath (
- &gEfiDevicePathProtocolGuid,
- &TmpDevicePath,
- &DriverHandle
- );
- if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
- return NULL;
- }
-
- //
- // Retrieve all HII Handles from HII database
- //
- HiiHandles = HiiGetHiiHandles (NULL);
- if (HiiHandles == NULL) {
- return NULL;
- }
-
- //
- // Search Hii Handle by Driver Handle
- //
- HiiHandle = NULL;
- for (Index = 0; HiiHandles[Index] != NULL; Index++) {
- Status = mHiiDatabase->GetPackageListHandle (
- mHiiDatabase,
- HiiHandles[Index],
- &Handle
- );
- if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
- if (GetFormsetGuidFromHiiHandle (HiiHandles[Index], FormsetGuid)) {
- HiiHandle = HiiHandles[Index];
- break;
- }
-
- if (HiiHandle != NULL) {
- break;
- }
- }
- }
-
- FreePool (HiiHandles);
- return HiiHandle;
-}
-
-/**
- Find HII Handle in the HII database associated with given form set guid.
-
- If FormSetGuid is NULL, then ASSERT.
-
- @param ComparingGuid FormSet Guid associated with the HII package list
- handle.
-
- @retval Handle HII package list Handle associated with the Device
- Path.
- @retval NULL Hii Package list handle is not found.
-
-**/
-EFI_HII_HANDLE
-FormSetGuidToHiiHandle (
- EFI_GUID *ComparingGuid
- )
-{
- EFI_HII_HANDLE *HiiHandles;
- EFI_HII_HANDLE HiiHandle;
- UINTN Index;
-
- ASSERT (ComparingGuid != NULL);
-
- HiiHandle = NULL;
- //
- // Get all the Hii handles
- //
- HiiHandles = HiiGetHiiHandles (NULL);
- ASSERT (HiiHandles != NULL);
-
- //
- // Search for formset of each class type
- //
- for (Index = 0; HiiHandles[Index] != NULL; Index++) {
- if (GetFormsetGuidFromHiiHandle (HiiHandles[Index], ComparingGuid)) {
- HiiHandle = HiiHandles[Index];
- break;
- }
-
- if (HiiHandle != NULL) {
- break;
- }
- }
-
- FreePool (HiiHandles);
-
- return HiiHandle;
-}
-
-/**
- check how to process the changed data in current form or form set.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
-
- @param Scope Data save or discard scope, form or formset.
-
- @retval TRUE Success process the changed data, will return to the parent form.
- @retval FALSE Reject to process the changed data, will stay at current form.
-**/
-BOOLEAN
-ProcessChangedData (
- IN OUT UI_MENU_SELECTION *Selection,
- IN BROWSER_SETTING_SCOPE Scope
- )
-{
- BOOLEAN RetValue;
- EFI_STATUS Status;
-
- RetValue = TRUE;
- switch (mFormDisplay->ConfirmDataChange ()) {
- case BROWSER_ACTION_DISCARD:
- DiscardForm (Selection->FormSet, Selection->Form, Scope);
- break;
-
- case BROWSER_ACTION_SUBMIT:
- Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);
- if (EFI_ERROR (Status)) {
- RetValue = FALSE;
- }
-
- break;
-
- case BROWSER_ACTION_NONE:
- RetValue = FALSE;
- break;
-
- default:
- //
- // if Invalid value return, process same as BROWSER_ACTION_NONE.
- //
- RetValue = FALSE;
- break;
- }
-
- return RetValue;
-}
-
-/**
- Find parent formset menu(the first menu which has different formset) for current menu.
- If not find, just return to the first menu.
-
- @param Selection The selection info.
-
-**/
-VOID
-FindParentFormSet (
- IN OUT UI_MENU_SELECTION *Selection
- )
-{
- FORM_ENTRY_INFO *CurrentMenu;
- FORM_ENTRY_INFO *ParentMenu;
-
- CurrentMenu = Selection->CurrentMenu;
- ParentMenu = UiFindParentMenu (CurrentMenu, FormSetLevel);
-
- if (ParentMenu != NULL) {
- CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
- Selection->Handle = ParentMenu->HiiHandle;
- Selection->FormId = ParentMenu->FormId;
- Selection->QuestionId = ParentMenu->QuestionId;
- } else {
- Selection->FormId = CurrentMenu->FormId;
- Selection->QuestionId = CurrentMenu->QuestionId;
- }
-
- Selection->Statement = NULL;
-}
-
-/**
- Process the goto op code, update the info in the selection structure.
-
- @param Statement The statement belong to goto op code.
- @param Selection The selection info.
-
- @retval EFI_SUCCESS The menu process successfully.
- @return Other value if the process failed.
-**/
-EFI_STATUS
-ProcessGotoOpCode (
- IN OUT FORM_BROWSER_STATEMENT *Statement,
- IN OUT UI_MENU_SELECTION *Selection
- )
-{
- CHAR16 *StringPtr;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- FORM_BROWSER_FORM *RefForm;
- EFI_STATUS Status;
- EFI_HII_HANDLE HiiHandle;
-
- Status = EFI_SUCCESS;
- StringPtr = NULL;
- HiiHandle = NULL;
-
- //
- // Prepare the device path check, get the device path info first.
- //
- if (Statement->HiiValue.Value.ref.DevicePath != 0) {
- StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
- }
-
- //
- // Check whether the device path string is a valid string.
- //
- if ((Statement->HiiValue.Value.ref.DevicePath != 0) && (StringPtr != NULL) && (StringPtr[0] != L'\0')) {
- if (Selection->Form->ModalForm) {
- return Status;
- }
-
- //
- // Goto another Hii Package list
- //
- if (mPathFromText != NULL) {
- DevicePath = mPathFromText->ConvertTextToDevicePath (StringPtr);
- if (DevicePath != NULL) {
- HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);
- FreePool (DevicePath);
- }
-
- FreePool (StringPtr);
- } else {
- //
- // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
- //
- PopupErrorMessage (BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);
- FreePool (StringPtr);
- return Status;
- }
-
- if (HiiHandle != Selection->Handle) {
- //
- // Goto another Formset, check for uncommitted data
- //
- if (((gBrowserSettingScope == FormLevel) || (gBrowserSettingScope == FormSetLevel)) &&
- IsNvUpdateRequiredForFormSet (Selection->FormSet))
- {
- if (!ProcessChangedData (Selection, FormSetLevel)) {
- return EFI_SUCCESS;
- }
- }
- }
-
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- Selection->Handle = HiiHandle;
- if (Selection->Handle == NULL) {
- //
- // If target Hii Handle not found, exit current formset.
- //
- FindParentFormSet (Selection);
- return EFI_SUCCESS;
- }
-
- CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
- Selection->FormId = Statement->HiiValue.Value.ref.FormId;
- Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
- } else if (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) {
- if (Selection->Form->ModalForm) {
- return Status;
- }
-
- if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
- //
- // Goto another Formset, check for uncommitted data
- //
- if (((gBrowserSettingScope == FormLevel) || (gBrowserSettingScope == FormSetLevel)) &&
- IsNvUpdateRequiredForFormSet (Selection->FormSet))
- {
- if (!ProcessChangedData (Selection, FormSetLevel)) {
- return EFI_SUCCESS;
- }
- }
- }
-
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- Selection->Handle = FormSetGuidToHiiHandle (&Statement->HiiValue.Value.ref.FormSetGuid);
- if (Selection->Handle == NULL) {
- //
- // If target Hii Handle not found, exit current formset.
- //
- FindParentFormSet (Selection);
- return EFI_SUCCESS;
- }
-
- CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
- Selection->FormId = Statement->HiiValue.Value.ref.FormId;
- Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
- } else if (Statement->HiiValue.Value.ref.FormId != 0) {
- //
- // Goto another Form, check for uncommitted data
- //
- if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
- if (((gBrowserSettingScope == FormLevel) && IsNvUpdateRequiredForForm (Selection->Form))) {
- if (!ProcessChangedData (Selection, FormLevel)) {
- return EFI_SUCCESS;
- }
- }
- }
-
- RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
- if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
- if (EvaluateExpressionList (RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
- //
- // Form is suppressed.
- //
- PopupErrorMessage (BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
- return EFI_SUCCESS;
- }
- }
-
- Selection->FormId = Statement->HiiValue.Value.ref.FormId;
- Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
- } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
- Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
- }
-
- return Status;
-}
-
-/**
- Process Question Config.
-
- @param Selection The UI menu selection.
- @param Question The Question to be peocessed.
-
- @retval EFI_SUCCESS Question Config process success.
- @retval Other Question Config process fail.
-
-**/
-EFI_STATUS
-ProcessQuestionConfig (
- IN UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_STATEMENT *Question
- )
-{
- EFI_STATUS Status;
- CHAR16 *ConfigResp;
- CHAR16 *Progress;
-
- if (Question->QuestionConfig == 0) {
- return EFI_SUCCESS;
- }
-
- //
- // Get <ConfigResp>
- //
- ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
- if (ConfigResp == NULL) {
- return EFI_NOT_FOUND;
- } else if (ConfigResp[0] == L'\0') {
- return EFI_SUCCESS;
- }
-
- //
- // Send config to Configuration Driver
- //
- Status = mHiiConfigRouting->RouteConfig (
- mHiiConfigRouting,
- ConfigResp,
- &Progress
- );
-
- return Status;
-}
-
-/**
-
- Process the user input data.
-
- @param UserInput The user input data.
-
- @retval EFI_SUCESSS This function always return successfully for now.
-
-**/
-EFI_STATUS
-ProcessUserInput (
- IN USER_INPUT *UserInput
- )
-{
- EFI_STATUS Status;
- FORM_BROWSER_STATEMENT *Statement;
-
- Status = EFI_SUCCESS;
- Statement = NULL;
-
- //
- // When Exit from FormDisplay function, one of the below two cases must be true.
- //
- ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
-
- //
- // Remove the last highligh question id, this id will update when show next form.
- //
- gCurrentSelection->QuestionId = 0;
- if (UserInput->SelectedStatement != NULL) {
- Statement = GetBrowserStatement (UserInput->SelectedStatement);
- ASSERT (Statement != NULL);
-
- //
- // This question is the current user select one,record it and later
- // show it as the highlight question.
- //
- gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
- //
- // For statement like text, actio, it not has question id.
- // So use FakeQuestionId to save the question.
- //
- if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
- mCurFakeQestId = Statement->FakeQuestionId;
- } else {
- mCurFakeQestId = 0;
- }
- }
-
- //
- // First process the Action field in USER_INPUT.
- //
- if (UserInput->Action != 0) {
- Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
- gCurrentSelection->Statement = NULL;
- } else {
- ASSERT (Statement != NULL);
- gCurrentSelection->Statement = Statement;
- switch (Statement->Operand) {
- case EFI_IFR_REF_OP:
- Status = ProcessGotoOpCode (Statement, gCurrentSelection);
- break;
-
- case EFI_IFR_ACTION_OP:
- //
- // Process the Config string <ConfigResp>
- //
- Status = ProcessQuestionConfig (gCurrentSelection, Statement);
- break;
-
- case EFI_IFR_RESET_BUTTON_OP:
- //
- // Reset Question to default value specified by DefaultId
- //
- Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);
- UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);
- break;
-
- default:
- switch (Statement->Operand) {
- case EFI_IFR_STRING_OP:
- DeleteString (Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
- Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
- CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN)UserInput->InputValue.BufferLen);
- FreePool (UserInput->InputValue.Buffer);
- break;
-
- case EFI_IFR_PASSWORD_OP:
- if (UserInput->InputValue.Buffer == NULL) {
- //
- // User not input new password, just return.
- //
- break;
- }
-
- DeleteString (Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
- Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
- CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN)UserInput->InputValue.BufferLen);
- ZeroMem (UserInput->InputValue.Buffer, (UINTN)UserInput->InputValue.BufferLen);
- FreePool (UserInput->InputValue.Buffer);
- //
- // Two password match, send it to Configuration Driver
- //
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
- PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *)Statement->BufferValue);
- //
- // Clean the value after saved it.
- //
- ZeroMem (Statement->BufferValue, (UINTN)UserInput->InputValue.BufferLen);
- HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16 *)Statement->BufferValue, NULL);
- } else {
- SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
- }
-
- break;
-
- case EFI_IFR_ORDERED_LIST_OP:
- CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
- break;
-
- default:
- CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
- break;
- }
-
- break;
- }
- }
-
- return Status;
-}
-
-/**
-
- Display form and wait for user to select one menu option, then return it.
-
- @retval EFI_SUCESSS This function always return successfully for now.
-
-**/
-EFI_STATUS
-DisplayForm (
- VOID
- )
-{
- EFI_STATUS Status;
- USER_INPUT UserInput;
- FORM_ENTRY_INFO *CurrentMenu;
-
- ZeroMem (&UserInput, sizeof (USER_INPUT));
-
- //
- // Update the menu history data.
- //
- CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
- if (CurrentMenu == NULL) {
- //
- // Current menu not found, add it to the menu tree
- //
- CurrentMenu = UiAddMenuList (
- gCurrentSelection->Handle,
- &gCurrentSelection->FormSetGuid,
- gCurrentSelection->FormId,
- gCurrentSelection->QuestionId
- );
- ASSERT (CurrentMenu != NULL);
- }
-
- //
- // Back up the form view history data for this form.
- //
- UiCopyMenuList (&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);
-
- gCurrentSelection->CurrentMenu = CurrentMenu;
-
- if (gCurrentSelection->QuestionId == 0) {
- //
- // Highlight not specified, fetch it from cached menu
- //
- gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
- }
-
- Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- UpdateDisplayFormData ();
-
- ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);
- Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
- if (EFI_ERROR (Status)) {
- FreeDisplayFormData ();
- return Status;
- }
-
- CheckConfigAccess (gCurrentSelection->FormSet);
-
- Status = ProcessUserInput (&UserInput);
- FreeDisplayFormData ();
- return Status;
-}
-
-/**
- Functions which are registered to receive notification of
- database events have this prototype. The actual event is encoded
- in NotifyType. The following table describes how PackageType,
- PackageGuid, Handle, and Package are used for each of the
- notification types.
-
- @param PackageType Package type of the notification.
-
- @param PackageGuid If PackageType is
- EFI_HII_PACKAGE_TYPE_GUID, then this is
- the pointer to the GUID from the Guid
- field of EFI_HII_PACKAGE_GUID_HEADER.
- Otherwise, it must be NULL.
-
- @param Package Points to the package referred to by the
- notification Handle The handle of the package
- list which contains the specified package.
-
- @param Handle The HII handle.
-
- @param NotifyType The type of change concerning the
- database. See
- EFI_HII_DATABASE_NOTIFY_TYPE.
-
-**/
-EFI_STATUS
-EFIAPI
-FormUpdateNotify (
- IN UINT8 PackageType,
- IN CONST EFI_GUID *PackageGuid,
- IN CONST EFI_HII_PACKAGE_HEADER *Package,
- IN EFI_HII_HANDLE Handle,
- IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
- )
-{
- mHiiPackageListUpdated = TRUE;
-
- return EFI_SUCCESS;
-}
-
-/**
- Update the NV flag info for this form set.
-
- @param FormSet FormSet data structure.
-
-**/
-BOOLEAN
-IsNvUpdateRequiredForFormSet (
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORM *Form;
- BOOLEAN RetVal;
-
- //
- // Not finished question initialization, return FALSE.
- //
- if (!FormSet->QuestionInited) {
- return FALSE;
- }
-
- RetVal = FALSE;
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- RetVal = IsNvUpdateRequiredForForm (Form);
- if (RetVal) {
- break;
- }
-
- Link = GetNextNode (&FormSet->FormListHead, Link);
- }
-
- return RetVal;
-}
-
-/**
- Update the NvUpdateRequired flag for a form.
-
- @param Form Form data structure.
-
-**/
-BOOLEAN
-IsNvUpdateRequiredForForm (
- IN FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Statement;
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-
- if (Statement->ValueChanged) {
- return TRUE;
- }
-
- Link = GetNextNode (&Form->StatementListHead, Link);
- }
-
- return FALSE;
-}
-
-/**
- Find menu which will show next time.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
- @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
- else, we need to exit current formset.
-
- @retval TRUE Exit current form.
- @retval FALSE User press ESC and keep in current form.
-**/
-BOOLEAN
-FindNextMenu (
- IN OUT UI_MENU_SELECTION *Selection,
- IN BROWSER_SETTING_SCOPE SettingLevel
- )
-{
- FORM_ENTRY_INFO *CurrentMenu;
- FORM_ENTRY_INFO *ParentMenu;
- BROWSER_SETTING_SCOPE Scope;
-
- CurrentMenu = Selection->CurrentMenu;
- Scope = FormSetLevel;
-
- ParentMenu = UiFindParentMenu (CurrentMenu, SettingLevel);
- while (ParentMenu != NULL && !ValidateHiiHandle (ParentMenu->HiiHandle)) {
- ParentMenu = UiFindParentMenu (ParentMenu, SettingLevel);
- }
-
- if (ParentMenu != NULL) {
- if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
- Scope = FormLevel;
- } else {
- Scope = FormSetLevel;
- }
- }
-
- //
- // Form Level Check whether the data is changed.
- //
- if (((gBrowserSettingScope == FormLevel) && IsNvUpdateRequiredForForm (Selection->Form)) ||
- ((gBrowserSettingScope == FormSetLevel) && IsNvUpdateRequiredForFormSet (Selection->FormSet) && (Scope == FormSetLevel)))
- {
- if (!ProcessChangedData (Selection, gBrowserSettingScope)) {
- return FALSE;
- }
- }
-
- if (ParentMenu != NULL) {
- //
- // ParentMenu is found. Then, go to it.
- //
- if (Scope == FormLevel) {
- Selection->Action = UI_ACTION_REFRESH_FORM;
- } else {
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
- Selection->Handle = ParentMenu->HiiHandle;
- }
-
- Selection->Statement = NULL;
-
- Selection->FormId = ParentMenu->FormId;
- Selection->QuestionId = ParentMenu->QuestionId;
-
- //
- // Clear highlight record for this menu
- //
- CurrentMenu->QuestionId = 0;
- return FALSE;
- }
-
- //
- // Current in root page, exit the SendForm
- //
- Selection->Action = UI_ACTION_EXIT;
-
- return TRUE;
-}
-
-/**
- Reconnect the controller.
-
- @param DriverHandle The controller handle which need to be reconnect.
-
- @retval TRUE do the reconnect behavior success.
- @retval FALSE do the reconnect behavior failed.
-
-**/
-BOOLEAN
-ReconnectController (
- IN EFI_HANDLE DriverHandle
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->DisconnectController (DriverHandle, NULL, NULL);
- if (!EFI_ERROR (Status)) {
- Status = gBS->ConnectController (DriverHandle, NULL, NULL, TRUE);
- }
-
- return Status == EFI_SUCCESS;
-}
-
-/**
- Call the call back function for the question and process the return action.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
- @param FormSet The formset this question belong to.
- @param Form The form this question belong to.
- @param Question The Question which need to call.
- @param Action The action request.
- @param SkipSaveOrDiscard Whether skip save or discard action.
-
- @retval EFI_SUCCESS The call back function executes successfully.
- @return Other value if the call back function failed to execute.
-**/
-EFI_STATUS
-ProcessCallBackFunction (
- IN OUT UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question,
- IN EFI_BROWSER_ACTION Action,
- IN BOOLEAN SkipSaveOrDiscard
- )
-{
- EFI_STATUS Status;
- EFI_STATUS InternalStatus;
- EFI_BROWSER_ACTION_REQUEST ActionRequest;
- EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
- EFI_HII_VALUE *HiiValue;
- EFI_IFR_TYPE_VALUE *TypeValue;
- FORM_BROWSER_STATEMENT *Statement;
- BOOLEAN SubmitFormIsRequired;
- BOOLEAN DiscardFormIsRequired;
- BOOLEAN NeedExit;
- LIST_ENTRY *Link;
- BROWSER_SETTING_SCOPE SettingLevel;
- EFI_IFR_TYPE_VALUE BackUpValue;
- UINT8 *BackUpBuffer;
- CHAR16 *NewString;
-
- ConfigAccess = FormSet->ConfigAccess;
- SubmitFormIsRequired = FALSE;
- SettingLevel = FormSetLevel;
- DiscardFormIsRequired = FALSE;
- NeedExit = FALSE;
- Status = EFI_SUCCESS;
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- BackUpBuffer = NULL;
-
- if (ConfigAccess == NULL) {
- return EFI_SUCCESS;
- }
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&Form->StatementListHead, Link);
-
- //
- // if Question != NULL, only process the question. Else, process all question in this form.
- //
- if ((Question != NULL) && (Statement != Question)) {
- continue;
- }
-
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
- continue;
- }
-
- //
- // Check whether Statement is disabled.
- //
- if (Statement->Expression != NULL) {
- if (EvaluateExpressionList (Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
- continue;
- }
- }
-
- HiiValue = &Statement->HiiValue;
- TypeValue = &HiiValue->Value;
- if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
- //
- // For OrderedList, passing in the value buffer to Callback()
- //
- TypeValue = (EFI_IFR_TYPE_VALUE *)Statement->BufferValue;
- }
-
- //
- // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
- //
- if (Action == EFI_BROWSER_ACTION_CHANGING) {
- if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
- BackUpBuffer = AllocateCopyPool (Statement->StorageWidth, Statement->BufferValue);
- ASSERT (BackUpBuffer != NULL);
- } else {
- CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
- }
- }
-
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- Status = ConfigAccess->Callback (
- ConfigAccess,
- Action,
- Statement->QuestionId,
- HiiValue->Type,
- TypeValue,
- &ActionRequest
- );
- if (!EFI_ERROR (Status)) {
- //
- // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
- //
- if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
- NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
- ASSERT (NewString != NULL);
-
- ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
- if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
- ZeroMem (Statement->BufferValue, Statement->StorageWidth);
- CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
- } else {
- CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
- }
-
- FreePool (NewString);
- }
-
- //
- // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
- //
- switch (Action) {
- case EFI_BROWSER_ACTION_CHANGED:
- switch (ActionRequest) {
- case EFI_BROWSER_ACTION_REQUEST_RESET:
- DiscardFormIsRequired = TRUE;
- gResetRequiredFormLevel = TRUE;
- gResetRequiredSystemLevel = TRUE;
- NeedExit = TRUE;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
- SubmitFormIsRequired = TRUE;
- NeedExit = TRUE;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_EXIT:
- DiscardFormIsRequired = TRUE;
- NeedExit = TRUE;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
- SubmitFormIsRequired = TRUE;
- SettingLevel = FormLevel;
- NeedExit = TRUE;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
- DiscardFormIsRequired = TRUE;
- SettingLevel = FormLevel;
- NeedExit = TRUE;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
- SubmitFormIsRequired = TRUE;
- SettingLevel = FormLevel;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
- DiscardFormIsRequired = TRUE;
- SettingLevel = FormLevel;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_RECONNECT:
- gCallbackReconnect = TRUE;
- break;
-
- case EFI_BROWSER_ACTION_REQUEST_QUESTION_APPLY:
- Status = SetQuestionValue (
- gCurrentSelection->FormSet,
- gCurrentSelection->Form,
- Statement,
- GetSetValueWithHiiDriver
- );
- break;
-
- default:
- break;
- }
-
- break;
-
- case EFI_BROWSER_ACTION_CHANGING:
- //
- // Do the question validation.
- //
- Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
- if (!EFI_ERROR (Status)) {
- //
- // check whether the question value changed compared with edit buffer before updating edit buffer
- // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
- //
- IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
- //
- // According the spec, return value from call back of "changing" and
- // "retrieve" should update to the question's temp buffer.
- //
- SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
- }
-
- break;
-
- case EFI_BROWSER_ACTION_RETRIEVE:
- //
- // According the spec, return value from call back of "changing" and
- // "retrieve" should update to the question's temp buffer.
- //
- SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
- break;
-
- default:
- break;
- }
- } else {
- //
- // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
- // then the browser will use the value passed to Callback() and ignore the
- // value returned by Callback().
- //
- if ((Action == EFI_BROWSER_ACTION_CHANGING) && (Status == EFI_UNSUPPORTED)) {
- if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
- CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth);
- } else {
- CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
- }
-
- //
- // Do the question validation.
- //
- InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
- if (!EFI_ERROR (InternalStatus)) {
- //
- // check whether the question value changed compared with edit buffer before updating edit buffer
- // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
- //
- IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
- SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
- }
- }
-
- //
- // According the spec, return fail from call back of "changing" and
- // "retrieve", should restore the question's value.
- //
- if ((Action == EFI_BROWSER_ACTION_CHANGING) && (Status != EFI_UNSUPPORTED)) {
- if (Statement->Storage != NULL) {
- GetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
- } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
- ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
- }
- }
-
- if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
- GetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer);
- }
-
- if (Status == EFI_UNSUPPORTED) {
- //
- // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
- //
- Status = EFI_SUCCESS;
- }
- }
-
- if (BackUpBuffer != NULL) {
- FreePool (BackUpBuffer);
- }
-
- //
- // If Question != NULL, means just process one question
- // and if code reach here means this question has finished
- // processing, so just break.
- //
- if (Question != NULL) {
- break;
- }
- }
-
- if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {
- //
- // Confirm changes with user first.
- //
- if (IsNvUpdateRequiredForFormSet (FormSet)) {
- if (BROWSER_ACTION_DISCARD == PopupErrorMessage (BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {
- gCallbackReconnect = FALSE;
- DiscardFormIsRequired = TRUE;
- } else {
- SubmitFormIsRequired = TRUE;
- }
- } else {
- PopupErrorMessage (BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);
- }
-
- //
- // Exit current formset before do the reconnect.
- //
- NeedExit = TRUE;
- SettingLevel = FormSetLevel;
- }
-
- if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
- SubmitForm (FormSet, Form, SettingLevel);
- }
-
- if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
- DiscardForm (FormSet, Form, SettingLevel);
- }
-
- if (NeedExit) {
- FindNextMenu (Selection, SettingLevel);
- }
-
- return Status;
-}
-
-/**
- Call the retrieve type call back function for one question to get the initialize data.
-
- This function only used when in the initialize stage, because in this stage, the
- Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
-
- @param ConfigAccess The config access protocol produced by the hii driver.
- @param Statement The Question which need to call.
- @param FormSet The formset this question belong to.
-
- @retval EFI_SUCCESS The call back function executes successfully.
- @return Other value if the call back function failed to execute.
-**/
-EFI_STATUS
-ProcessRetrieveForQuestion (
- IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
- IN FORM_BROWSER_STATEMENT *Statement,
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- EFI_STATUS Status;
- EFI_BROWSER_ACTION_REQUEST ActionRequest;
- EFI_HII_VALUE *HiiValue;
- EFI_IFR_TYPE_VALUE *TypeValue;
- CHAR16 *NewString;
-
- Status = EFI_SUCCESS;
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
-
- if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || (ConfigAccess == NULL)) {
- return EFI_UNSUPPORTED;
- }
-
- HiiValue = &Statement->HiiValue;
- TypeValue = &HiiValue->Value;
- if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
- //
- // For OrderedList, passing in the value buffer to Callback()
- //
- TypeValue = (EFI_IFR_TYPE_VALUE *)Statement->BufferValue;
- }
-
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- Status = ConfigAccess->Callback (
- ConfigAccess,
- EFI_BROWSER_ACTION_RETRIEVE,
- Statement->QuestionId,
- HiiValue->Type,
- TypeValue,
- &ActionRequest
- );
- if (!EFI_ERROR (Status) && (HiiValue->Type == EFI_IFR_TYPE_STRING)) {
- NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
- ASSERT (NewString != NULL);
-
- ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
- if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
- ZeroMem (Statement->BufferValue, Statement->StorageWidth);
- CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
- } else {
- CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
- }
-
- FreePool (NewString);
- }
-
- return Status;
-}
-
-/**
- The worker function that send the displays to the screen. On output,
- the selection made by user is returned.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
-
- @retval EFI_SUCCESS The page is displayed successfully.
- @return Other value if the page failed to be diplayed.
-
-**/
-EFI_STATUS
-SetupBrowser (
- IN OUT UI_MENU_SELECTION *Selection
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EFI_HANDLE NotifyHandle;
- FORM_BROWSER_STATEMENT *Statement;
- EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
-
- ConfigAccess = Selection->FormSet->ConfigAccess;
-
- //
- // Register notify for Form package update
- //
- Status = mHiiDatabase->RegisterPackageNotify (
- mHiiDatabase,
- EFI_HII_PACKAGE_FORMS,
- NULL,
- FormUpdateNotify,
- EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
- &NotifyHandle
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Initialize current settings of Questions in this FormSet
- //
- InitializeCurrentSetting (Selection->FormSet);
-
- //
- // Initilize Action field.
- //
- Selection->Action = UI_ACTION_REFRESH_FORM;
-
- //
- // Clean the mCurFakeQestId value is formset refreshed.
- //
- mCurFakeQestId = 0;
-
- do {
- //
- // Reset Status to prevent the next break from returning incorrect error status.
- //
- Status = EFI_SUCCESS;
-
- //
- // IFR is updated, force to reparse the IFR binary
- // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and
- // EFI_BROWSER_ACTION_RETRIEVE, so code place here.
- //
- if (mHiiPackageListUpdated) {
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- mHiiPackageListUpdated = FALSE;
- break;
- }
-
- //
- // Initialize Selection->Form
- //
- if (Selection->FormId == 0) {
- //
- // Zero FormId indicates display the first Form in a FormSet
- //
- Link = GetFirstNode (&Selection->FormSet->FormListHead);
-
- Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Selection->FormId = Selection->Form->FormId;
- } else {
- Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
- }
-
- if (Selection->Form == NULL) {
- //
- // No Form to display
- //
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Check Form is suppressed.
- //
- if (Selection->Form->SuppressExpression != NULL) {
- if (EvaluateExpressionList (Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
- //
- // Form is suppressed.
- //
- PopupErrorMessage (BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
-
- //
- // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
- // for each question with callback flag.
- // New form may be the first form, or the different form after another form close.
- //
- if (((Selection->Handle != mCurrentHiiHandle) ||
- (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
- (Selection->FormId != mCurrentFormId)))
- {
- //
- // Update Retrieve flag.
- //
- mFinishRetrieveCall = FALSE;
-
- //
- // Keep current form information
- //
- mCurrentHiiHandle = Selection->Handle;
- CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
- mCurrentFormId = Selection->FormId;
-
- if (ConfigAccess != NULL) {
- Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary
- //
- if (mHiiPackageListUpdated) {
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- mHiiPackageListUpdated = FALSE;
- break;
- }
- }
- }
-
- //
- // Load Questions' Value for display
- //
- Status = LoadFormSetConfig (Selection, Selection->FormSet);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (!mFinishRetrieveCall) {
- //
- // Finish call RETRIEVE callback for this form.
- //
- mFinishRetrieveCall = TRUE;
-
- if (ConfigAccess != NULL) {
- Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // IFR is updated during callback of open form, force to reparse the IFR binary
- //
- if (mHiiPackageListUpdated) {
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- mHiiPackageListUpdated = FALSE;
- break;
- }
- }
- }
-
- //
- // Display form
- //
- Status = DisplayForm ();
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
- //
- Statement = Selection->Statement;
- if (Statement != NULL) {
- if ((ConfigAccess != NULL) &&
- ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
- (Statement->Operand != EFI_IFR_PASSWORD_OP))
- {
- Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
- if (Statement->Operand == EFI_IFR_REF_OP) {
- //
- // Process dynamic update ref opcode.
- //
- if (!EFI_ERROR (Status)) {
- Status = ProcessGotoOpCode (Statement, Selection);
- }
-
- //
- // Callback return error status or status return from process goto opcode.
- //
- if (EFI_ERROR (Status)) {
- //
- // Cross reference will not be taken, restore all essential field
- //
- Selection->Handle = mCurrentHiiHandle;
- CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID));
- Selection->FormId = mCurrentFormId;
- Selection->QuestionId = 0;
- Selection->Action = UI_ACTION_REFRESH_FORM;
- }
- }
-
- if (!EFI_ERROR (Status) &&
- (Statement->Operand != EFI_IFR_REF_OP) &&
- ((Statement->Storage == NULL) || ((Statement->Storage != NULL) && Statement->ValueChanged)))
- {
- //
- // Only question value has been changed, browser will trig CHANGED callback.
- //
- ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
- //
- // check whether the question value changed compared with buffer value
- // if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen
- //
- IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
- }
- } else {
- //
- // Do the question validation.
- //
- Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
- if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
- SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
- //
- // Verify whether question value has checked, update the ValueChanged flag in Question.
- //
- IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
- }
- }
-
- //
- // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage
- // and process question success till here, trig the gResetFlag/gFlagReconnect.
- //
- if ((Status == EFI_SUCCESS) &&
- (Statement->Storage == NULL))
- {
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
- gResetRequiredFormLevel = TRUE;
- gResetRequiredSystemLevel = TRUE;
- }
-
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
- gFlagReconnect = TRUE;
- }
- }
- }
-
- //
- // Check whether Exit flag is TRUE.
- //
- if (gExitRequired) {
- switch (gBrowserSettingScope) {
- case SystemLevel:
- Selection->Action = UI_ACTION_EXIT;
- break;
-
- case FormSetLevel:
- case FormLevel:
- FindNextMenu (Selection, gBrowserSettingScope);
- break;
-
- default:
- break;
- }
-
- gExitRequired = FALSE;
- }
-
- //
- // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
- // for each question with callback flag.
- //
- if ((ConfigAccess != NULL) &&
- ((Selection->Action == UI_ACTION_EXIT) ||
- (Selection->Handle != mCurrentHiiHandle) ||
- (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
- (Selection->FormId != mCurrentFormId)))
- {
- Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
- } while (Selection->Action == UI_ACTION_REFRESH_FORM);
-
-Done:
- //
- // Reset current form information to the initial setting when error happens or form exit.
- //
- if (EFI_ERROR (Status) || (Selection->Action == UI_ACTION_EXIT)) {
- mCurrentHiiHandle = NULL;
- CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
- mCurrentFormId = 0;
- }
-
- //
- // Unregister notify for Form package update
- //
- mHiiDatabase->UnregisterPackageNotify (
- mHiiDatabase,
- NotifyHandle
- );
- return Status;
-}
+/** @file +Utility functions for UI presentation. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 - 2022 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Setup.h" + +BOOLEAN mHiiPackageListUpdated; +UI_MENU_SELECTION *gCurrentSelection; +EFI_HII_HANDLE mCurrentHiiHandle = NULL; +EFI_GUID mCurrentFormSetGuid = { + 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } +}; +UINT16 mCurrentFormId = 0; +EFI_EVENT mValueChangedEvent = NULL; +LIST_ENTRY mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList); +UINT16 mCurFakeQestId; +FORM_DISPLAY_ENGINE_FORM gDisplayFormData; +BOOLEAN mFinishRetrieveCall = FALSE; + +/** + Check whether the ConfigAccess protocol is available. + + @param FormSet FormSet of which the ConfigAcces protocol need to be checked. + + @retval EFI_SUCCESS The function executed successfully. + +**/ +EFI_STATUS +CheckConfigAccess ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + + Status = gBS->HandleProtocol ( + FormSet->DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + (VOID **)&FormSet->ConfigAccess + ); + if (EFI_ERROR (Status)) { + // + // Configuration Driver don't attach ConfigAccess protocol to its HII package + // list, then there will be no configuration action required. + // Or the ConfigAccess protocol has been uninstalled. + // + FormSet->ConfigAccess = NULL; + } + + return EFI_SUCCESS; +} + +/** + Evaluate all expressions in a Form. + + @param FormSet FormSet this Form belongs to. + @param Form The Form. + + @retval EFI_SUCCESS The expression evaluated successfuly + +**/ +EFI_STATUS +EvaluateFormExpressions ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + Link = GetNextNode (&Form->ExpressionListHead, Link); + + if ((Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) || + (Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) || + (Expression->Type == EFI_HII_EXPRESSION_WARNING_IF) || + (Expression->Type == EFI_HII_EXPRESSION_WRITE) || + ((Expression->Type == EFI_HII_EXPRESSION_READ) && (Form->FormType != STANDARD_MAP_FORM_TYPE))) + { + // + // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form. + // + continue; + } + + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Base on the opcode buffer info to get the display statement. + + @param OpCode The input opcode buffer for this statement. + + @retval Statement The statement use this opcode buffer. + +**/ +FORM_DISPLAY_ENGINE_STATEMENT * +GetDisplayStatement ( + IN EFI_IFR_OP_HEADER *OpCode + ) +{ + FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gDisplayFormData.StatementListHead); + while (!IsNull (&gDisplayFormData.StatementListHead, Link)) { + DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + + if (DisplayStatement->OpCode == OpCode) { + return DisplayStatement; + } + + Link = GetNextNode (&gDisplayFormData.StatementListHead, Link); + } + + return NULL; +} + +/** + Free the refresh event list. + +**/ +VOID +FreeRefreshEvent ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + + while (!IsListEmpty (&mRefreshEventList)) { + Link = GetFirstNode (&mRefreshEventList); + EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link); + RemoveEntryList (&EventNode->Link); + + gBS->CloseEvent (EventNode->RefreshEvent); + + FreePool (EventNode); + } +} + +/** + Check whether this statement value is changed. If yes, update the statement value and return TRUE; + else return FALSE. + + @param Statement The statement need to check. + +**/ +VOID +UpdateStatement ( + IN OUT FORM_BROWSER_STATEMENT *Statement + ) +{ + GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); + + // + // Reset FormPackage update flag + // + mHiiPackageListUpdated = FALSE; + + // + // Question value may be changed, need invoke its Callback() + // + ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE); + + if (mHiiPackageListUpdated) { + // + // Package list is updated, force to reparse IFR binary of target Formset + // + mHiiPackageListUpdated = FALSE; + gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; + } +} + +/** + Refresh the question which has refresh guid event attribute. + + @param Event The event which has this function related. + @param Context The input context info related to this event or the status code return to the caller. +**/ +VOID +EFIAPI +RefreshEventNotifyForStatement ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + FORM_BROWSER_STATEMENT *Statement; + + Statement = (FORM_BROWSER_STATEMENT *)Context; + UpdateStatement (Statement); + gBS->SignalEvent (mValueChangedEvent); +} + +/** + Refresh the questions within this form. + + @param Event The event which has this function related. + @param Context The input context info related to this event or the status code return to the caller. +**/ +VOID +EFIAPI +RefreshEventNotifyForForm ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; + + gBS->SignalEvent (mValueChangedEvent); +} + +/** + Create refresh hook event for statement which has refresh event or interval. + + @param Statement The statement need to check. + +**/ +VOID +CreateRefreshEventForStatement ( + IN FORM_BROWSER_STATEMENT *Statement + ) +{ + EFI_STATUS Status; + EFI_EVENT RefreshEvent; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + + // + // If question has refresh guid, create the notify function. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RefreshEventNotifyForStatement, + Statement, + &Statement->RefreshGuid, + &RefreshEvent + ); + ASSERT_EFI_ERROR (Status); + + EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); + ASSERT (EventNode != NULL); + EventNode->RefreshEvent = RefreshEvent; + InsertTailList (&mRefreshEventList, &EventNode->Link); +} + +/** + Create refresh hook event for form which has refresh event or interval. + + @param Form The form need to check. + +**/ +VOID +CreateRefreshEventForForm ( + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + EFI_EVENT RefreshEvent; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + + // + // If question has refresh guid, create the notify function. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RefreshEventNotifyForForm, + Form, + &Form->RefreshGuid, + &RefreshEvent + ); + ASSERT_EFI_ERROR (Status); + + EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); + ASSERT (EventNode != NULL); + EventNode->RefreshEvent = RefreshEvent; + InsertTailList (&mRefreshEventList, &EventNode->Link); +} + +/** + + Initialize the Display statement structure data. + + @param DisplayStatement Pointer to the display Statement data strucure. + @param Statement The statement need to check. +**/ +VOID +InitializeDisplayStatement ( + IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement, + IN FORM_BROWSER_STATEMENT *Statement + ) +{ + LIST_ENTRY *Link; + QUESTION_OPTION *Option; + DISPLAY_QUESTION_OPTION *DisplayOption; + FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement; + + DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; + DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; + DisplayStatement->OpCode = Statement->OpCode; + InitializeListHead (&DisplayStatement->NestStatementList); + InitializeListHead (&DisplayStatement->OptionListHead); + + if ((EvaluateExpressionList (Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) { + DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT; + } + + if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) { + DisplayStatement->Attribute |= HII_DISPLAY_READONLY; + } + + // + // Initilize the option list in statement. + // + Link = GetFirstNode (&Statement->OptionListHead); + while (!IsNull (&Statement->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Statement->OptionListHead, Link); + if ((Option->SuppressExpression != NULL) && + ((EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) + { + continue; + } + + DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION)); + ASSERT (DisplayOption != NULL); + + DisplayOption->ImageId = Option->ImageId; + DisplayOption->Signature = DISPLAY_QUESTION_OPTION_SIGNATURE; + DisplayOption->OptionOpCode = Option->OpCode; + InsertTailList (&DisplayStatement->OptionListHead, &DisplayOption->Link); + } + + CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE)); + + // + // Some special op code need an extra buffer to save the data. + // Such as string, password, orderedlist... + // + if (Statement->BufferValue != NULL) { + // + // Ordered list opcode may not initilized, get default value here. + // + if ((Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) && (GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0)) { + GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0); + } + + DisplayStatement->CurrentValue.Buffer = AllocateCopyPool (Statement->StorageWidth, Statement->BufferValue); + DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth; + } + + DisplayStatement->SettingChangedFlag = Statement->ValueChanged; + + // + // Get the highlight statement for current form. + // + if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) || + ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) + { + gDisplayFormData.HighLightedStatement = DisplayStatement; + } + + // + // Create the refresh event process function. + // + if (!IsZeroGuid (&Statement->RefreshGuid)) { + CreateRefreshEventForStatement (Statement); + } + + // + // For RTC type of date/time, set default refresh interval to be 1 second. + // + if (((Statement->Operand == EFI_IFR_DATE_OP) || (Statement->Operand == EFI_IFR_TIME_OP)) && (Statement->Storage == NULL)) { + Statement->RefreshInterval = 1; + } + + // + // Create the refresh guid hook event. + // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine. + // + if ((!IsZeroGuid (&Statement->RefreshGuid)) || (Statement->RefreshInterval != 0)) { + gDisplayFormData.FormRefreshEvent = mValueChangedEvent; + } + + // + // Save the password check function for later use. + // + if (Statement->Operand == EFI_IFR_PASSWORD_OP) { + DisplayStatement->PasswordCheck = PasswordCheck; + } + + // + // If this statement is nest in the subtitle, insert to the host statement. + // else insert to the form it belongs to. + // + if (Statement->ParentStatement != NULL) { + ParentStatement = GetDisplayStatement (Statement->ParentStatement->OpCode); + ASSERT (ParentStatement != NULL); + InsertTailList (&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink); + } else { + InsertTailList (&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink); + } +} + +/** + Process for the refresh interval statement. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +RefreshIntervalProcess ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + FORM_BROWSER_STATEMENT *Statement; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); + while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); + + if (Statement->RefreshInterval == 0) { + continue; + } + + UpdateStatement (Statement); + } + + gBS->SignalEvent (mValueChangedEvent); +} + +/** + + Make a copy of the global hotkey info. + +**/ +VOID +UpdateHotkeyList ( + VOID + ) +{ + BROWSER_HOT_KEY *HotKey; + BROWSER_HOT_KEY *CopyKey; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gBrowserHotKeyList); + while (!IsNull (&gBrowserHotKeyList, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + + CopyKey = AllocateCopyPool (sizeof (BROWSER_HOT_KEY), HotKey); + ASSERT (CopyKey != NULL); + CopyKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), HotKey->KeyData); + ASSERT (CopyKey->KeyData != NULL); + CopyKey->HelpString = AllocateCopyPool (StrSize (HotKey->HelpString), HotKey->HelpString); + ASSERT (CopyKey->HelpString != NULL); + + InsertTailList (&gDisplayFormData.HotKeyListHead, &CopyKey->Link); + + Link = GetNextNode (&gBrowserHotKeyList, Link); + } +} + +/** + + Get the extra question attribute from override question list. + + @param QuestionId The question id for this request question. + + @retval The attribute for this question or NULL if not found this + question in the list. + +**/ +UINT32 +ProcessQuestionExtraAttr ( + IN EFI_QUESTION_ID QuestionId + ) +{ + LIST_ENTRY *Link; + QUESTION_ATTRIBUTE_OVERRIDE *QuestionDesc; + + // + // Return HII_DISPLAY_NONE if input a invalid question id. + // + if (QuestionId == 0) { + return HII_DISPLAY_NONE; + } + + Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead); + while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) { + QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link); + Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link); + + if ((QuestionDesc->QuestionId == QuestionId) && + (QuestionDesc->FormId == gCurrentSelection->FormId) && + (QuestionDesc->HiiHandle == gCurrentSelection->Handle) && + CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid)) + { + return QuestionDesc->Attribute; + } + } + + return HII_DISPLAY_NONE; +} + +/** + + Enum all statement in current form, find all the statement can be display and + add to the display form. + +**/ +VOID +AddStatementToDisplayForm ( + VOID + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement; + UINT8 MinRefreshInterval; + EFI_EVENT RefreshIntervalEvent; + FORM_BROWSER_REFRESH_EVENT_NODE *EventNode; + BOOLEAN FormEditable; + UINT32 ExtraAttribute; + + MinRefreshInterval = 0; + FormEditable = FALSE; + + // + // Process the statement outside the form, these statements are not recognized + // by browser core. + // + Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF); + while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link); + + DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); + ASSERT (DisplayStatement != NULL); + DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; + DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; + DisplayStatement->OpCode = Statement->OpCode; + + InitializeListHead (&DisplayStatement->NestStatementList); + InitializeListHead (&DisplayStatement->OptionListHead); + + InsertTailList (&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink); + } + + // + // treat formset as statement outside the form,get its opcode. + // + DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); + ASSERT (DisplayStatement != NULL); + + DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE; + DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1; + DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode; + + InitializeListHead (&DisplayStatement->NestStatementList); + InitializeListHead (&DisplayStatement->OptionListHead); + + InsertTailList (&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink); + + // + // Process the statement in this form. + // + Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); + while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); + + // + // This statement can't be show, skip it. + // + if (EvaluateExpressionList (Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) { + continue; + } + + // + // Check the extra attribute. + // + ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId); + if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) { + continue; + } + + DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); + ASSERT (DisplayStatement != NULL); + + // + // Initialize this statement and add it to the display form. + // + InitializeDisplayStatement (DisplayStatement, Statement); + + // + // Set the extra attribute. + // + DisplayStatement->Attribute |= ExtraAttribute; + + if (Statement->Storage != NULL) { + FormEditable = TRUE; + } + + // + // Get the minimal refresh interval value for later use. + // + if ((Statement->RefreshInterval != 0) && + ((MinRefreshInterval == 0) || (Statement->RefreshInterval < MinRefreshInterval))) + { + MinRefreshInterval = Statement->RefreshInterval; + } + } + + // + // Create the periodic timer for refresh interval statement. + // + if (MinRefreshInterval != 0) { + Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent); + ASSERT_EFI_ERROR (Status); + Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND); + ASSERT_EFI_ERROR (Status); + + EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE)); + ASSERT (EventNode != NULL); + EventNode->RefreshEvent = RefreshIntervalEvent; + InsertTailList (&mRefreshEventList, &EventNode->Link); + } + + // + // Create the refresh event process function for Form. + // + if (!IsZeroGuid (&gCurrentSelection->Form->RefreshGuid)) { + CreateRefreshEventForForm (gCurrentSelection->Form); + if (gDisplayFormData.FormRefreshEvent == NULL) { + gDisplayFormData.FormRefreshEvent = mValueChangedEvent; + } + } + + // + // Update hotkey list field. + // + if ((gBrowserSettingScope == SystemLevel) || FormEditable) { + UpdateHotkeyList (); + } +} + +/** + + Initialize the SettingChangedFlag variable in the display form. + +**/ +VOID +UpdateDataChangedFlag ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *LocalFormSet; + + gDisplayFormData.SettingChangedFlag = FALSE; + + if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) { + gDisplayFormData.SettingChangedFlag = TRUE; + return; + } + + // + // Base on the system level to check whether need to show the NV flag. + // + switch (gBrowserSettingScope) { + case SystemLevel: + // + // Check the maintain list to see whether there is any change. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (IsNvUpdateRequiredForFormSet (LocalFormSet)) { + gDisplayFormData.SettingChangedFlag = TRUE; + return; + } + + Link = GetNextNode (&gBrowserFormSetList, Link); + } + + break; + + case FormSetLevel: + if (IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet)) { + gDisplayFormData.SettingChangedFlag = TRUE; + return; + } + + break; + + default: + break; + } +} + +/** + + Initialize the Display form structure data. + +**/ +VOID +InitializeDisplayFormData ( + VOID + ) +{ + EFI_STATUS Status; + + gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE; + gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1; + gDisplayFormData.ImageId = 0; + gDisplayFormData.AnimationId = 0; + + InitializeListHead (&gDisplayFormData.StatementListHead); + InitializeListHead (&gDisplayFormData.StatementListOSF); + InitializeListHead (&gDisplayFormData.HotKeyListHead); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_CALLBACK, + EfiEventEmptyFunction, + NULL, + &mValueChangedEvent + ); + ASSERT_EFI_ERROR (Status); +} + +/** + + Free the kotkey info saved in form data. + +**/ +VOID +FreeHotkeyList ( + VOID + ) +{ + BROWSER_HOT_KEY *HotKey; + LIST_ENTRY *Link; + + while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) { + Link = GetFirstNode (&gDisplayFormData.HotKeyListHead); + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + + RemoveEntryList (&HotKey->Link); + + FreePool (HotKey->KeyData); + FreePool (HotKey->HelpString); + FreePool (HotKey); + } +} + +/** + + Update the Display form structure data. + +**/ +VOID +UpdateDisplayFormData ( + VOID + ) +{ + gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle; + gDisplayFormData.FormId = gCurrentSelection->FormId; + gDisplayFormData.HiiHandle = gCurrentSelection->Handle; + CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid); + + gDisplayFormData.Attribute = 0; + gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0; + gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0; + + gDisplayFormData.FormRefreshEvent = NULL; + gDisplayFormData.HighLightedStatement = NULL; + + UpdateDataChangedFlag (); + + AddStatementToDisplayForm (); +} + +/** + + Free the Display Statement structure data. + + @param StatementList Point to the statement list which need to be free. + +**/ +VOID +FreeStatementData ( + LIST_ENTRY *StatementList + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *OptionLink; + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + DISPLAY_QUESTION_OPTION *Option; + + // + // Free Statements/Questions + // + while (!IsListEmpty (StatementList)) { + Link = GetFirstNode (StatementList); + Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link); + + // + // Free Options List + // + while (!IsListEmpty (&Statement->OptionListHead)) { + OptionLink = GetFirstNode (&Statement->OptionListHead); + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink); + RemoveEntryList (&Option->Link); + FreePool (Option); + } + + // + // Free nest statement List + // + if (!IsListEmpty (&Statement->NestStatementList)) { + FreeStatementData (&Statement->NestStatementList); + } + + RemoveEntryList (&Statement->DisplayLink); + FreePool (Statement); + } +} + +/** + + Free the Display form structure data. + +**/ +VOID +FreeDisplayFormData ( + VOID + ) +{ + FreeStatementData (&gDisplayFormData.StatementListHead); + FreeStatementData (&gDisplayFormData.StatementListOSF); + + FreeRefreshEvent (); + + FreeHotkeyList (); +} + +/** + + Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. + + @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. + + @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. + +**/ +FORM_BROWSER_STATEMENT * +GetBrowserStatement ( + IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement + ) +{ + FORM_BROWSER_STATEMENT *Statement; + LIST_ENTRY *Link; + + Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead); + while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->OpCode == DisplayStatement->OpCode) { + return Statement; + } + + Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link); + } + + return NULL; +} + +/** + Update the ValueChanged status for questions in this form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +UpdateStatementStatusForForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // For password opcode, not set the the value changed flag. + // + if (Question->Operand == EFI_IFR_PASSWORD_OP) { + continue; + } + + IsQuestionValueChanged (FormSet, Form, Question, GetSetValueWithBuffer); + } +} + +/** + Update the ValueChanged status for questions in this formset. + + @param FormSet FormSet data structure. + +**/ +VOID +UpdateStatementStatusForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + + UpdateStatementStatusForForm (FormSet, Form); + } +} + +/** + Update the ValueChanged status for questions. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param SettingScope Setting Scope for Default action. + +**/ +VOID +UpdateStatementStatus ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN BROWSER_SETTING_SCOPE SettingScope + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *LocalFormSet; + + switch (SettingScope) { + case SystemLevel: + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!ValidateFormSet (LocalFormSet)) { + continue; + } + + UpdateStatementStatusForFormSet (LocalFormSet); + } + + break; + + case FormSetLevel: + UpdateStatementStatusForFormSet (FormSet); + break; + + case FormLevel: + UpdateStatementStatusForForm (FormSet, Form); + break; + + default: + break; + } +} + +/** + + Process the action request in user input. + + @param Action The user input action request info. + @param DefaultId The user input default Id info. + + @retval EFI_SUCESSS This function always return successfully for now. + +**/ +EFI_STATUS +ProcessAction ( + IN UINT32 Action, + IN UINT16 DefaultId + ) +{ + // + // This is caused by use press ESC, and it should not combine with other action type. + // + if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) { + FindNextMenu (gCurrentSelection, FormLevel); + return EFI_SUCCESS; + } + + // + // Below is normal hotkey trigged action, these action maybe combine with each other. + // + if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) { + DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + } + + if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) { + ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE); + UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + } + + if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) { + SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + } + + if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) { + gResetRequiredFormLevel = TRUE; + gResetRequiredSystemLevel = TRUE; + } + + if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) { + // + // Form Exit without saving, Similar to ESC Key. + // FormSet Exit without saving, Exit SendForm. + // System Exit without saving, CallExitHandler and Exit SendForm. + // + DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope); + if ((gBrowserSettingScope == FormLevel) || (gBrowserSettingScope == FormSetLevel)) { + FindNextMenu (gCurrentSelection, gBrowserSettingScope); + } else if (gBrowserSettingScope == SystemLevel) { + if (ExitHandlerFunction != NULL) { + ExitHandlerFunction (); + } + + gCurrentSelection->Action = UI_ACTION_EXIT; + } + } + + return EFI_SUCCESS; +} + +/** + Check whether the formset guid is in this Hii package list. + + @param HiiHandle The HiiHandle for this HII package list. + @param FormSetGuid The formset guid for the request formset. + + @retval TRUE Find the formset guid. + @retval FALSE Not found the formset guid. + +**/ +BOOLEAN +GetFormsetGuidFromHiiHandle ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid + ) +{ + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT32 Offset; + UINT32 Offset2; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINT8 *Package; + UINT8 *OpCodeData; + EFI_STATUS Status; + BOOLEAN FindGuid; + + BufferSize = 0; + HiiPackageList = NULL; + FindGuid = FALSE; + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList); + } + + if (EFI_ERROR (Status) || (HiiPackageList == NULL)) { + return FALSE; + } + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + while (Offset < PackageListLength) { + Package = ((UINT8 *)HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + Offset += PackageHeader.Length; + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + FindGuid = TRUE; + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length; + } + } + + if (FindGuid) { + break; + } + } + + FreePool (HiiPackageList); + + return FindGuid; +} + +/** + Find HII Handle in the HII database associated with given Device Path. + + If DevicePath is NULL, then ASSERT. + + @param DevicePath Device Path associated with the HII package list + handle. + @param FormsetGuid The formset guid for this formset. + + @retval Handle HII package list Handle associated with the Device + Path. + @retval NULL Hii Package list handle is not found. + +**/ +EFI_HII_HANDLE +DevicePathToHiiHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_GUID *FormsetGuid + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + UINTN Index; + EFI_HANDLE Handle; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE *HiiHandles; + EFI_HII_HANDLE HiiHandle; + + ASSERT (DevicePath != NULL); + + TmpDevicePath = DevicePath; + // + // Locate Device Path Protocol handle buffer + // + Status = gBS->LocateDevicePath ( + &gEfiDevicePathProtocolGuid, + &TmpDevicePath, + &DriverHandle + ); + if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) { + return NULL; + } + + // + // Retrieve all HII Handles from HII database + // + HiiHandles = HiiGetHiiHandles (NULL); + if (HiiHandles == NULL) { + return NULL; + } + + // + // Search Hii Handle by Driver Handle + // + HiiHandle = NULL; + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + Status = mHiiDatabase->GetPackageListHandle ( + mHiiDatabase, + HiiHandles[Index], + &Handle + ); + if (!EFI_ERROR (Status) && (Handle == DriverHandle)) { + if (GetFormsetGuidFromHiiHandle (HiiHandles[Index], FormsetGuid)) { + HiiHandle = HiiHandles[Index]; + break; + } + + if (HiiHandle != NULL) { + break; + } + } + } + + FreePool (HiiHandles); + return HiiHandle; +} + +/** + Find HII Handle in the HII database associated with given form set guid. + + If FormSetGuid is NULL, then ASSERT. + + @param ComparingGuid FormSet Guid associated with the HII package list + handle. + + @retval Handle HII package list Handle associated with the Device + Path. + @retval NULL Hii Package list handle is not found. + +**/ +EFI_HII_HANDLE +FormSetGuidToHiiHandle ( + EFI_GUID *ComparingGuid + ) +{ + EFI_HII_HANDLE *HiiHandles; + EFI_HII_HANDLE HiiHandle; + UINTN Index; + + ASSERT (ComparingGuid != NULL); + + HiiHandle = NULL; + // + // Get all the Hii handles + // + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); + + // + // Search for formset of each class type + // + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + if (GetFormsetGuidFromHiiHandle (HiiHandles[Index], ComparingGuid)) { + HiiHandle = HiiHandles[Index]; + break; + } + + if (HiiHandle != NULL) { + break; + } + } + + FreePool (HiiHandles); + + return HiiHandle; +} + +/** + check how to process the changed data in current form or form set. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + + @param Scope Data save or discard scope, form or formset. + + @retval TRUE Success process the changed data, will return to the parent form. + @retval FALSE Reject to process the changed data, will stay at current form. +**/ +BOOLEAN +ProcessChangedData ( + IN OUT UI_MENU_SELECTION *Selection, + IN BROWSER_SETTING_SCOPE Scope + ) +{ + BOOLEAN RetValue; + EFI_STATUS Status; + + RetValue = TRUE; + switch (mFormDisplay->ConfirmDataChange ()) { + case BROWSER_ACTION_DISCARD: + DiscardForm (Selection->FormSet, Selection->Form, Scope); + break; + + case BROWSER_ACTION_SUBMIT: + Status = SubmitForm (Selection->FormSet, Selection->Form, Scope); + if (EFI_ERROR (Status)) { + RetValue = FALSE; + } + + break; + + case BROWSER_ACTION_NONE: + RetValue = FALSE; + break; + + default: + // + // if Invalid value return, process same as BROWSER_ACTION_NONE. + // + RetValue = FALSE; + break; + } + + return RetValue; +} + +/** + Find parent formset menu(the first menu which has different formset) for current menu. + If not find, just return to the first menu. + + @param Selection The selection info. + +**/ +VOID +FindParentFormSet ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + FORM_ENTRY_INFO *CurrentMenu; + FORM_ENTRY_INFO *ParentMenu; + + CurrentMenu = Selection->CurrentMenu; + ParentMenu = UiFindParentMenu (CurrentMenu, FormSetLevel); + + if (ParentMenu != NULL) { + CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); + Selection->Handle = ParentMenu->HiiHandle; + Selection->FormId = ParentMenu->FormId; + Selection->QuestionId = ParentMenu->QuestionId; + } else { + Selection->FormId = CurrentMenu->FormId; + Selection->QuestionId = CurrentMenu->QuestionId; + } + + Selection->Statement = NULL; +} + +/** + Process the goto op code, update the info in the selection structure. + + @param Statement The statement belong to goto op code. + @param Selection The selection info. + + @retval EFI_SUCCESS The menu process successfully. + @return Other value if the process failed. +**/ +EFI_STATUS +ProcessGotoOpCode ( + IN OUT FORM_BROWSER_STATEMENT *Statement, + IN OUT UI_MENU_SELECTION *Selection + ) +{ + CHAR16 *StringPtr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + FORM_BROWSER_FORM *RefForm; + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + + Status = EFI_SUCCESS; + StringPtr = NULL; + HiiHandle = NULL; + + // + // Prepare the device path check, get the device path info first. + // + if (Statement->HiiValue.Value.ref.DevicePath != 0) { + StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle); + } + + // + // Check whether the device path string is a valid string. + // + if ((Statement->HiiValue.Value.ref.DevicePath != 0) && (StringPtr != NULL) && (StringPtr[0] != L'\0')) { + if (Selection->Form->ModalForm) { + return Status; + } + + // + // Goto another Hii Package list + // + if (mPathFromText != NULL) { + DevicePath = mPathFromText->ConvertTextToDevicePath (StringPtr); + if (DevicePath != NULL) { + HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid); + FreePool (DevicePath); + } + + FreePool (StringPtr); + } else { + // + // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol. + // + PopupErrorMessage (BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL); + FreePool (StringPtr); + return Status; + } + + if (HiiHandle != Selection->Handle) { + // + // Goto another Formset, check for uncommitted data + // + if (((gBrowserSettingScope == FormLevel) || (gBrowserSettingScope == FormSetLevel)) && + IsNvUpdateRequiredForFormSet (Selection->FormSet)) + { + if (!ProcessChangedData (Selection, FormSetLevel)) { + return EFI_SUCCESS; + } + } + } + + Selection->Action = UI_ACTION_REFRESH_FORMSET; + Selection->Handle = HiiHandle; + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit current formset. + // + FindParentFormSet (Selection); + return EFI_SUCCESS; + } + + CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = Statement->HiiValue.Value.ref.FormId; + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } else if (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) { + if (Selection->Form->ModalForm) { + return Status; + } + + if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) { + // + // Goto another Formset, check for uncommitted data + // + if (((gBrowserSettingScope == FormLevel) || (gBrowserSettingScope == FormSetLevel)) && + IsNvUpdateRequiredForFormSet (Selection->FormSet)) + { + if (!ProcessChangedData (Selection, FormSetLevel)) { + return EFI_SUCCESS; + } + } + } + + Selection->Action = UI_ACTION_REFRESH_FORMSET; + Selection->Handle = FormSetGuidToHiiHandle (&Statement->HiiValue.Value.ref.FormSetGuid); + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit current formset. + // + FindParentFormSet (Selection); + return EFI_SUCCESS; + } + + CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = Statement->HiiValue.Value.ref.FormId; + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } else if (Statement->HiiValue.Value.ref.FormId != 0) { + // + // Goto another Form, check for uncommitted data + // + if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) { + if (((gBrowserSettingScope == FormLevel) && IsNvUpdateRequiredForForm (Selection->Form))) { + if (!ProcessChangedData (Selection, FormLevel)) { + return EFI_SUCCESS; + } + } + } + + RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId); + if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) { + if (EvaluateExpressionList (RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) { + // + // Form is suppressed. + // + PopupErrorMessage (BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); + return EFI_SUCCESS; + } + } + + Selection->FormId = Statement->HiiValue.Value.ref.FormId; + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } else if (Statement->HiiValue.Value.ref.QuestionId != 0) { + Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId; + } + + return Status; +} + +/** + Process Question Config. + + @param Selection The UI menu selection. + @param Question The Question to be peocessed. + + @retval EFI_SUCCESS Question Config process success. + @retval Other Question Config process fail. + +**/ +EFI_STATUS +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question + ) +{ + EFI_STATUS Status; + CHAR16 *ConfigResp; + CHAR16 *Progress; + + if (Question->QuestionConfig == 0) { + return EFI_SUCCESS; + } + + // + // Get <ConfigResp> + // + ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle); + if (ConfigResp == NULL) { + return EFI_NOT_FOUND; + } else if (ConfigResp[0] == L'\0') { + return EFI_SUCCESS; + } + + // + // Send config to Configuration Driver + // + Status = mHiiConfigRouting->RouteConfig ( + mHiiConfigRouting, + ConfigResp, + &Progress + ); + + return Status; +} + +/** + + Process the user input data. + + @param UserInput The user input data. + + @retval EFI_SUCESSS This function always return successfully for now. + +**/ +EFI_STATUS +ProcessUserInput ( + IN USER_INPUT *UserInput + ) +{ + EFI_STATUS Status; + FORM_BROWSER_STATEMENT *Statement; + + Status = EFI_SUCCESS; + Statement = NULL; + + // + // When Exit from FormDisplay function, one of the below two cases must be true. + // + ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL); + + // + // Remove the last highligh question id, this id will update when show next form. + // + gCurrentSelection->QuestionId = 0; + if (UserInput->SelectedStatement != NULL) { + Statement = GetBrowserStatement (UserInput->SelectedStatement); + ASSERT (Statement != NULL); + + // + // This question is the current user select one,record it and later + // show it as the highlight question. + // + gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId; + // + // For statement like text, actio, it not has question id. + // So use FakeQuestionId to save the question. + // + if (gCurrentSelection->CurrentMenu->QuestionId == 0) { + mCurFakeQestId = Statement->FakeQuestionId; + } else { + mCurFakeQestId = 0; + } + } + + // + // First process the Action field in USER_INPUT. + // + if (UserInput->Action != 0) { + Status = ProcessAction (UserInput->Action, UserInput->DefaultId); + gCurrentSelection->Statement = NULL; + } else { + ASSERT (Statement != NULL); + gCurrentSelection->Statement = Statement; + switch (Statement->Operand) { + case EFI_IFR_REF_OP: + Status = ProcessGotoOpCode (Statement, gCurrentSelection); + break; + + case EFI_IFR_ACTION_OP: + // + // Process the Config string <ConfigResp> + // + Status = ProcessQuestionConfig (gCurrentSelection, Statement); + break; + + case EFI_IFR_RESET_BUTTON_OP: + // + // Reset Question to default value specified by DefaultId + // + Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE); + UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel); + break; + + default: + switch (Statement->Operand) { + case EFI_IFR_STRING_OP: + DeleteString (Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle); + Statement->HiiValue.Value.string = UserInput->InputValue.Value.string; + CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN)UserInput->InputValue.BufferLen); + FreePool (UserInput->InputValue.Buffer); + break; + + case EFI_IFR_PASSWORD_OP: + if (UserInput->InputValue.Buffer == NULL) { + // + // User not input new password, just return. + // + break; + } + + DeleteString (Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle); + Statement->HiiValue.Value.string = UserInput->InputValue.Value.string; + CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN)UserInput->InputValue.BufferLen); + ZeroMem (UserInput->InputValue.Buffer, (UINTN)UserInput->InputValue.BufferLen); + FreePool (UserInput->InputValue.Buffer); + // + // Two password match, send it to Configuration Driver + // + if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { + PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *)Statement->BufferValue); + // + // Clean the value after saved it. + // + ZeroMem (Statement->BufferValue, (UINTN)UserInput->InputValue.BufferLen); + HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16 *)Statement->BufferValue, NULL); + } else { + SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver); + } + + break; + + case EFI_IFR_ORDERED_LIST_OP: + CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen); + break; + + default: + CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE)); + break; + } + + break; + } + } + + return Status; +} + +/** + + Display form and wait for user to select one menu option, then return it. + + @retval EFI_SUCESSS This function always return successfully for now. + +**/ +EFI_STATUS +DisplayForm ( + VOID + ) +{ + EFI_STATUS Status; + USER_INPUT UserInput; + FORM_ENTRY_INFO *CurrentMenu; + + ZeroMem (&UserInput, sizeof (USER_INPUT)); + + // + // Update the menu history data. + // + CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId); + if (CurrentMenu == NULL) { + // + // Current menu not found, add it to the menu tree + // + CurrentMenu = UiAddMenuList ( + gCurrentSelection->Handle, + &gCurrentSelection->FormSetGuid, + gCurrentSelection->FormId, + gCurrentSelection->QuestionId + ); + ASSERT (CurrentMenu != NULL); + } + + // + // Back up the form view history data for this form. + // + UiCopyMenuList (&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead); + + gCurrentSelection->CurrentMenu = CurrentMenu; + + if (gCurrentSelection->QuestionId == 0) { + // + // Highlight not specified, fetch it from cached menu + // + gCurrentSelection->QuestionId = CurrentMenu->QuestionId; + } + + Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + UpdateDisplayFormData (); + + ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS); + Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput); + if (EFI_ERROR (Status)) { + FreeDisplayFormData (); + return Status; + } + + CheckConfigAccess (gCurrentSelection->FormSet); + + Status = ProcessUserInput (&UserInput); + FreeDisplayFormData (); + return Status; +} + +/** + Functions which are registered to receive notification of + database events have this prototype. The actual event is encoded + in NotifyType. The following table describes how PackageType, + PackageGuid, Handle, and Package are used for each of the + notification types. + + @param PackageType Package type of the notification. + + @param PackageGuid If PackageType is + EFI_HII_PACKAGE_TYPE_GUID, then this is + the pointer to the GUID from the Guid + field of EFI_HII_PACKAGE_GUID_HEADER. + Otherwise, it must be NULL. + + @param Package Points to the package referred to by the + notification Handle The handle of the package + list which contains the specified package. + + @param Handle The HII handle. + + @param NotifyType The type of change concerning the + database. See + EFI_HII_DATABASE_NOTIFY_TYPE. + +**/ +EFI_STATUS +EFIAPI +FormUpdateNotify ( + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_PACKAGE_HEADER *Package, + IN EFI_HII_HANDLE Handle, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType + ) +{ + mHiiPackageListUpdated = TRUE; + + return EFI_SUCCESS; +} + +/** + Update the NV flag info for this form set. + + @param FormSet FormSet data structure. + +**/ +BOOLEAN +IsNvUpdateRequiredForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + BOOLEAN RetVal; + + // + // Not finished question initialization, return FALSE. + // + if (!FormSet->QuestionInited) { + return FALSE; + } + + RetVal = FALSE; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + RetVal = IsNvUpdateRequiredForForm (Form); + if (RetVal) { + break; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return RetVal; +} + +/** + Update the NvUpdateRequired flag for a form. + + @param Form Form data structure. + +**/ +BOOLEAN +IsNvUpdateRequiredForForm ( + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->ValueChanged) { + return TRUE; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return FALSE; +} + +/** + Find menu which will show next time. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. + else, we need to exit current formset. + + @retval TRUE Exit current form. + @retval FALSE User press ESC and keep in current form. +**/ +BOOLEAN +FindNextMenu ( + IN OUT UI_MENU_SELECTION *Selection, + IN BROWSER_SETTING_SCOPE SettingLevel + ) +{ + FORM_ENTRY_INFO *CurrentMenu; + FORM_ENTRY_INFO *ParentMenu; + BROWSER_SETTING_SCOPE Scope; + + CurrentMenu = Selection->CurrentMenu; + Scope = FormSetLevel; + + ParentMenu = UiFindParentMenu (CurrentMenu, SettingLevel); + while (ParentMenu != NULL && !ValidateHiiHandle (ParentMenu->HiiHandle)) { + ParentMenu = UiFindParentMenu (ParentMenu, SettingLevel); + } + + if (ParentMenu != NULL) { + if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { + Scope = FormLevel; + } else { + Scope = FormSetLevel; + } + } + + // + // Form Level Check whether the data is changed. + // + if (((gBrowserSettingScope == FormLevel) && IsNvUpdateRequiredForForm (Selection->Form)) || + ((gBrowserSettingScope == FormSetLevel) && IsNvUpdateRequiredForFormSet (Selection->FormSet) && (Scope == FormSetLevel))) + { + if (!ProcessChangedData (Selection, gBrowserSettingScope)) { + return FALSE; + } + } + + if (ParentMenu != NULL) { + // + // ParentMenu is found. Then, go to it. + // + if (Scope == FormLevel) { + Selection->Action = UI_ACTION_REFRESH_FORM; + } else { + Selection->Action = UI_ACTION_REFRESH_FORMSET; + CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID)); + Selection->Handle = ParentMenu->HiiHandle; + } + + Selection->Statement = NULL; + + Selection->FormId = ParentMenu->FormId; + Selection->QuestionId = ParentMenu->QuestionId; + + // + // Clear highlight record for this menu + // + CurrentMenu->QuestionId = 0; + return FALSE; + } + + // + // Current in root page, exit the SendForm + // + Selection->Action = UI_ACTION_EXIT; + + return TRUE; +} + +/** + Reconnect the controller. + + @param DriverHandle The controller handle which need to be reconnect. + + @retval TRUE do the reconnect behavior success. + @retval FALSE do the reconnect behavior failed. + +**/ +BOOLEAN +ReconnectController ( + IN EFI_HANDLE DriverHandle + ) +{ + EFI_STATUS Status; + + Status = gBS->DisconnectController (DriverHandle, NULL, NULL); + if (!EFI_ERROR (Status)) { + Status = gBS->ConnectController (DriverHandle, NULL, NULL, TRUE); + } + + return Status == EFI_SUCCESS; +} + +/** + Call the call back function for the question and process the return action. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + @param FormSet The formset this question belong to. + @param Form The form this question belong to. + @param Question The Question which need to call. + @param Action The action request. + @param SkipSaveOrDiscard Whether skip save or discard action. + + @retval EFI_SUCCESS The call back function executes successfully. + @return Other value if the call back function failed to execute. +**/ +EFI_STATUS +ProcessCallBackFunction ( + IN OUT UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_BROWSER_ACTION Action, + IN BOOLEAN SkipSaveOrDiscard + ) +{ + EFI_STATUS Status; + EFI_STATUS InternalStatus; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_HII_VALUE *HiiValue; + EFI_IFR_TYPE_VALUE *TypeValue; + FORM_BROWSER_STATEMENT *Statement; + BOOLEAN SubmitFormIsRequired; + BOOLEAN DiscardFormIsRequired; + BOOLEAN NeedExit; + LIST_ENTRY *Link; + BROWSER_SETTING_SCOPE SettingLevel; + EFI_IFR_TYPE_VALUE BackUpValue; + UINT8 *BackUpBuffer; + CHAR16 *NewString; + + ConfigAccess = FormSet->ConfigAccess; + SubmitFormIsRequired = FALSE; + SettingLevel = FormSetLevel; + DiscardFormIsRequired = FALSE; + NeedExit = FALSE; + Status = EFI_SUCCESS; + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + BackUpBuffer = NULL; + + if (ConfigAccess == NULL) { + return EFI_SUCCESS; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // if Question != NULL, only process the question. Else, process all question in this form. + // + if ((Question != NULL) && (Statement != Question)) { + continue; + } + + if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { + continue; + } + + // + // Check whether Statement is disabled. + // + if (Statement->Expression != NULL) { + if (EvaluateExpressionList (Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) { + continue; + } + } + + HiiValue = &Statement->HiiValue; + TypeValue = &HiiValue->Value; + if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { + // + // For OrderedList, passing in the value buffer to Callback() + // + TypeValue = (EFI_IFR_TYPE_VALUE *)Statement->BufferValue; + } + + // + // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value. + // + if (Action == EFI_BROWSER_ACTION_CHANGING) { + if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { + BackUpBuffer = AllocateCopyPool (Statement->StorageWidth, Statement->BufferValue); + ASSERT (BackUpBuffer != NULL); + } else { + CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE)); + } + } + + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + Status = ConfigAccess->Callback ( + ConfigAccess, + Action, + Statement->QuestionId, + HiiValue->Type, + TypeValue, + &ActionRequest + ); + if (!EFI_ERROR (Status)) { + // + // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue + // + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle); + ASSERT (NewString != NULL); + + ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth); + if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) { + ZeroMem (Statement->BufferValue, Statement->StorageWidth); + CopyMem (Statement->BufferValue, NewString, StrSize (NewString)); + } else { + CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth); + } + + FreePool (NewString); + } + + // + // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest. + // + switch (Action) { + case EFI_BROWSER_ACTION_CHANGED: + switch (ActionRequest) { + case EFI_BROWSER_ACTION_REQUEST_RESET: + DiscardFormIsRequired = TRUE; + gResetRequiredFormLevel = TRUE; + gResetRequiredSystemLevel = TRUE; + NeedExit = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_SUBMIT: + SubmitFormIsRequired = TRUE; + NeedExit = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_EXIT: + DiscardFormIsRequired = TRUE; + NeedExit = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT: + SubmitFormIsRequired = TRUE; + SettingLevel = FormLevel; + NeedExit = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT: + DiscardFormIsRequired = TRUE; + SettingLevel = FormLevel; + NeedExit = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY: + SubmitFormIsRequired = TRUE; + SettingLevel = FormLevel; + break; + + case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD: + DiscardFormIsRequired = TRUE; + SettingLevel = FormLevel; + break; + + case EFI_BROWSER_ACTION_REQUEST_RECONNECT: + gCallbackReconnect = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_QUESTION_APPLY: + Status = SetQuestionValue ( + gCurrentSelection->FormSet, + gCurrentSelection->Form, + Statement, + GetSetValueWithHiiDriver + ); + break; + + default: + break; + } + + break; + + case EFI_BROWSER_ACTION_CHANGING: + // + // Do the question validation. + // + Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); + if (!EFI_ERROR (Status)) { + // + // check whether the question value changed compared with edit buffer before updating edit buffer + // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function + // + IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); + // + // According the spec, return value from call back of "changing" and + // "retrieve" should update to the question's temp buffer. + // + SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer); + } + + break; + + case EFI_BROWSER_ACTION_RETRIEVE: + // + // According the spec, return value from call back of "changing" and + // "retrieve" should update to the question's temp buffer. + // + SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer); + break; + + default: + break; + } + } else { + // + // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING, + // then the browser will use the value passed to Callback() and ignore the + // value returned by Callback(). + // + if ((Action == EFI_BROWSER_ACTION_CHANGING) && (Status == EFI_UNSUPPORTED)) { + if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { + CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth); + } else { + CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE)); + } + + // + // Do the question validation. + // + InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); + if (!EFI_ERROR (InternalStatus)) { + // + // check whether the question value changed compared with edit buffer before updating edit buffer + // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function + // + IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); + SetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer); + } + } + + // + // According the spec, return fail from call back of "changing" and + // "retrieve", should restore the question's value. + // + if ((Action == EFI_BROWSER_ACTION_CHANGING) && (Status != EFI_UNSUPPORTED)) { + if (Statement->Storage != NULL) { + GetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer); + } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { + ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE); + } + } + + if (Action == EFI_BROWSER_ACTION_RETRIEVE) { + GetQuestionValue (FormSet, Form, Statement, GetSetValueWithEditBuffer); + } + + if (Status == EFI_UNSUPPORTED) { + // + // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it. + // + Status = EFI_SUCCESS; + } + } + + if (BackUpBuffer != NULL) { + FreePool (BackUpBuffer); + } + + // + // If Question != NULL, means just process one question + // and if code reach here means this question has finished + // processing, so just break. + // + if (Question != NULL) { + break; + } + } + + if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) { + // + // Confirm changes with user first. + // + if (IsNvUpdateRequiredForFormSet (FormSet)) { + if (BROWSER_ACTION_DISCARD == PopupErrorMessage (BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) { + gCallbackReconnect = FALSE; + DiscardFormIsRequired = TRUE; + } else { + SubmitFormIsRequired = TRUE; + } + } else { + PopupErrorMessage (BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL); + } + + // + // Exit current formset before do the reconnect. + // + NeedExit = TRUE; + SettingLevel = FormSetLevel; + } + + if (SubmitFormIsRequired && !SkipSaveOrDiscard) { + SubmitForm (FormSet, Form, SettingLevel); + } + + if (DiscardFormIsRequired && !SkipSaveOrDiscard) { + DiscardForm (FormSet, Form, SettingLevel); + } + + if (NeedExit) { + FindNextMenu (Selection, SettingLevel); + } + + return Status; +} + +/** + Call the retrieve type call back function for one question to get the initialize data. + + This function only used when in the initialize stage, because in this stage, the + Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead. + + @param ConfigAccess The config access protocol produced by the hii driver. + @param Statement The Question which need to call. + @param FormSet The formset this question belong to. + + @retval EFI_SUCCESS The call back function executes successfully. + @return Other value if the call back function failed to execute. +**/ +EFI_STATUS +ProcessRetrieveForQuestion ( + IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess, + IN FORM_BROWSER_STATEMENT *Statement, + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HII_VALUE *HiiValue; + EFI_IFR_TYPE_VALUE *TypeValue; + CHAR16 *NewString; + + Status = EFI_SUCCESS; + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + + if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || (ConfigAccess == NULL)) { + return EFI_UNSUPPORTED; + } + + HiiValue = &Statement->HiiValue; + TypeValue = &HiiValue->Value; + if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { + // + // For OrderedList, passing in the value buffer to Callback() + // + TypeValue = (EFI_IFR_TYPE_VALUE *)Statement->BufferValue; + } + + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_RETRIEVE, + Statement->QuestionId, + HiiValue->Type, + TypeValue, + &ActionRequest + ); + if (!EFI_ERROR (Status) && (HiiValue->Type == EFI_IFR_TYPE_STRING)) { + NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle); + ASSERT (NewString != NULL); + + ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth); + if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) { + ZeroMem (Statement->BufferValue, Statement->StorageWidth); + CopyMem (Statement->BufferValue, NewString, StrSize (NewString)); + } else { + CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth); + } + + FreePool (NewString); + } + + return Status; +} + +/** + The worker function that send the displays to the screen. On output, + the selection made by user is returned. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + + @retval EFI_SUCCESS The page is displayed successfully. + @return Other value if the page failed to be diplayed. + +**/ +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_HANDLE NotifyHandle; + FORM_BROWSER_STATEMENT *Statement; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + ConfigAccess = Selection->FormSet->ConfigAccess; + + // + // Register notify for Form package update + // + Status = mHiiDatabase->RegisterPackageNotify ( + mHiiDatabase, + EFI_HII_PACKAGE_FORMS, + NULL, + FormUpdateNotify, + EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, + &NotifyHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Initialize current settings of Questions in this FormSet + // + InitializeCurrentSetting (Selection->FormSet); + + // + // Initilize Action field. + // + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Clean the mCurFakeQestId value is formset refreshed. + // + mCurFakeQestId = 0; + + do { + // + // Reset Status to prevent the next break from returning incorrect error status. + // + Status = EFI_SUCCESS; + + // + // IFR is updated, force to reparse the IFR binary + // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and + // EFI_BROWSER_ACTION_RETRIEVE, so code place here. + // + if (mHiiPackageListUpdated) { + Selection->Action = UI_ACTION_REFRESH_FORMSET; + mHiiPackageListUpdated = FALSE; + break; + } + + // + // Initialize Selection->Form + // + if (Selection->FormId == 0) { + // + // Zero FormId indicates display the first Form in a FormSet + // + Link = GetFirstNode (&Selection->FormSet->FormListHead); + + Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Selection->FormId = Selection->Form->FormId; + } else { + Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); + } + + if (Selection->Form == NULL) { + // + // No Form to display + // + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Check Form is suppressed. + // + if (Selection->Form->SuppressExpression != NULL) { + if (EvaluateExpressionList (Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) { + // + // Form is suppressed. + // + PopupErrorMessage (BROWSER_FORM_SUPPRESS, NULL, NULL, NULL); + Status = EFI_NOT_FOUND; + goto Done; + } + } + + // + // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN + // for each question with callback flag. + // New form may be the first form, or the different form after another form close. + // + if (((Selection->Handle != mCurrentHiiHandle) || + (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || + (Selection->FormId != mCurrentFormId))) + { + // + // Update Retrieve flag. + // + mFinishRetrieveCall = FALSE; + + // + // Keep current form information + // + mCurrentHiiHandle = Selection->Handle; + CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid); + mCurrentFormId = Selection->FormId; + + if (ConfigAccess != NULL) { + Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary + // + if (mHiiPackageListUpdated) { + Selection->Action = UI_ACTION_REFRESH_FORMSET; + mHiiPackageListUpdated = FALSE; + break; + } + } + } + + // + // Load Questions' Value for display + // + Status = LoadFormSetConfig (Selection, Selection->FormSet); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (!mFinishRetrieveCall) { + // + // Finish call RETRIEVE callback for this form. + // + mFinishRetrieveCall = TRUE; + + if (ConfigAccess != NULL) { + Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // IFR is updated during callback of open form, force to reparse the IFR binary + // + if (mHiiPackageListUpdated) { + Selection->Action = UI_ACTION_REFRESH_FORMSET; + mHiiPackageListUpdated = FALSE; + break; + } + } + } + + // + // Display form + // + Status = DisplayForm (); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Check Selected Statement (if press ESC, Selection->Statement will be NULL) + // + Statement = Selection->Statement; + if (Statement != NULL) { + if ((ConfigAccess != NULL) && + ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && + (Statement->Operand != EFI_IFR_PASSWORD_OP)) + { + Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE); + if (Statement->Operand == EFI_IFR_REF_OP) { + // + // Process dynamic update ref opcode. + // + if (!EFI_ERROR (Status)) { + Status = ProcessGotoOpCode (Statement, Selection); + } + + // + // Callback return error status or status return from process goto opcode. + // + if (EFI_ERROR (Status)) { + // + // Cross reference will not be taken, restore all essential field + // + Selection->Handle = mCurrentHiiHandle; + CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = mCurrentFormId; + Selection->QuestionId = 0; + Selection->Action = UI_ACTION_REFRESH_FORM; + } + } + + if (!EFI_ERROR (Status) && + (Statement->Operand != EFI_IFR_REF_OP) && + ((Statement->Storage == NULL) || ((Statement->Storage != NULL) && Statement->ValueChanged))) + { + // + // Only question value has been changed, browser will trig CHANGED callback. + // + ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE); + // + // check whether the question value changed compared with buffer value + // if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen + // + IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer); + } + } else { + // + // Do the question validation. + // + Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement); + if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) { + SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer); + // + // Verify whether question value has checked, update the ValueChanged flag in Question. + // + IsQuestionValueChanged (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer); + } + } + + // + // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage + // and process question success till here, trig the gResetFlag/gFlagReconnect. + // + if ((Status == EFI_SUCCESS) && + (Statement->Storage == NULL)) + { + if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { + gResetRequiredFormLevel = TRUE; + gResetRequiredSystemLevel = TRUE; + } + + if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { + gFlagReconnect = TRUE; + } + } + } + + // + // Check whether Exit flag is TRUE. + // + if (gExitRequired) { + switch (gBrowserSettingScope) { + case SystemLevel: + Selection->Action = UI_ACTION_EXIT; + break; + + case FormSetLevel: + case FormLevel: + FindNextMenu (Selection, gBrowserSettingScope); + break; + + default: + break; + } + + gExitRequired = FALSE; + } + + // + // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE + // for each question with callback flag. + // + if ((ConfigAccess != NULL) && + ((Selection->Action == UI_ACTION_EXIT) || + (Selection->Handle != mCurrentHiiHandle) || + (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) || + (Selection->FormId != mCurrentFormId))) + { + Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE); + if (EFI_ERROR (Status)) { + goto Done; + } + } + } while (Selection->Action == UI_ACTION_REFRESH_FORM); + +Done: + // + // Reset current form information to the initial setting when error happens or form exit. + // + if (EFI_ERROR (Status) || (Selection->Action == UI_ACTION_EXIT)) { + mCurrentHiiHandle = NULL; + CopyGuid (&mCurrentFormSetGuid, &gZeroGuid); + mCurrentFormId = 0; + } + + // + // Unregister notify for Form package update + // + mHiiDatabase->UnregisterPackageNotify ( + mHiiDatabase, + NotifyHandle + ); + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index 2f7b11b1aa..b18bfb2041 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -1,6752 +1,6752 @@ -/** @file
-Entry and initialization module for the browser.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2020 - 2022 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Setup.h"
-
-SETUP_DRIVER_PRIVATE_DATA mPrivateData = {
- SETUP_DRIVER_SIGNATURE,
- NULL,
- {
- SendForm,
- BrowserCallback
- },
- {
- SetScope,
- RegisterHotKey,
- RegiserExitHandler,
- SaveReminder
- },
- {
- BROWSER_EXTENSION2_VERSION_1_1,
- SetScope,
- RegisterHotKey,
- RegiserExitHandler,
- IsBrowserDataModified,
- ExecuteAction,
- { NULL, NULL },
- { NULL, NULL },
- IsResetRequired
- }
-};
-
-EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
-EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
-EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
-EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
-
-UINTN gBrowserContextCount = 0;
-LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
-LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
-LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
-LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
-LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList);
-
-BOOLEAN mSystemSubmit = FALSE;
-BOOLEAN gResetRequiredFormLevel;
-BOOLEAN gResetRequiredSystemLevel = FALSE;
-BOOLEAN gExitRequired;
-BOOLEAN gFlagReconnect;
-BOOLEAN gCallbackReconnect;
-BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
-BOOLEAN mBrowserScopeFirstSet = TRUE;
-EXIT_HANDLER ExitHandlerFunction = NULL;
-FORM_BROWSER_FORMSET *mSystemLevelFormSet;
-
-//
-// Browser Global Strings
-//
-CHAR16 *gEmptyString;
-CHAR16 *mUnknownString = L"!";
-
-extern EFI_GUID mCurrentFormSetGuid;
-extern EFI_HII_HANDLE mCurrentHiiHandle;
-extern UINT16 mCurrentFormId;
-extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
-
-/**
- Create a menu with specified formset GUID and form ID, and add it as a child
- of the given parent menu.
-
- @param HiiHandle Hii handle related to this formset.
- @param FormSetGuid The Formset Guid of menu to be added.
- @param FormId The Form ID of menu to be added.
- @param QuestionId The question id of this menu to be added.
-
- @return A pointer to the newly added menu or NULL if memory is insufficient.
-
-**/
-FORM_ENTRY_INFO *
-UiAddMenuList (
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_GUID *FormSetGuid,
- IN UINT16 FormId,
- IN UINT16 QuestionId
- )
-{
- FORM_ENTRY_INFO *MenuList;
-
- MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
- if (MenuList == NULL) {
- return NULL;
- }
-
- MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;
-
- MenuList->HiiHandle = HiiHandle;
- CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
- MenuList->FormId = FormId;
- MenuList->QuestionId = QuestionId;
-
- //
- // If parent is not specified, it is the root Form of a Formset
- //
- InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
-
- return MenuList;
-}
-
-/**
- Return the form id for the input hiihandle and formset.
-
- @param HiiHandle HiiHandle for FormSet.
- @param FormSetGuid The Formset GUID of the menu to search.
-
- @return First form's id for this form set.
-
-**/
-EFI_FORM_ID
-GetFirstFormId (
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_GUID *FormSetGuid
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORM *Form;
-
- Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- return Form->FormId;
-}
-
-/**
- Search Menu with given FormSetGuid and FormId in all cached menu list.
-
- @param HiiHandle HiiHandle for FormSet.
- @param FormSetGuid The Formset GUID of the menu to search.
- @param FormId The Form ID of menu to search.
-
- @return A pointer to menu found or NULL if not found.
-
-**/
-FORM_ENTRY_INFO *
-UiFindMenuList (
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_GUID *FormSetGuid,
- IN UINT16 FormId
- )
-{
- LIST_ENTRY *Link;
- FORM_ENTRY_INFO *MenuList;
- FORM_ENTRY_INFO *RetMenu;
- EFI_FORM_ID FirstFormId;
-
- RetMenu = NULL;
-
- Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
- while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {
- MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
- Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);
-
- //
- // If already find the menu, free the menus behind it.
- //
- if (RetMenu != NULL) {
- RemoveEntryList (&MenuList->Link);
- FreePool (MenuList);
- continue;
- }
-
- //
- // Find the same FromSet.
- //
- if (MenuList->HiiHandle == HiiHandle) {
- if (IsZeroGuid (&MenuList->FormSetGuid)) {
- //
- // FormSetGuid is not specified.
- //
- RetMenu = MenuList;
- } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {
- if (MenuList->FormId == FormId) {
- RetMenu = MenuList;
- } else if ((FormId == 0) || (MenuList->FormId == 0)) {
- FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);
- if (((FormId == 0) && (FirstFormId == MenuList->FormId)) || ((MenuList->FormId == 0) && (FirstFormId == FormId))) {
- RetMenu = MenuList;
- }
- }
- }
- }
- }
-
- return RetMenu;
-}
-
-/**
- Find parent menu for current menu.
-
- @param CurrentMenu Current Menu
- @param SettingLevel Whether find parent menu in Form Level or Formset level.
- In form level, just find the parent menu;
- In formset level, find the parent menu which has different
- formset guid value.
-
- @retval The parent menu for current menu.
-**/
-FORM_ENTRY_INFO *
-UiFindParentMenu (
- IN FORM_ENTRY_INFO *CurrentMenu,
- IN BROWSER_SETTING_SCOPE SettingLevel
- )
-{
- FORM_ENTRY_INFO *ParentMenu;
- LIST_ENTRY *Link;
-
- ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel);
-
- if (CurrentMenu == NULL) {
- return NULL;
- }
-
- ParentMenu = NULL;
- Link = &CurrentMenu->Link;
-
- while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
- ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink);
-
- if (SettingLevel == FormLevel) {
- //
- // For FormLevel, just find the parent menu, return.
- //
- break;
- }
-
- if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
- //
- // For SystemLevel, must find the menu which has different formset.
- //
- break;
- }
-
- Link = Link->BackLink;
- }
-
- //
- // Not find the parent menu, just return NULL.
- //
- if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
- return NULL;
- }
-
- return ParentMenu;
-}
-
-/**
- Free Menu list linked list.
-
- @param MenuListHead One Menu list point in the menu list.
-
-**/
-VOID
-UiFreeMenuList (
- LIST_ENTRY *MenuListHead
- )
-{
- FORM_ENTRY_INFO *MenuList;
-
- while (!IsListEmpty (MenuListHead)) {
- MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);
- RemoveEntryList (&MenuList->Link);
-
- FreePool (MenuList);
- }
-}
-
-/**
- Copy current Menu list to the new menu list.
-
- @param NewMenuListHead New create Menu list.
- @param CurrentMenuListHead Current Menu list.
-
-**/
-VOID
-UiCopyMenuList (
- OUT LIST_ENTRY *NewMenuListHead,
- IN LIST_ENTRY *CurrentMenuListHead
- )
-{
- LIST_ENTRY *Link;
- FORM_ENTRY_INFO *MenuList;
- FORM_ENTRY_INFO *NewMenuEntry;
-
- //
- // If new menu list not empty, free it first.
- //
- UiFreeMenuList (NewMenuListHead);
-
- Link = GetFirstNode (CurrentMenuListHead);
- while (!IsNull (CurrentMenuListHead, Link)) {
- MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
- Link = GetNextNode (CurrentMenuListHead, Link);
-
- NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
- ASSERT (NewMenuEntry != NULL);
- NewMenuEntry->Signature = FORM_ENTRY_INFO_SIGNATURE;
- NewMenuEntry->HiiHandle = MenuList->HiiHandle;
- CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID));
- NewMenuEntry->FormId = MenuList->FormId;
- NewMenuEntry->QuestionId = MenuList->QuestionId;
-
- InsertTailList (NewMenuListHead, &NewMenuEntry->Link);
- }
-}
-
-/**
- Load all hii formset to the browser.
-
-**/
-VOID
-LoadAllHiiFormset (
- VOID
- )
-{
- FORM_BROWSER_FORMSET *LocalFormSet;
- EFI_HII_HANDLE *HiiHandles;
- UINTN Index;
- EFI_GUID ZeroGuid;
- EFI_STATUS Status;
- FORM_BROWSER_FORMSET *OldFormset;
-
- OldFormset = mSystemLevelFormSet;
-
- //
- // Get all the Hii handles
- //
- HiiHandles = HiiGetHiiHandles (NULL);
- ASSERT (HiiHandles != NULL);
-
- //
- // Search for formset of each class type
- //
- for (Index = 0; HiiHandles[Index] != NULL; Index++) {
- //
- // Check HiiHandles[Index] does exist in global maintain list.
- //
- if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
- continue;
- }
-
- //
- // Initilize FormSet Setting
- //
- LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
- ASSERT (LocalFormSet != NULL);
- mSystemLevelFormSet = LocalFormSet;
-
- ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
- Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);
- if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
- DestroyFormSet (LocalFormSet);
- continue;
- }
-
- InitializeCurrentSetting (LocalFormSet);
-
- //
- // Initilize Questions' Value
- //
- Status = LoadFormSetConfig (NULL, LocalFormSet);
- if (EFI_ERROR (Status)) {
- DestroyFormSet (LocalFormSet);
- continue;
- }
- }
-
- //
- // Free resources, and restore gOldFormSet and gClassOfVfr
- //
- FreePool (HiiHandles);
-
- mSystemLevelFormSet = OldFormset;
-}
-
-/**
- Pop up the error info.
-
- @param BrowserStatus The input browser status.
- @param HiiHandle The Hiihandle for this opcode.
- @param OpCode The opcode use to get the erro info and timeout value.
- @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF.
-
-**/
-UINT32
-PopupErrorMessage (
- IN UINT32 BrowserStatus,
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_IFR_OP_HEADER *OpCode OPTIONAL,
- IN CHAR16 *ErrorString
- )
-{
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- USER_INPUT UserInputData;
-
- Statement = NULL;
-
- if (OpCode != NULL) {
- Statement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
- ASSERT (Statement != NULL);
- Statement->OpCode = OpCode;
- gDisplayFormData.HighLightedStatement = Statement;
- }
-
- //
- // Used to compatible with old display engine.
- // New display engine not use this field.
- //
- gDisplayFormData.ErrorString = ErrorString;
- gDisplayFormData.BrowserStatus = BrowserStatus;
-
- if (HiiHandle != NULL) {
- gDisplayFormData.HiiHandle = HiiHandle;
- }
-
- mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData);
-
- gDisplayFormData.BrowserStatus = BROWSER_SUCCESS;
- gDisplayFormData.ErrorString = NULL;
-
- if (OpCode != NULL) {
- FreePool (Statement);
- }
-
- return UserInputData.Action;
-}
-
-/**
- This is the routine which an external caller uses to direct the browser
- where to obtain it's information.
-
-
- @param This The Form Browser protocol instanse.
- @param Handles A pointer to an array of Handles. If HandleCount > 1 we
- display a list of the formsets for the handles specified.
- @param HandleCount The number of Handles specified in Handle.
- @param FormSetGuid This field points to the EFI_GUID which must match the Guid
- field in the EFI_IFR_FORM_SET op-code for the specified
- forms-based package. If FormSetGuid is NULL, then this
- function will display the first found forms package.
- @param FormId This field specifies which EFI_IFR_FORM to render as the first
- displayable page. If this field has a value of 0x0000, then
- the forms browser will render the specified forms in their encoded order.
- @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
- characters.
- @param ActionRequest Points to the action recommended by the form.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_NOT_FOUND No valid forms could be found to display.
-
-**/
-EFI_STATUS
-EFIAPI
-SendForm (
- IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
- IN EFI_HII_HANDLE *Handles,
- IN UINTN HandleCount,
- IN EFI_GUID *FormSetGuid OPTIONAL,
- IN UINT16 FormId OPTIONAL,
- IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions OPTIONAL,
- OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL
- )
-{
- EFI_STATUS Status;
- UI_MENU_SELECTION *Selection;
- UINTN Index;
- FORM_BROWSER_FORMSET *FormSet;
- FORM_ENTRY_INFO *MenuList;
- BOOLEAN RetVal;
-
- //
- // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.
- //
- if (mFormDisplay == NULL) {
- DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!"));
- return EFI_UNSUPPORTED;
- }
-
- //
- // Save globals used by SendForm()
- //
- SaveBrowserContext ();
-
- gFlagReconnect = FALSE;
- gResetRequiredFormLevel = FALSE;
- gExitRequired = FALSE;
- gCallbackReconnect = FALSE;
- Status = EFI_SUCCESS;
- gEmptyString = L"";
- gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *)ScreenDimensions;
-
- for (Index = 0; Index < HandleCount; Index++) {
- Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
- ASSERT (Selection != NULL);
-
- Selection->Handle = Handles[Index];
- if (FormSetGuid != NULL) {
- CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
- Selection->FormId = FormId;
- } else {
- CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));
- }
-
- do {
- FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
- ASSERT (FormSet != NULL);
-
- //
- // Validate the HiiHandle
- // if validate failed, find the first validate parent HiiHandle.
- //
- if (!ValidateHiiHandle (Selection->Handle)) {
- FindNextMenu (Selection, FormSetLevel);
- }
-
- //
- // Initialize internal data structures of FormSet
- //
- Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
- if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
- DestroyFormSet (FormSet);
- break;
- }
-
- Selection->FormSet = FormSet;
- mSystemLevelFormSet = FormSet;
-
- //
- // Display this formset
- //
- gCurrentSelection = Selection;
-
- Status = SetupBrowser (Selection);
-
- gCurrentSelection = NULL;
- mSystemLevelFormSet = NULL;
-
- //
- // Check incoming formset whether is same with previous. If yes, that means action is not exiting of formset so do not reconnect controller.
- //
- if ((gFlagReconnect || gCallbackReconnect) && !CompareGuid (&FormSet->Guid, &Selection->FormSetGuid)) {
- RetVal = ReconnectController (FormSet->DriverHandle);
- if (!RetVal) {
- PopupErrorMessage (BROWSER_RECONNECT_FAIL, NULL, NULL, NULL);
- }
-
- gFlagReconnect = FALSE;
- gCallbackReconnect = FALSE;
- }
-
- //
- // If no data is changed, don't need to save current FormSet into the maintain list.
- //
- if (!IsNvUpdateRequiredForFormSet (FormSet)) {
- CleanBrowserStorage (FormSet);
- RemoveEntryList (&FormSet->Link);
- DestroyFormSet (FormSet);
- }
-
- if (EFI_ERROR (Status)) {
- break;
- }
- } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
-
- FreePool (Selection);
- }
-
- if (ActionRequest != NULL) {
- *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- if (gResetRequiredFormLevel) {
- *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
- }
- }
-
- mFormDisplay->ExitDisplay ();
-
- //
- // Clear the menu history data.
- //
- while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
- MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
- RemoveEntryList (&MenuList->Link);
- FreePool (MenuList);
- }
-
- //
- // Restore globals used by SendForm()
- //
- RestoreBrowserContext ();
-
- return Status;
-}
-
-/**
- Get or set data to the storage.
-
- @param ResultsDataSize The size of the buffer associatedwith ResultsData.
- @param ResultsData A string returned from an IFR browser or
- equivalent. The results string will have no
- routing information in them.
- @param RetrieveData A BOOLEAN field which allows an agent to retrieve
- (if RetrieveData = TRUE) data from the uncommitted
- browser state information or set (if RetrieveData
- = FALSE) data in the uncommitted browser state
- information.
- @param Storage The pointer to the storage.
-
- @retval EFI_SUCCESS The results have been distributed or are awaiting
- distribution.
-
-**/
-EFI_STATUS
-ProcessStorage (
- IN OUT UINTN *ResultsDataSize,
- IN OUT EFI_STRING *ResultsData,
- IN BOOLEAN RetrieveData,
- IN BROWSER_STORAGE *Storage
- )
-{
- CHAR16 *ConfigResp;
- EFI_STATUS Status;
- CHAR16 *StrPtr;
- UINTN BufferSize;
- UINTN TmpSize;
- UINTN MaxLen;
- FORMSET_STORAGE *BrowserStorage;
-
- if (RetrieveData) {
- //
- // Generate <ConfigResp>
- //
- Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.
- // Also need to consider add "\0" at first time.
- //
- StrPtr = StrStr (ConfigResp, L"PATH");
- ASSERT (StrPtr != NULL);
- StrPtr = StrStr (StrPtr, L"&");
- StrPtr += 1;
- BufferSize = StrSize (StrPtr);
-
- //
- // Copy the data if the input buffer is bigger enough.
- //
- if (*ResultsDataSize >= BufferSize) {
- StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr);
- }
-
- *ResultsDataSize = BufferSize;
- FreePool (ConfigResp);
- } else {
- //
- // Prepare <ConfigResp>
- //
- BrowserStorage = GetFstStgFromBrsStg (Storage);
- ASSERT (BrowserStorage != NULL);
- TmpSize = StrLen (*ResultsData);
- BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);
- MaxLen = BufferSize / sizeof (CHAR16);
- ConfigResp = AllocateZeroPool (BufferSize);
- ASSERT (ConfigResp != NULL);
-
- StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr);
- StrCatS (ConfigResp, MaxLen, L"&");
- StrCatS (ConfigResp, MaxLen, *ResultsData);
-
- //
- // Update Browser uncommited data
- //
- Status = ConfigRespToStorage (Storage, ConfigResp);
- FreePool (ConfigResp);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This routine called this service in the browser to retrieve or set certain uncommitted
- state information that resides in the open formsets.
-
- @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
- instance.
- @param ResultsDataSize A pointer to the size of the buffer associated
- with ResultsData.
- @param ResultsData A string returned from an IFR browser or
- equivalent. The results string will have no
- routing information in them.
- @param RetrieveData A BOOLEAN field which allows an agent to retrieve
- (if RetrieveData = TRUE) data from the uncommitted
- browser state information or set (if RetrieveData
- = FALSE) data in the uncommitted browser state
- information.
- @param VariableGuid An optional field to indicate the target variable
- GUID name to use.
- @param VariableName An optional field to indicate the target
- human-readable variable name.
-
- @retval EFI_SUCCESS The results have been distributed or are awaiting
- distribution.
- @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
- contain the results data.
-
-**/
-EFI_STATUS
-EFIAPI
-BrowserCallback (
- IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
- IN OUT UINTN *ResultsDataSize,
- IN OUT EFI_STRING ResultsData,
- IN BOOLEAN RetrieveData,
- IN CONST EFI_GUID *VariableGuid OPTIONAL,
- IN CONST CHAR16 *VariableName OPTIONAL
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormsetStorage;
- UINTN TotalSize;
- BOOLEAN Found;
-
- if ((ResultsDataSize == NULL) || (ResultsData == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- TotalSize = *ResultsDataSize;
- Storage = NULL;
- Found = FALSE;
- Status = EFI_SUCCESS;
-
- if (VariableGuid != NULL) {
- //
- // Try to find target storage in the current formset.
- //
- Link = GetFirstNode (&gBrowserStorageList);
- while (!IsNull (&gBrowserStorageList, Link)) {
- Storage = BROWSER_STORAGE_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserStorageList, Link);
- //
- // Check the current storage.
- //
- if (!CompareGuid (&Storage->Guid, (EFI_GUID *)VariableGuid)) {
- continue;
- }
-
- if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER))
- {
- //
- // Buffer storage require both GUID and Name
- //
- if (VariableName == NULL) {
- return EFI_NOT_FOUND;
- }
-
- if (StrCmp (Storage->Name, (CHAR16 *)VariableName) != 0) {
- continue;
- }
- }
-
- if ((Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) ||
- (Storage->Type == EFI_HII_VARSTORE_BUFFER))
- {
- if ((mSystemLevelFormSet == NULL) || (mSystemLevelFormSet->HiiHandle == NULL)) {
- return EFI_NOT_FOUND;
- }
-
- if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {
- continue;
- }
- }
-
- Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
- ConfigRequestAdjust (Storage, ResultsData, TRUE);
- }
-
- //
- // Different formsets may have same varstore, so here just set the flag
- // not exit the circle.
- //
- Found = TRUE;
- break;
- }
-
- if (!Found) {
- return EFI_NOT_FOUND;
- }
- } else {
- //
- // GUID/Name is not specified, take the first storage in FormSet
- //
- if (mSystemLevelFormSet == NULL) {
- return EFI_NOT_READY;
- }
-
- //
- // Generate <ConfigResp>
- //
- Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);
- if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {
- return EFI_UNSUPPORTED;
- }
-
- FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
-
- Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- if (RetrieveData) {
- Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
- *ResultsDataSize = TotalSize;
- }
-
- return Status;
-}
-
-/**
- Callback function for SimpleTextInEx protocol install events
-
- @param Event the event that is signaled.
- @param Context not used here.
-
-**/
-VOID
-EFIAPI
-FormDisplayCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- if (mFormDisplay != NULL) {
- return;
- }
-
- gBS->LocateProtocol (
- &gEdkiiFormDisplayEngineProtocolGuid,
- NULL,
- (VOID **)&mFormDisplay
- );
-}
-
-/**
- Initialize Setup Browser driver.
-
- @param ImageHandle The image handle.
- @param SystemTable The system table.
-
- @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
- @return Other value if failed to initialize the Setup Browser module.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeSetup (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- VOID *Registration;
-
- //
- // Locate required Hii relative protocols
- //
- Status = gBS->LocateProtocol (
- &gEfiHiiDatabaseProtocolGuid,
- NULL,
- (VOID **)&mHiiDatabase
- );
- ASSERT_EFI_ERROR (Status);
-
- Status = gBS->LocateProtocol (
- &gEfiHiiConfigRoutingProtocolGuid,
- NULL,
- (VOID **)&mHiiConfigRouting
- );
- ASSERT_EFI_ERROR (Status);
-
- Status = gBS->LocateProtocol (
- &gEfiDevicePathFromTextProtocolGuid,
- NULL,
- (VOID **)&mPathFromText
- );
-
- //
- // Install FormBrowser2 protocol
- //
- mPrivateData.Handle = NULL;
- Status = gBS->InstallProtocolInterface (
- &mPrivateData.Handle,
- &gEfiFormBrowser2ProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mPrivateData.FormBrowser2
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Install FormBrowserEx2 protocol
- //
- InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
- InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
- mPrivateData.Handle = NULL;
- Status = gBS->InstallProtocolInterface (
- &mPrivateData.Handle,
- &gEdkiiFormBrowserEx2ProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mPrivateData.FormBrowserEx2
- );
- ASSERT_EFI_ERROR (Status);
-
- Status = gBS->InstallProtocolInterface (
- &mPrivateData.Handle,
- &gEdkiiFormBrowserExProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mPrivateData.FormBrowserEx
- );
- ASSERT_EFI_ERROR (Status);
-
- InitializeDisplayFormData ();
-
- Status = gBS->LocateProtocol (
- &gEdkiiFormDisplayEngineProtocolGuid,
- NULL,
- (VOID **)&mFormDisplay
- );
-
- if (EFI_ERROR (Status)) {
- EfiCreateProtocolNotifyEvent (
- &gEdkiiFormDisplayEngineProtocolGuid,
- TPL_CALLBACK,
- FormDisplayCallback,
- NULL,
- &Registration
- );
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Create a new string in HII Package List.
-
- @param String The String to be added
- @param HiiHandle The package list in the HII database to insert the
- specified string.
-
- @return The output string.
-
-**/
-EFI_STRING_ID
-NewString (
- IN CHAR16 *String,
- IN EFI_HII_HANDLE HiiHandle
- )
-{
- EFI_STRING_ID StringId;
-
- StringId = HiiSetString (HiiHandle, 0, String, NULL);
- ASSERT (StringId != 0);
-
- return StringId;
-}
-
-/**
- Delete a string from HII Package List.
-
- @param StringId Id of the string in HII database.
- @param HiiHandle The HII package list handle.
-
- @retval EFI_SUCCESS The string was deleted successfully.
-
-**/
-EFI_STATUS
-DeleteString (
- IN EFI_STRING_ID StringId,
- IN EFI_HII_HANDLE HiiHandle
- )
-{
- CHAR16 NullChar;
-
- NullChar = CHAR_NULL;
- HiiSetString (HiiHandle, StringId, &NullChar, NULL);
- return EFI_SUCCESS;
-}
-
-/**
- Get the string based on the StringId and HII Package List Handle.
-
- @param Token The String's ID.
- @param HiiHandle The package list in the HII database to search for
- the specified string.
-
- @return The output string.
-
-**/
-CHAR16 *
-GetToken (
- IN EFI_STRING_ID Token,
- IN EFI_HII_HANDLE HiiHandle
- )
-{
- EFI_STRING String;
-
- if (HiiHandle == NULL) {
- return NULL;
- }
-
- String = HiiGetString (HiiHandle, Token, NULL);
- if (String == NULL) {
- String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
- ASSERT (String != NULL);
- }
-
- return (CHAR16 *)String;
-}
-
-/**
- Allocate new memory and then copy the Unicode string Source to Destination.
-
- @param Dest Location to copy string
- @param Src String to copy
-
-**/
-VOID
-NewStringCpy (
- IN OUT CHAR16 **Dest,
- IN CHAR16 *Src
- )
-{
- if (*Dest != NULL) {
- FreePool (*Dest);
- }
-
- *Dest = AllocateCopyPool (StrSize (Src), Src);
- ASSERT (*Dest != NULL);
-}
-
-/**
- Allocate new memory and concatinate Source on the end of Destination.
-
- @param Dest String to added to the end of.
- @param Src String to concatinate.
-
-**/
-VOID
-NewStringCat (
- IN OUT CHAR16 **Dest,
- IN CHAR16 *Src
- )
-{
- CHAR16 *NewString;
- UINTN MaxLen;
-
- if (*Dest == NULL) {
- NewStringCpy (Dest, Src);
- return;
- }
-
- MaxLen = (StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16);
- NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (NewString != NULL);
-
- StrCpyS (NewString, MaxLen, *Dest);
- StrCatS (NewString, MaxLen, Src);
-
- FreePool (*Dest);
- *Dest = NewString;
-}
-
-/**
- Get Value for given Name from a NameValue Storage.
-
- @param Storage The NameValue Storage.
- @param Name The Name.
- @param Value The retured Value.
- @param GetValueFrom Where to get source value, from EditValue or Value.
-
- @retval EFI_SUCCESS Value found for given Name.
- @retval EFI_NOT_FOUND No such Name found in NameValue storage.
-
-**/
-EFI_STATUS
-GetValueByName (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Name,
- IN OUT CHAR16 **Value,
- IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
- )
-{
- LIST_ENTRY *Link;
- NAME_VALUE_NODE *Node;
-
- if ((GetValueFrom != GetSetValueWithEditBuffer) && (GetValueFrom != GetSetValueWithBuffer)) {
- return EFI_INVALID_PARAMETER;
- }
-
- *Value = NULL;
-
- Link = GetFirstNode (&Storage->NameValueListHead);
- while (!IsNull (&Storage->NameValueListHead, Link)) {
- Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
- if (StrCmp (Name, Node->Name) == 0) {
- if (GetValueFrom == GetSetValueWithEditBuffer) {
- NewStringCpy (Value, Node->EditValue);
- } else {
- NewStringCpy (Value, Node->Value);
- }
-
- return EFI_SUCCESS;
- }
-
- Link = GetNextNode (&Storage->NameValueListHead, Link);
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Set Value of given Name in a NameValue Storage.
-
- @param Storage The NameValue Storage.
- @param Name The Name.
- @param Value The Value to set.
- @param SetValueTo Whether update editValue or Value.
- @param ReturnNode The node use the input name.
-
- @retval EFI_SUCCESS Value found for given Name.
- @retval EFI_NOT_FOUND No such Name found in NameValue storage.
-
-**/
-EFI_STATUS
-SetValueByName (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Name,
- IN CHAR16 *Value,
- IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
- OUT NAME_VALUE_NODE **ReturnNode
- )
-{
- LIST_ENTRY *Link;
- NAME_VALUE_NODE *Node;
- CHAR16 *Buffer;
-
- if ((SetValueTo != GetSetValueWithEditBuffer) && (SetValueTo != GetSetValueWithBuffer)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Link = GetFirstNode (&Storage->NameValueListHead);
- while (!IsNull (&Storage->NameValueListHead, Link)) {
- Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
- if (StrCmp (Name, Node->Name) == 0) {
- if (SetValueTo == GetSetValueWithEditBuffer) {
- Buffer = Node->EditValue;
- } else {
- Buffer = Node->Value;
- }
-
- if (Buffer != NULL) {
- FreePool (Buffer);
- }
-
- Buffer = AllocateCopyPool (StrSize (Value), Value);
- ASSERT (Buffer != NULL);
- if (SetValueTo == GetSetValueWithEditBuffer) {
- Node->EditValue = Buffer;
- } else {
- Node->Value = Buffer;
- }
-
- if (ReturnNode != NULL) {
- *ReturnNode = Node;
- }
-
- return EFI_SUCCESS;
- }
-
- Link = GetNextNode (&Storage->NameValueListHead, Link);
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
-
- @param Storage The Storage to be conveted.
- @param ConfigResp The returned <ConfigResp>.
- @param ConfigRequest The ConfigRequest string.
- @param GetEditBuf Get the data from editbuffer or buffer.
-
- @retval EFI_SUCCESS Convert success.
- @retval EFI_INVALID_PARAMETER Incorrect storage type.
-
-**/
-EFI_STATUS
-StorageToConfigResp (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 **ConfigResp,
- IN CHAR16 *ConfigRequest,
- IN BOOLEAN GetEditBuf
- )
-{
- EFI_STATUS Status;
- EFI_STRING Progress;
- LIST_ENTRY *Link;
- NAME_VALUE_NODE *Node;
- UINT8 *SourceBuf;
- FORMSET_STORAGE *FormsetStorage;
-
- Status = EFI_SUCCESS;
-
- switch (Storage->Type) {
- case EFI_HII_VARSTORE_BUFFER:
- case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
- SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;
- Status = mHiiConfigRouting->BlockToConfig (
- mHiiConfigRouting,
- ConfigRequest,
- SourceBuf,
- Storage->Size,
- ConfigResp,
- &Progress
- );
- break;
-
- case EFI_HII_VARSTORE_NAME_VALUE:
- *ConfigResp = NULL;
- FormsetStorage = GetFstStgFromBrsStg (Storage);
- ASSERT (FormsetStorage != NULL);
- NewStringCat (ConfigResp, FormsetStorage->ConfigHdr);
-
- Link = GetFirstNode (&Storage->NameValueListHead);
- while (!IsNull (&Storage->NameValueListHead, Link)) {
- Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
- if (StrStr (ConfigRequest, Node->Name) != NULL) {
- NewStringCat (ConfigResp, L"&");
- NewStringCat (ConfigResp, Node->Name);
- NewStringCat (ConfigResp, L"=");
- if (GetEditBuf) {
- NewStringCat (ConfigResp, Node->EditValue);
- } else {
- NewStringCat (ConfigResp, Node->Value);
- }
- }
-
- Link = GetNextNode (&Storage->NameValueListHead, Link);
- }
-
- break;
-
- case EFI_HII_VARSTORE_EFI_VARIABLE:
- default:
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- return Status;
-}
-
-/**
- Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
-
- @param Storage The Storage to receive the settings.
- @param ConfigResp The <ConfigResp> to be converted.
-
- @retval EFI_SUCCESS Convert success.
- @retval EFI_INVALID_PARAMETER Incorrect storage type.
-
-**/
-EFI_STATUS
-ConfigRespToStorage (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *ConfigResp
- )
-{
- EFI_STATUS Status;
- EFI_STRING Progress;
- UINTN BufferSize;
- CHAR16 *StrPtr;
- CHAR16 *Name;
- CHAR16 *Value;
-
- Status = EFI_SUCCESS;
-
- switch (Storage->Type) {
- case EFI_HII_VARSTORE_BUFFER:
- case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
- BufferSize = Storage->Size;
- Status = mHiiConfigRouting->ConfigToBlock (
- mHiiConfigRouting,
- ConfigResp,
- Storage->EditBuffer,
- &BufferSize,
- &Progress
- );
- break;
-
- case EFI_HII_VARSTORE_NAME_VALUE:
- StrPtr = StrStr (ConfigResp, L"PATH");
- if (StrPtr == NULL) {
- break;
- }
-
- StrPtr = StrStr (ConfigResp, L"&");
- while (StrPtr != NULL) {
- //
- // Skip '&'
- //
- StrPtr = StrPtr + 1;
- Name = StrPtr;
- StrPtr = StrStr (StrPtr, L"=");
- if (StrPtr == NULL) {
- break;
- }
-
- *StrPtr = 0;
-
- //
- // Skip '='
- //
- StrPtr = StrPtr + 1;
- Value = StrPtr;
- StrPtr = StrStr (StrPtr, L"&");
- if (StrPtr != NULL) {
- *StrPtr = 0;
- }
-
- SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);
- }
-
- break;
-
- case EFI_HII_VARSTORE_EFI_VARIABLE:
- default:
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- return Status;
-}
-
-/**
- Get bit field value from the buffer and then set the value for the question.
- Note: Data type UINT32 can cover all the bit field value.
-
- @param Question The question refer to bit field.
- @param Buffer Point to the buffer which the question value get from.
-
-**/
-VOID
-GetBitsQuestionValue (
- IN FORM_BROWSER_STATEMENT *Question,
- IN UINT8 *Buffer
- )
-{
- UINTN StartBit;
- UINTN EndBit;
- UINT32 RetVal;
- UINT32 BufferValue;
-
- StartBit = Question->BitVarOffset % 8;
- EndBit = StartBit + Question->BitStorageWidth - 1;
-
- CopyMem ((UINT8 *)&BufferValue, Buffer, Question->StorageWidth);
-
- RetVal = BitFieldRead32 (BufferValue, StartBit, EndBit);
-
- //
- // Set question value.
- // Note: Since Question with BufferValue (orderedlist, password, string)are not supported to refer bit field.
- // Only oneof/checkbox/oneof can support bit field.So we can copy the value to the Hiivalue of Question directly.
- //
- CopyMem ((UINT8 *)&Question->HiiValue.Value, (UINT8 *)&RetVal, Question->StorageWidth);
-}
-
-/**
- Set bit field value to the buffer.
- Note: Data type UINT32 can cover all the bit field value.
-
- @param Question The question refer to bit field.
- @param Buffer Point to the buffer which the question value set to.
- @param Value The bit field value need to set.
-
-**/
-VOID
-SetBitsQuestionValue (
- IN FORM_BROWSER_STATEMENT *Question,
- IN OUT UINT8 *Buffer,
- IN UINT32 Value
- )
-{
- UINT32 Operand;
- UINTN StartBit;
- UINTN EndBit;
- UINT32 RetVal;
-
- StartBit = Question->BitVarOffset % 8;
- EndBit = StartBit + Question->BitStorageWidth - 1;
-
- CopyMem ((UINT8 *)&Operand, Buffer, Question->StorageWidth);
-
- RetVal = BitFieldWrite32 (Operand, StartBit, EndBit, Value);
-
- CopyMem (Buffer, (UINT8 *)&RetVal, Question->StorageWidth);
-}
-
-/**
- Convert the buffer value to HiiValue.
-
- @param Question The question.
- @param Value Unicode buffer save the question value.
-
- @retval Status whether convert the value success.
-
-**/
-EFI_STATUS
-BufferToValue (
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN CHAR16 *Value
- )
-{
- CHAR16 *StringPtr;
- BOOLEAN IsBufferStorage;
- CHAR16 *DstBuf;
- CHAR16 TempChar;
- UINTN LengthStr;
- UINT8 *Dst;
- CHAR16 TemStr[5];
- UINTN Index;
- UINT8 DigitUint8;
- BOOLEAN IsString;
- UINTN Length;
- EFI_STATUS Status;
- UINT8 *Buffer;
-
- Buffer = NULL;
-
- IsString = (BOOLEAN)((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
- if ((Question->Storage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER))
- {
- IsBufferStorage = TRUE;
- } else {
- IsBufferStorage = FALSE;
- }
-
- //
- // Question Value is provided by Buffer Storage or NameValue Storage
- //
- if (Question->BufferValue != NULL) {
- //
- // This Question is password or orderedlist
- //
- Dst = Question->BufferValue;
- } else {
- //
- // Other type of Questions
- //
- if (Question->QuestionReferToBitField) {
- Buffer = (UINT8 *)AllocateZeroPool (Question->StorageWidth);
- if (Buffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Dst = Buffer;
- } else {
- Dst = (UINT8 *)&Question->HiiValue.Value;
- }
- }
-
- //
- // Temp cut at the end of this section, end with '\0' or '&'.
- //
- StringPtr = Value;
- while (*StringPtr != L'\0' && *StringPtr != L'&') {
- StringPtr++;
- }
-
- TempChar = *StringPtr;
- *StringPtr = L'\0';
-
- LengthStr = StrLen (Value);
-
- //
- // Value points to a Unicode hexadecimal string, we need to convert the string to the value with CHAR16/UINT8...type.
- // When generating the Value string, we follow this rule: 1 byte -> 2 Unicode characters (for string: 2 byte(CHAR16) ->4 Unicode characters).
- // So the maximum value string length of a question is : Question->StorageWidth * 2.
- // If the value string length > Question->StorageWidth * 2, only set the string length as Question->StorageWidth * 2, then convert.
- //
- if (LengthStr > (UINTN)Question->StorageWidth * 2) {
- Length = (UINTN)Question->StorageWidth * 2;
- } else {
- Length = LengthStr;
- }
-
- Status = EFI_SUCCESS;
- if (!IsBufferStorage && IsString) {
- //
- // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
- // Add string tail char L'\0' into Length
- //
- DstBuf = (CHAR16 *)Dst;
- ZeroMem (TemStr, sizeof (TemStr));
- for (Index = 0; Index < Length; Index += 4) {
- StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4);
- DstBuf[Index/4] = (CHAR16)StrHexToUint64 (TemStr);
- }
-
- //
- // Add tailing L'\0' character
- //
- DstBuf[Index/4] = L'\0';
- } else {
- ZeroMem (TemStr, sizeof (TemStr));
- for (Index = 0; Index < Length; Index++) {
- TemStr[0] = Value[LengthStr - Index - 1];
- DigitUint8 = (UINT8)StrHexToUint64 (TemStr);
- if ((Index & 1) == 0) {
- Dst[Index/2] = DigitUint8;
- } else {
- Dst[Index/2] = (UINT8)((DigitUint8 << 4) + Dst[Index/2]);
- }
- }
- }
-
- *StringPtr = TempChar;
-
- if ((Buffer != NULL) && Question->QuestionReferToBitField) {
- GetBitsQuestionValue (Question, Buffer);
- FreePool (Buffer);
- }
-
- return Status;
-}
-
-/**
- Get Question's current Value.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question Question to be initialized.
- @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-GetQuestionValue (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
- )
-{
- EFI_STATUS Status;
- BOOLEAN Enabled;
- BOOLEAN Pending;
- UINT8 *Dst;
- UINTN StorageWidth;
- EFI_TIME EfiTime;
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormsetStorage;
- EFI_IFR_TYPE_VALUE *QuestionValue;
- CHAR16 *ConfigRequest;
- CHAR16 *Progress;
- CHAR16 *Result;
- CHAR16 *Value;
- UINTN Length;
- BOOLEAN IsBufferStorage;
- UINTN MaxLen;
-
- Status = EFI_SUCCESS;
- Value = NULL;
- Result = NULL;
-
- if (GetValueFrom >= GetSetValueWithMax) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Question value is provided by an Expression, evaluate it
- //
- if (Question->ValueExpression != NULL) {
- Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
- if (!EFI_ERROR (Status)) {
- if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
- ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
- if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
- CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
- Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
- } else {
- CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
- Question->HiiValue.BufferLen = Question->StorageWidth;
- }
-
- FreePool (Question->ValueExpression->Result.Buffer);
- }
-
- Question->HiiValue.Type = Question->ValueExpression->Result.Type;
- CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
- }
-
- return Status;
- }
-
- //
- // Get question value by read expression.
- //
- if ((Question->ReadExpression != NULL) && (Form->FormType == STANDARD_MAP_FORM_TYPE)) {
- Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
- if (!EFI_ERROR (Status) &&
- ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER)))
- {
- //
- // Only update question value to the valid result.
- //
- if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
- ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
- if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
- CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
- Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
- } else {
- CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
- Question->HiiValue.BufferLen = Question->StorageWidth;
- }
-
- FreePool (Question->ReadExpression->Result.Buffer);
- }
-
- Question->HiiValue.Type = Question->ReadExpression->Result.Type;
- CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
- return EFI_SUCCESS;
- }
- }
-
- //
- // Question value is provided by RTC
- //
- Storage = Question->Storage;
- QuestionValue = &Question->HiiValue.Value;
- if (Storage == NULL) {
- //
- // It's a Question without storage, or RTC date/time
- //
- if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) {
- //
- // Date and time define the same Flags bit
- //
- switch (Question->Flags & EFI_QF_DATE_STORAGE) {
- case QF_DATE_STORAGE_TIME:
- Status = gRT->GetTime (&EfiTime, NULL);
- break;
-
- case QF_DATE_STORAGE_WAKEUP:
- Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
- break;
-
- case QF_DATE_STORAGE_NORMAL:
- default:
- //
- // For date/time without storage
- //
- return EFI_SUCCESS;
- }
-
- if (EFI_ERROR (Status)) {
- if (Question->Operand == EFI_IFR_DATE_OP) {
- QuestionValue->date.Year = 0xff;
- QuestionValue->date.Month = 0xff;
- QuestionValue->date.Day = 0xff;
- } else {
- QuestionValue->time.Hour = 0xff;
- QuestionValue->time.Minute = 0xff;
- QuestionValue->time.Second = 0xff;
- }
-
- return EFI_SUCCESS;
- }
-
- if (Question->Operand == EFI_IFR_DATE_OP) {
- QuestionValue->date.Year = EfiTime.Year;
- QuestionValue->date.Month = EfiTime.Month;
- QuestionValue->date.Day = EfiTime.Day;
- } else {
- QuestionValue->time.Hour = EfiTime.Hour;
- QuestionValue->time.Minute = EfiTime.Minute;
- QuestionValue->time.Second = EfiTime.Second;
- }
- }
-
- return EFI_SUCCESS;
- }
-
- //
- // Question value is provided by EFI variable
- //
- StorageWidth = Question->StorageWidth;
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- if (Question->BufferValue != NULL) {
- Dst = Question->BufferValue;
- } else {
- Dst = (UINT8 *)QuestionValue;
- }
-
- Status = gRT->GetVariable (
- Question->VariableName,
- &Storage->Guid,
- NULL,
- &StorageWidth,
- Dst
- );
- //
- // Always return success, even this EFI variable doesn't exist
- //
- return EFI_SUCCESS;
- }
-
- //
- // Question Value is provided by Buffer Storage or NameValue Storage
- //
- if (Question->BufferValue != NULL) {
- //
- // This Question is password or orderedlist
- //
- Dst = Question->BufferValue;
- } else {
- //
- // Other type of Questions
- //
- Dst = (UINT8 *)&Question->HiiValue.Value;
- }
-
- if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER))
- {
- IsBufferStorage = TRUE;
- } else {
- IsBufferStorage = FALSE;
- }
-
- if ((GetValueFrom == GetSetValueWithEditBuffer) || (GetValueFrom == GetSetValueWithBuffer)) {
- if (IsBufferStorage) {
- if (GetValueFrom == GetSetValueWithEditBuffer) {
- //
- // Copy from storage Edit buffer
- // If the Question refer to bit filed, get the value in the related bit filed.
- //
- if (Question->QuestionReferToBitField) {
- GetBitsQuestionValue (Question, Storage->EditBuffer + Question->VarStoreInfo.VarOffset);
- } else {
- CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
- }
- } else {
- //
- // Copy from storage Edit buffer
- // If the Question refer to bit filed, get the value in the related bit filed.
- //
- if (Question->QuestionReferToBitField) {
- GetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset);
- } else {
- CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
- }
- }
- } else {
- Value = NULL;
- Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ASSERT (Value != NULL);
- Status = BufferToValue (Question, Value);
- FreePool (Value);
- }
- } else {
- FormsetStorage = GetFstStgFromVarId (FormSet, Question->VarStoreId);
- ASSERT (FormsetStorage != NULL);
- //
- // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
- // <ConfigHdr> + "&" + <VariableName>
- //
- if (IsBufferStorage) {
- Length = StrLen (FormsetStorage->ConfigHdr);
- Length += StrLen (Question->BlockName);
- } else {
- Length = StrLen (FormsetStorage->ConfigHdr);
- Length += StrLen (Question->VariableName) + 1;
- }
-
- // Allocate buffer include '\0'
- MaxLen = Length + 1;
- ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (ConfigRequest != NULL);
-
- StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr);
- if (IsBufferStorage) {
- StrCatS (ConfigRequest, MaxLen, Question->BlockName);
- } else {
- StrCatS (ConfigRequest, MaxLen, L"&");
- StrCatS (ConfigRequest, MaxLen, Question->VariableName);
- }
-
- //
- // Request current settings from Configuration Driver
- //
- Status = mHiiConfigRouting->ExtractConfig (
- mHiiConfigRouting,
- ConfigRequest,
- &Progress,
- &Result
- );
- FreePool (ConfigRequest);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Skip <ConfigRequest>
- //
- if (IsBufferStorage) {
- Value = StrStr (Result, L"&VALUE");
- if (Value == NULL) {
- FreePool (Result);
- return EFI_NOT_FOUND;
- }
-
- //
- // Skip "&VALUE"
- //
- Value = Value + 6;
- } else {
- Value = Result + Length;
- }
-
- if (*Value != '=') {
- FreePool (Result);
- return EFI_NOT_FOUND;
- }
-
- //
- // Skip '=', point to value
- //
- Value = Value + 1;
-
- Status = BufferToValue (Question, Value);
- if (EFI_ERROR (Status)) {
- FreePool (Result);
- return Status;
- }
-
- //
- // Synchronize Edit Buffer
- //
- if (IsBufferStorage) {
- CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
- } else {
- SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
- }
-
- if (Result != NULL) {
- FreePool (Result);
- }
- }
-
- return Status;
-}
-
-/**
- Save Question Value to edit copy(cached) or Storage(uncached).
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question Pointer to the Question.
- @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-SetQuestionValue (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN GET_SET_QUESTION_VALUE_WITH SetValueTo
- )
-{
- EFI_STATUS Status;
- BOOLEAN Enabled;
- BOOLEAN Pending;
- UINT8 *Src;
- EFI_TIME EfiTime;
- UINTN BufferLen;
- UINTN StorageWidth;
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormsetStorage;
- EFI_IFR_TYPE_VALUE *QuestionValue;
- CHAR16 *ConfigResp;
- CHAR16 *Progress;
- CHAR16 *Value;
- UINTN Length;
- BOOLEAN IsBufferStorage;
- BOOLEAN IsString;
- UINT8 *TemBuffer;
- CHAR16 *TemName;
- CHAR16 *TemString;
- UINTN Index;
- NAME_VALUE_NODE *Node;
- UINTN MaxLen;
-
- Status = EFI_SUCCESS;
- Node = NULL;
-
- if (SetValueTo >= GetSetValueWithMax) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If Question value is provided by an Expression, then it is read only
- //
- if (Question->ValueExpression != NULL) {
- return Status;
- }
-
- //
- // Before set question value, evaluate its write expression.
- //
- if ((Question->WriteExpression != NULL) && (Form->FormType == STANDARD_MAP_FORM_TYPE)) {
- Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Question value is provided by RTC
- //
- Storage = Question->Storage;
- QuestionValue = &Question->HiiValue.Value;
- if (Storage == NULL) {
- //
- // It's a Question without storage, or RTC date/time
- //
- if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) {
- //
- // Date and time define the same Flags bit
- //
- switch (Question->Flags & EFI_QF_DATE_STORAGE) {
- case QF_DATE_STORAGE_TIME:
- Status = gRT->GetTime (&EfiTime, NULL);
- break;
-
- case QF_DATE_STORAGE_WAKEUP:
- Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
- break;
-
- case QF_DATE_STORAGE_NORMAL:
- default:
- //
- // For date/time without storage
- //
- return EFI_SUCCESS;
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Question->Operand == EFI_IFR_DATE_OP) {
- EfiTime.Year = QuestionValue->date.Year;
- EfiTime.Month = QuestionValue->date.Month;
- EfiTime.Day = QuestionValue->date.Day;
- } else {
- EfiTime.Hour = QuestionValue->time.Hour;
- EfiTime.Minute = QuestionValue->time.Minute;
- EfiTime.Second = QuestionValue->time.Second;
- }
-
- if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
- Status = gRT->SetTime (&EfiTime);
- } else {
- Status = gRT->SetWakeupTime (TRUE, &EfiTime);
- }
- }
-
- return Status;
- }
-
- //
- // Question value is provided by EFI variable
- //
- StorageWidth = Question->StorageWidth;
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- if (Question->BufferValue != NULL) {
- Src = Question->BufferValue;
- } else {
- Src = (UINT8 *)QuestionValue;
- }
-
- Status = gRT->SetVariable (
- Question->VariableName,
- &Storage->Guid,
- Storage->Attributes,
- StorageWidth,
- Src
- );
- return Status;
- }
-
- //
- // Question Value is provided by Buffer Storage or NameValue Storage
- //
- if (Question->BufferValue != NULL) {
- Src = Question->BufferValue;
- } else {
- Src = (UINT8 *)&Question->HiiValue.Value;
- }
-
- if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER))
- {
- IsBufferStorage = TRUE;
- } else {
- IsBufferStorage = FALSE;
- }
-
- IsString = (BOOLEAN)((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
-
- if ((SetValueTo == GetSetValueWithEditBuffer) || (SetValueTo == GetSetValueWithBuffer)) {
- if (IsBufferStorage) {
- if (SetValueTo == GetSetValueWithEditBuffer) {
- //
- // Copy to storage edit buffer
- // If the Question refer to bit filed, copy the value in related bit filed to storage edit buffer.
- //
- if (Question->QuestionReferToBitField) {
- SetBitsQuestionValue (Question, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src));
- } else {
- CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
- }
- } else if (SetValueTo == GetSetValueWithBuffer) {
- //
- // Copy to storage buffer
- // If the Question refer to bit filed, copy the value in related bit filed to storage buffer.
- //
- if (Question->QuestionReferToBitField) {
- SetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src));
- } else {
- CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
- }
- }
- } else {
- if (IsString) {
- //
- // Allocate enough string buffer.
- //
- Value = NULL;
- BufferLen = ((StrLen ((CHAR16 *)Src) * 4) + 1) * sizeof (CHAR16);
- Value = AllocateZeroPool (BufferLen);
- ASSERT (Value != NULL);
- //
- // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
- //
- TemName = (CHAR16 *)Src;
- TemString = Value;
- for ( ; *TemName != L'\0'; TemName++) {
- UnicodeValueToStringS (
- TemString,
- BufferLen - ((UINTN)TemString - (UINTN)Value),
- PREFIX_ZERO | RADIX_HEX,
- *TemName,
- 4
- );
- TemString += StrnLenS (TemString, (BufferLen - ((UINTN)TemString - (UINTN)Value)) / sizeof (CHAR16));
- }
- } else {
- BufferLen = StorageWidth * 2 + 1;
- Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
- ASSERT (Value != NULL);
- //
- // Convert Buffer to Hex String
- //
- TemBuffer = Src + StorageWidth - 1;
- TemString = Value;
- for (Index = 0; Index < StorageWidth; Index++, TemBuffer--) {
- UnicodeValueToStringS (
- TemString,
- BufferLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)Value),
- PREFIX_ZERO | RADIX_HEX,
- *TemBuffer,
- 2
- );
- TemString += StrnLenS (TemString, BufferLen - ((UINTN)TemString - (UINTN)Value) / sizeof (CHAR16));
- }
- }
-
- Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
- FreePool (Value);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- } else if (SetValueTo == GetSetValueWithHiiDriver) {
- //
- // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
- // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
- //
- if (IsBufferStorage) {
- Length = StrLen (Question->BlockName) + 7;
- } else {
- Length = StrLen (Question->VariableName) + 2;
- }
-
- if (!IsBufferStorage && IsString) {
- Length += (StrLen ((CHAR16 *)Src) * 4);
- } else {
- Length += (StorageWidth * 2);
- }
-
- FormsetStorage = GetFstStgFromVarId (FormSet, Question->VarStoreId);
- ASSERT (FormsetStorage != NULL);
- MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1;
- ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (ConfigResp != NULL);
-
- StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr);
- if (IsBufferStorage) {
- StrCatS (ConfigResp, MaxLen, Question->BlockName);
- StrCatS (ConfigResp, MaxLen, L"&VALUE=");
- } else {
- StrCatS (ConfigResp, MaxLen, L"&");
- StrCatS (ConfigResp, MaxLen, Question->VariableName);
- StrCatS (ConfigResp, MaxLen, L"=");
- }
-
- Value = ConfigResp + StrLen (ConfigResp);
-
- if (!IsBufferStorage && IsString) {
- //
- // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
- //
- TemName = (CHAR16 *)Src;
- TemString = Value;
- for ( ; *TemName != L'\0'; TemName++) {
- UnicodeValueToStringS (
- TemString,
- MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp),
- PREFIX_ZERO | RADIX_HEX,
- *TemName,
- 4
- );
- TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16));
- }
- } else {
- //
- // Convert Buffer to Hex String
- //
- TemBuffer = Src + StorageWidth - 1;
- TemString = Value;
- for (Index = 0; Index < StorageWidth; Index++, TemBuffer--) {
- UnicodeValueToStringS (
- TemString,
- MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp),
- PREFIX_ZERO | RADIX_HEX,
- *TemBuffer,
- 2
- );
- TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16));
- }
- }
-
- //
- // Convert to lower char.
- //
- for (TemString = Value; *Value != L'\0'; Value++) {
- if ((*Value >= L'A') && (*Value <= L'Z')) {
- *Value = (CHAR16)(*Value - L'A' + L'a');
- }
- }
-
- //
- // Submit Question Value to Configuration Driver
- //
- Status = mHiiConfigRouting->RouteConfig (
- mHiiConfigRouting,
- ConfigResp,
- &Progress
- );
- if (EFI_ERROR (Status)) {
- FreePool (ConfigResp);
- return Status;
- }
-
- FreePool (ConfigResp);
-
- //
- // Sync storage, from editbuffer to buffer.
- //
- CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
- }
-
- return Status;
-}
-
-/**
- Perform nosubmitif check for a Form.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question The Question to be validated.
- @param Type Validation type: NoSubmit
-
- @retval EFI_SUCCESS Form validation pass.
- @retval other Form validation failed.
-
-**/
-EFI_STATUS
-ValidateQuestion (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question,
- IN UINTN Type
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- LIST_ENTRY *ListHead;
- FORM_EXPRESSION *Expression;
- UINT32 BrowserStatus;
- CHAR16 *ErrorStr;
-
- BrowserStatus = BROWSER_SUCCESS;
- ErrorStr = NULL;
-
- switch (Type) {
- case EFI_HII_EXPRESSION_INCONSISTENT_IF:
- ListHead = &Question->InconsistentListHead;
- break;
-
- case EFI_HII_EXPRESSION_WARNING_IF:
- ListHead = &Question->WarningListHead;
- break;
-
- case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
- ListHead = &Question->NoSubmitListHead;
- break;
-
- default:
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
- }
-
- Link = GetFirstNode (ListHead);
- while (!IsNull (ListHead, Link)) {
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
-
- //
- // Evaluate the expression
- //
- Status = EvaluateExpression (FormSet, Form, Expression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (IsTrue (&Expression->Result)) {
- switch (Type) {
- case EFI_HII_EXPRESSION_INCONSISTENT_IF:
- BrowserStatus = BROWSER_INCONSISTENT_IF;
- break;
-
- case EFI_HII_EXPRESSION_WARNING_IF:
- BrowserStatus = BROWSER_WARNING_IF;
- break;
-
- case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
- BrowserStatus = BROWSER_NO_SUBMIT_IF;
- //
- // This code only used to compatible with old display engine,
- // New display engine will not use this field.
- //
- if (Expression->Error != 0) {
- ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);
- }
-
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
-
- if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {
- //
- // If in system submit process and for no_submit_if check, not popup this error message.
- // Will process this fail again later in not system submit process.
- //
- PopupErrorMessage (BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);
- }
-
- if (ErrorStr != NULL) {
- FreePool (ErrorStr);
- }
-
- if (Type == EFI_HII_EXPRESSION_WARNING_IF) {
- return EFI_SUCCESS;
- } else {
- return EFI_NOT_READY;
- }
- }
-
- Link = GetNextNode (ListHead, Link);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Perform question check.
-
- If one question has more than one check, process form high priority to low.
- Only one error info will be popup.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question The Question to be validated.
-
- @retval EFI_SUCCESS Form validation pass.
- @retval other Form validation failed.
-
-**/
-EFI_STATUS
-ValueChangedValidation (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question
- )
-{
- EFI_STATUS Status;
-
- Status = EFI_SUCCESS;
-
- //
- // Do the inconsistentif check.
- //
- if (!IsListEmpty (&Question->InconsistentListHead)) {
- Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Do the warningif check.
- //
- if (!IsListEmpty (&Question->WarningListHead)) {
- Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);
- }
-
- return Status;
-}
-
-/**
- Perform NoSubmit check for each Form in FormSet.
-
- @param FormSet FormSet data structure.
- @param CurrentForm Current input form data structure.
- @param Statement The statement for this check.
-
- @retval EFI_SUCCESS Form validation pass.
- @retval other Form validation failed.
-
-**/
-EFI_STATUS
-NoSubmitCheck (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN OUT FORM_BROWSER_FORM **CurrentForm,
- OUT FORM_BROWSER_STATEMENT **Statement
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
- FORM_BROWSER_FORM *Form;
- LIST_ENTRY *LinkForm;
-
- LinkForm = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, LinkForm)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
- LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
-
- if ((*CurrentForm != NULL) && (*CurrentForm != Form)) {
- continue;
- }
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
- if (EFI_ERROR (Status)) {
- if (*CurrentForm == NULL) {
- *CurrentForm = Form;
- }
-
- if (Statement != NULL) {
- *Statement = Question;
- }
-
- return Status;
- }
-
- Link = GetNextNode (&Form->StatementListHead, Link);
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Fill storage's edit copy with settings requested from Configuration Driver.
-
- @param Storage The storage which need to sync.
- @param ConfigRequest The config request string which used to sync storage.
- @param SyncOrRestore Sync the buffer to editbuffer or Restore the
- editbuffer to buffer
- if TRUE, copy the editbuffer to the buffer.
- if FALSE, copy the buffer to the editbuffer.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-SynchronizeStorage (
- OUT BROWSER_STORAGE *Storage,
- IN CHAR16 *ConfigRequest,
- IN BOOLEAN SyncOrRestore
- )
-{
- EFI_STATUS Status;
- EFI_STRING Progress;
- EFI_STRING Result;
- UINTN BufferSize;
- LIST_ENTRY *Link;
- NAME_VALUE_NODE *Node;
- UINT8 *Src;
- UINT8 *Dst;
-
- Status = EFI_SUCCESS;
- Result = NULL;
-
- if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER))
- {
- BufferSize = Storage->Size;
-
- if (SyncOrRestore) {
- Src = Storage->EditBuffer;
- Dst = Storage->Buffer;
- } else {
- Src = Storage->Buffer;
- Dst = Storage->EditBuffer;
- }
-
- if (ConfigRequest != NULL) {
- Status = mHiiConfigRouting->BlockToConfig (
- mHiiConfigRouting,
- ConfigRequest,
- Src,
- BufferSize,
- &Result,
- &Progress
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = mHiiConfigRouting->ConfigToBlock (
- mHiiConfigRouting,
- Result,
- Dst,
- &BufferSize,
- &Progress
- );
- if (Result != NULL) {
- FreePool (Result);
- }
- } else {
- CopyMem (Dst, Src, BufferSize);
- }
- } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- Link = GetFirstNode (&Storage->NameValueListHead);
- while (!IsNull (&Storage->NameValueListHead, Link)) {
- Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
- if (((ConfigRequest != NULL) && (StrStr (ConfigRequest, Node->Name) != NULL)) ||
- (ConfigRequest == NULL))
- {
- if (SyncOrRestore) {
- NewStringCpy (&Node->Value, Node->EditValue);
- } else {
- NewStringCpy (&Node->EditValue, Node->Value);
- }
- }
-
- Link = GetNextNode (&Storage->NameValueListHead, Link);
- }
- }
-
- return Status;
-}
-
-/**
- When discard the question value, call the callback function with Changed type
- to inform the hii driver.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
-**/
-VOID
-SendDiscardInfoToDriver (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
- EFI_IFR_TYPE_VALUE *TypeValue;
- EFI_BROWSER_ACTION_REQUEST ActionRequest;
-
- if (FormSet->ConfigAccess == NULL) {
- return;
- }
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&Form->StatementListHead, Link);
-
- if ((Question->Storage == NULL) || (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
- continue;
- }
-
- if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
- continue;
- }
-
- if (Question->Operand == EFI_IFR_PASSWORD_OP) {
- continue;
- }
-
- if (!Question->ValueChanged) {
- continue;
- }
-
- //
- // Restore the question value before call the CHANGED callback type.
- //
- GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
-
- if (Question->Operand == EFI_IFR_STRING_OP) {
- HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16 *)Question->BufferValue, NULL);
- }
-
- if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
- TypeValue = (EFI_IFR_TYPE_VALUE *)Question->BufferValue;
- } else {
- TypeValue = &Question->HiiValue.Value;
- }
-
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- FormSet->ConfigAccess->Callback (
- FormSet->ConfigAccess,
- EFI_BROWSER_ACTION_CHANGED,
- Question->QuestionId,
- Question->HiiValue.Type,
- TypeValue,
- &ActionRequest
- );
- }
-}
-
-/**
- When submit the question value, call the callback function with Submitted type
- to inform the hii driver.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
-**/
-VOID
-SubmitCallbackForForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
- EFI_IFR_TYPE_VALUE *TypeValue;
- EFI_BROWSER_ACTION_REQUEST ActionRequest;
-
- if (FormSet->ConfigAccess == NULL) {
- return;
- }
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&Form->StatementListHead, Link);
-
- if ((Question->Storage == NULL) || (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
- continue;
- }
-
- if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
- continue;
- }
-
- if (Question->Operand == EFI_IFR_PASSWORD_OP) {
- continue;
- }
-
- if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
- TypeValue = (EFI_IFR_TYPE_VALUE *)Question->BufferValue;
- } else {
- TypeValue = &Question->HiiValue.Value;
- }
-
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- FormSet->ConfigAccess->Callback (
- FormSet->ConfigAccess,
- EFI_BROWSER_ACTION_SUBMITTED,
- Question->QuestionId,
- Question->HiiValue.Type,
- TypeValue,
- &ActionRequest
- );
- }
-}
-
-/**
- When value set Success, call the submit callback function.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
-**/
-VOID
-SubmitCallback (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- FORM_BROWSER_FORM *CurrentForm;
- LIST_ENTRY *Link;
-
- if (Form != NULL) {
- SubmitCallbackForForm (FormSet, Form);
- return;
- }
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->FormListHead, Link);
-
- SubmitCallbackForForm (FormSet, CurrentForm);
- }
-}
-
-/**
- Validate the HiiHandle.
-
- @param HiiHandle The input HiiHandle which need to validate.
-
- @retval TRUE The handle is validate.
- @retval FALSE The handle is invalidate.
-
-**/
-BOOLEAN
-ValidateHiiHandle (
- EFI_HII_HANDLE HiiHandle
- )
-{
- EFI_HII_HANDLE *HiiHandles;
- UINTN Index;
- BOOLEAN Find;
-
- if (HiiHandle == NULL) {
- return FALSE;
- }
-
- Find = FALSE;
-
- HiiHandles = HiiGetHiiHandles (NULL);
- ASSERT (HiiHandles != NULL);
-
- for (Index = 0; HiiHandles[Index] != NULL; Index++) {
- if (HiiHandles[Index] == HiiHandle) {
- Find = TRUE;
- break;
- }
- }
-
- FreePool (HiiHandles);
-
- return Find;
-}
-
-/**
- Validate the FormSet. If the formset is not validate, remove it from the list.
-
- @param FormSet The input FormSet which need to validate.
-
- @retval TRUE The handle is validate.
- @retval FALSE The handle is invalidate.
-
-**/
-BOOLEAN
-ValidateFormSet (
- FORM_BROWSER_FORMSET *FormSet
- )
-{
- BOOLEAN Find;
-
- ASSERT (FormSet != NULL);
-
- Find = ValidateHiiHandle (FormSet->HiiHandle);
- //
- // Should not remove the formset which is being used.
- //
- if (!Find && (FormSet != gCurrentSelection->FormSet)) {
- CleanBrowserStorage (FormSet);
- RemoveEntryList (&FormSet->Link);
- DestroyFormSet (FormSet);
- }
-
- return Find;
-}
-
-/**
- Check whether need to enable the reset flag in form level.
- Also clean all ValueChanged flag in question.
-
- @param SetFlag Whether need to set the Reset Flag.
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
-**/
-VOID
-UpdateFlagForForm (
- IN BOOLEAN SetFlag,
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
- BOOLEAN OldValue;
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&Form->StatementListHead, Link);
-
- if (!Question->ValueChanged) {
- continue;
- }
-
- OldValue = Question->ValueChanged;
-
- //
- // Compare the buffer and editbuffer data to see whether the data has been saved.
- //
- Question->ValueChanged = IsQuestionValueChanged (FormSet, Form, Question, GetSetValueWithBothBuffer);
-
- //
- // Only the changed data has been saved, then need to set the reset flag.
- //
- if (SetFlag && OldValue && !Question->ValueChanged) {
- if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
- gResetRequiredFormLevel = TRUE;
- gResetRequiredSystemLevel = TRUE;
- }
-
- if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
- gFlagReconnect = TRUE;
- }
- }
- }
-}
-
-/**
- Check whether need to enable the reset flag.
- Also clean ValueChanged flag for all statements.
-
- Form level or formset level, only one.
-
- @param SetFlag Whether need to set the Reset Flag.
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
-**/
-VOID
-ValueChangeResetFlagUpdate (
- IN BOOLEAN SetFlag,
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- FORM_BROWSER_FORM *CurrentForm;
- LIST_ENTRY *Link;
-
- if (Form != NULL) {
- UpdateFlagForForm (SetFlag, FormSet, Form);
- return;
- }
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->FormListHead, Link);
-
- UpdateFlagForForm (SetFlag, FormSet, CurrentForm);
- }
-}
-
-/**
- Base on the return Progress string to find the form.
-
- Base on the first return Offset/Width (Name) string to find the form
- which keep this string.
-
- @param FormSet FormSet data structure.
- @param Storage Storage which has this Progress string.
- @param Progress The Progress string which has the first fail string.
- @param RetForm The return form for this progress string.
- @param RetQuestion The return question for the error progress string.
-
- @retval TRUE Find the error form and statement for this error progress string.
- @retval FALSE Not find the error form.
-
-**/
-BOOLEAN
-FindQuestionFromProgress (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN BROWSER_STORAGE *Storage,
- IN EFI_STRING Progress,
- OUT FORM_BROWSER_FORM **RetForm,
- OUT FORM_BROWSER_STATEMENT **RetQuestion
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *LinkStorage;
- LIST_ENTRY *LinkStatement;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
- FORM_BROWSER_FORM *Form;
- EFI_STRING EndStr;
- FORM_BROWSER_STATEMENT *Statement;
-
- ASSERT ((*Progress == '&') || (*Progress == 'G'));
-
- ConfigInfo = NULL;
- *RetForm = NULL;
- *RetQuestion = NULL;
-
- //
- // Skip the first "&" or the ConfigHdr part.
- //
- if (*Progress == '&') {
- Progress++;
- } else {
- //
- // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
- //
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- //
- // For Name/Value type, Skip the ConfigHdr part.
- //
- EndStr = StrStr (Progress, L"PATH=");
- ASSERT (EndStr != NULL);
- while (*EndStr != '&') {
- EndStr++;
- }
-
- *EndStr = '\0';
- } else {
- //
- // For Buffer type, Skip the ConfigHdr part.
- //
- EndStr = StrStr (Progress, L"&OFFSET=");
- ASSERT (EndStr != NULL);
- *EndStr = '\0';
- }
-
- Progress = EndStr + 1;
- }
-
- //
- // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
- //
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- //
- // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
- // here, just keep the "Fred" string.
- //
- EndStr = StrStr (Progress, L"=");
- ASSERT (EndStr != NULL);
- *EndStr = '\0';
- } else {
- //
- // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
- // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
- //
- EndStr = StrStr (Progress, L"&VALUE=");
- ASSERT (EndStr != NULL);
- *EndStr = '\0';
- }
-
- //
- // Search in the form list.
- //
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->FormListHead, Link);
-
- //
- // Search in the ConfigReqeust list in this form.
- //
- LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
- LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
-
- if (Storage != ConfigInfo->Storage) {
- continue;
- }
-
- if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
- //
- // Find the OffsetWidth string in this form.
- //
- *RetForm = Form;
- break;
- }
- }
-
- if (*RetForm != NULL) {
- LinkStatement = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, LinkStatement)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
- LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
-
- if ((Statement->BlockName != NULL) && (StrStr (Statement->BlockName, Progress) != NULL)) {
- *RetQuestion = Statement;
- break;
- }
-
- if ((Statement->VariableName != NULL) && (StrStr (Statement->VariableName, Progress) != NULL)) {
- *RetQuestion = Statement;
- break;
- }
- }
- }
-
- if (*RetForm != NULL) {
- break;
- }
- }
-
- //
- // restore the OffsetWidth string to the original format.
- //
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- *EndStr = '=';
- } else {
- *EndStr = '&';
- }
-
- return (BOOLEAN)(*RetForm != NULL);
-}
-
-/**
- Base on the return Progress string to get the SyncConfigRequest and RestoreConfigRequest
- for form and formset.
-
- @param Storage Storage which has this Progress string.
- @param ConfigRequest The ConfigRequest string.
- @param Progress The Progress string which has the first fail string.
- @param RestoreConfigRequest Return the RestoreConfigRequest string.
- @param SyncConfigRequest Return the SyncConfigRequest string.
-
-**/
-VOID
-GetSyncRestoreConfigRequest (
- IN BROWSER_STORAGE *Storage,
- IN EFI_STRING ConfigRequest,
- IN EFI_STRING Progress,
- OUT EFI_STRING *RestoreConfigRequest,
- OUT EFI_STRING *SyncConfigRequest
- )
-{
- EFI_STRING EndStr;
- EFI_STRING ConfigHdrEndStr;
- EFI_STRING ElementStr;
- UINTN TotalSize;
- UINTN RestoreEleSize;
- UINTN SyncSize;
-
- ASSERT ((*Progress == L'&') || (*Progress == L'G'));
- //
- // If the Progress starts with ConfigHdr, means the failure is in the first name / value pair.
- // Need to restore all the fields in the ConfigRequest.
- //
- if (*Progress == L'G') {
- *RestoreConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
- ASSERT (*RestoreConfigRequest != NULL);
- return;
- }
-
- //
- // Find the first fail "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
- //
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- //
- // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
- // here, just keep the "Fred" string.
- //
- EndStr = StrStr (Progress, L"=");
- ASSERT (EndStr != NULL);
- *EndStr = L'\0';
- //
- // Find the ConfigHdr in ConfigRequest.
- //
- ConfigHdrEndStr = StrStr (ConfigRequest, L"PATH=");
- ASSERT (ConfigHdrEndStr != NULL);
- while (*ConfigHdrEndStr != L'&') {
- ConfigHdrEndStr++;
- }
- } else {
- //
- // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
- // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
- //
- EndStr = StrStr (Progress, L"&VALUE=");
- ASSERT (EndStr != NULL);
- *EndStr = L'\0';
- //
- // Find the ConfigHdr in ConfigRequest.
- //
- ConfigHdrEndStr = StrStr (ConfigRequest, L"&OFFSET=");
- }
-
- //
- // Find the first fail pair in the ConfigRequest.
- //
- ElementStr = StrStr (ConfigRequest, Progress);
- ASSERT (ElementStr != NULL);
- //
- // To get the RestoreConfigRequest.
- //
- RestoreEleSize = StrSize (ElementStr);
- TotalSize = (ConfigHdrEndStr - ConfigRequest) * sizeof (CHAR16) + RestoreEleSize + sizeof (CHAR16);
- *RestoreConfigRequest = AllocateZeroPool (TotalSize);
- ASSERT (*RestoreConfigRequest != NULL);
- StrnCpyS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ConfigRequest, ConfigHdrEndStr - ConfigRequest);
- StrCatS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ElementStr);
- //
- // To get the SyncConfigRequest.
- //
- SyncSize = StrSize (ConfigRequest) - RestoreEleSize + sizeof (CHAR16);
- *SyncConfigRequest = AllocateZeroPool (SyncSize);
- ASSERT (*SyncConfigRequest != NULL);
- StrnCpyS (*SyncConfigRequest, SyncSize / sizeof (CHAR16), ConfigRequest, SyncSize / sizeof (CHAR16) - 1);
-
- //
- // restore the Progress string to the original format.
- //
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- *EndStr = L'=';
- } else {
- *EndStr = L'&';
- }
-}
-
-/**
- Popup an save error info and get user input.
-
- @param TitleId The form title id.
- @param HiiHandle The hii handle for this package.
-
- @retval UINT32 The user select option for the save fail.
- BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
-**/
-UINT32
-ConfirmSaveFail (
- IN EFI_STRING_ID TitleId,
- IN EFI_HII_HANDLE HiiHandle
- )
-{
- CHAR16 *FormTitle;
- CHAR16 *StringBuffer;
- UINT32 RetVal;
-
- FormTitle = GetToken (TitleId, HiiHandle);
-
- StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
- ASSERT (StringBuffer != NULL);
-
- UnicodeSPrint (
- StringBuffer,
- 24 * sizeof (CHAR16) + StrSize (FormTitle),
- L"Submit Fail For Form: %s.",
- FormTitle
- );
-
- RetVal = PopupErrorMessage (BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
-
- FreePool (StringBuffer);
- FreePool (FormTitle);
-
- return RetVal;
-}
-
-/**
- Popup an NO_SUBMIT_IF error info and get user input.
-
- @param TitleId The form title id.
- @param HiiHandle The hii handle for this package.
-
- @retval UINT32 The user select option for the save fail.
- BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
-**/
-UINT32
-ConfirmNoSubmitFail (
- IN EFI_STRING_ID TitleId,
- IN EFI_HII_HANDLE HiiHandle
- )
-{
- CHAR16 *FormTitle;
- CHAR16 *StringBuffer;
- UINT32 RetVal;
-
- FormTitle = GetToken (TitleId, HiiHandle);
-
- StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
- ASSERT (StringBuffer != NULL);
-
- UnicodeSPrint (
- StringBuffer,
- 24 * sizeof (CHAR16) + StrSize (FormTitle),
- L"NO_SUBMIT_IF error For Form: %s.",
- FormTitle
- );
-
- RetVal = PopupErrorMessage (BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
-
- FreePool (StringBuffer);
- FreePool (FormTitle);
-
- return RetVal;
-}
-
-/**
- Discard data based on the input setting scope (Form, FormSet or System).
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param SettingScope Setting Scope for Discard action.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-DiscardForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN BROWSER_SETTING_SCOPE SettingScope
- )
-{
- LIST_ENTRY *Link;
- FORMSET_STORAGE *Storage;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
- FORM_BROWSER_FORMSET *LocalFormSet;
- FORM_BROWSER_FORMSET *OldFormSet;
-
- //
- // Check the supported setting level.
- //
- if (SettingScope >= MaxLevel) {
- return EFI_UNSUPPORTED;
- }
-
- if ((SettingScope == FormLevel) && IsNvUpdateRequiredForForm (Form)) {
- ConfigInfo = NULL;
- Link = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
- Link = GetNextNode (&Form->ConfigRequestHead, Link);
-
- if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- continue;
- }
-
- //
- // Skip if there is no RequestElement
- //
- if (ConfigInfo->ElementCount == 0) {
- continue;
- }
-
- //
- // Prepare <ConfigResp>
- //
- SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
-
- //
- // Call callback with Changed type to inform the driver.
- //
- SendDiscardInfoToDriver (FormSet, Form);
- }
-
- ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
- } else if ((SettingScope == FormSetLevel) && IsNvUpdateRequiredForFormSet (FormSet)) {
- //
- // Discard Buffer storage or Name/Value storage
- //
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- Storage = FORMSET_STORAGE_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->StorageListHead, Link);
-
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- continue;
- }
-
- //
- // Skip if there is no RequestElement
- //
- if (Storage->ElementCount == 0) {
- continue;
- }
-
- SynchronizeStorage (Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
- }
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->FormListHead, Link);
-
- //
- // Call callback with Changed type to inform the driver.
- //
- SendDiscardInfoToDriver (FormSet, Form);
- }
-
- ValueChangeResetFlagUpdate (FALSE, FormSet, NULL);
- } else if (SettingScope == SystemLevel) {
- //
- // System Level Discard.
- //
- OldFormSet = mSystemLevelFormSet;
-
- //
- // Discard changed value for each FormSet in the maintain list.
- //
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserFormSetList, Link);
- if (!ValidateFormSet (LocalFormSet)) {
- continue;
- }
-
- mSystemLevelFormSet = LocalFormSet;
-
- DiscardForm (LocalFormSet, NULL, FormSetLevel);
- if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
- //
- // Remove maintain backup list after discard except for the current using FormSet.
- //
- CleanBrowserStorage (LocalFormSet);
- RemoveEntryList (&LocalFormSet->Link);
- DestroyFormSet (LocalFormSet);
- }
- }
-
- mSystemLevelFormSet = OldFormSet;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Submit data for a form.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-SubmitForForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EFI_STRING ConfigResp;
- EFI_STRING Progress;
- BROWSER_STORAGE *Storage;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
- BOOLEAN SubmitFormFail;
-
- SubmitFormFail = FALSE;
-
- if (!IsNvUpdateRequiredForForm (Form)) {
- return EFI_SUCCESS;
- }
-
- Status = NoSubmitCheck (FormSet, &Form, NULL);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Link = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
- Link = GetNextNode (&Form->ConfigRequestHead, Link);
-
- Storage = ConfigInfo->Storage;
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- continue;
- }
-
- //
- // Skip if there is no RequestElement
- //
- if (ConfigInfo->ElementCount == 0) {
- continue;
- }
-
- //
- // 1. Prepare <ConfigResp>
- //
- Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // 2. Set value to hii config routine protocol.
- //
- Status = mHiiConfigRouting->RouteConfig (
- mHiiConfigRouting,
- ConfigResp,
- &Progress
- );
-
- if (EFI_ERROR (Status)) {
- //
- // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
- //
- SubmitFormFail = TRUE;
- GetSyncRestoreConfigRequest (ConfigInfo->Storage, ConfigInfo->ConfigRequest, Progress, &ConfigInfo->RestoreConfigRequest, &ConfigInfo->SyncConfigRequest);
- InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
- FreePool (ConfigResp);
- continue;
- }
-
- FreePool (ConfigResp);
- //
- // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
- //
- SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
- }
-
- //
- // 4. Process the save failed storage.
- //
- if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
- if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
- Link = GetFirstNode (&gBrowserSaveFailFormSetList);
- while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
- Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
- //
- // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
- // base on the SyncConfigRequest to Sync the buffer.
- //
- SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->RestoreConfigRequest, FALSE);
- FreePool (ConfigInfo->RestoreConfigRequest);
- ConfigInfo->RestoreConfigRequest = NULL;
- if (ConfigInfo->SyncConfigRequest != NULL) {
- SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->SyncConfigRequest, TRUE);
- FreePool (ConfigInfo->SyncConfigRequest);
- ConfigInfo->SyncConfigRequest = NULL;
- }
-
- Status = EFI_SUCCESS;
- }
-
- SendDiscardInfoToDriver (FormSet, Form);
- } else {
- Status = EFI_UNSUPPORTED;
- }
-
- //
- // Free Form save fail list.
- //
- while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
- Link = GetFirstNode (&gBrowserSaveFailFormSetList);
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
- RemoveEntryList (&ConfigInfo->SaveFailLink);
- }
- }
-
- //
- // 5. Update the NV flag.
- //
- ValueChangeResetFlagUpdate (TRUE, FormSet, Form);
-
- //
- // 6 Call callback with Submitted type to inform the driver.
- //
- if (!SubmitFormFail) {
- SubmitCallback (FormSet, Form);
- }
-
- return Status;
-}
-
-/**
- Submit data for a formset.
-
- @param FormSet FormSet data structure.
- @param SkipProcessFail Whether skip to process the save failed storage.
- If submit formset is called when do system level save,
- set this value to true and process the failed formset
- together.
- if submit formset is called when do formset level save,
- set the value to false and process the failed storage
- right after process all storages for this formset.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-SubmitForFormSet (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN BOOLEAN SkipProcessFail
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EFI_STRING ConfigResp;
- EFI_STRING Progress;
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormSetStorage;
- FORM_BROWSER_FORM *Form;
- BOOLEAN HasInserted;
- FORM_BROWSER_STATEMENT *Question;
- BOOLEAN SubmitFormSetFail;
- BOOLEAN DiscardChange;
-
- HasInserted = FALSE;
- SubmitFormSetFail = FALSE;
- DiscardChange = FALSE;
-
- if (!IsNvUpdateRequiredForFormSet (FormSet)) {
- return EFI_SUCCESS;
- }
-
- Form = NULL;
- Status = NoSubmitCheck (FormSet, &Form, &Question);
- if (EFI_ERROR (Status)) {
- if (SkipProcessFail) {
- //
- // Process NO_SUBMIT check first, so insert it at head.
- //
- FormSet->SaveFailForm = Form;
- FormSet->SaveFailStatement = Question;
- InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
- }
-
- return Status;
- }
-
- Form = NULL;
- Question = NULL;
- //
- // Submit Buffer storage or Name/Value storage
- //
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
- Storage = FormSetStorage->BrowserStorage;
- Link = GetNextNode (&FormSet->StorageListHead, Link);
-
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- continue;
- }
-
- //
- // Skip if there is no RequestElement
- //
- if (FormSetStorage->ElementCount == 0) {
- continue;
- }
-
- //
- // 1. Prepare <ConfigResp>
- //
- Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // 2. Send <ConfigResp> to Routine config Protocol.
- //
- Status = mHiiConfigRouting->RouteConfig (
- mHiiConfigRouting,
- ConfigResp,
- &Progress
- );
- if (EFI_ERROR (Status)) {
- //
- // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
- //
- SubmitFormSetFail = TRUE;
- GetSyncRestoreConfigRequest (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, Progress, &FormSetStorage->RestoreConfigRequest, &FormSetStorage->SyncConfigRequest);
- InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
- if (!HasInserted) {
- //
- // Call submit formset for system level, save the formset info
- // and process later.
- //
- FindQuestionFromProgress (FormSet, Storage, Progress, &Form, &Question);
- ASSERT (Form != NULL && Question != NULL);
- FormSet->SaveFailForm = Form;
- FormSet->SaveFailStatement = Question;
- if (SkipProcessFail) {
- InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
- }
-
- HasInserted = TRUE;
- }
-
- FreePool (ConfigResp);
- continue;
- }
-
- FreePool (ConfigResp);
- //
- // 3. Config success, update storage shadow Buffer
- //
- SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
- }
-
- //
- // 4. Has save fail storage need to handle.
- //
- if (Form != NULL) {
- if (!SkipProcessFail) {
- //
- // If not in system level, just handl the save failed storage here.
- //
- if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
- DiscardChange = TRUE;
- Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
- while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
- FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
- Storage = FormSetStorage->BrowserStorage;
- Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
- //
- // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
- // base on the SyncConfigRequest to Sync the buffer.
- //
- SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
- FreePool (FormSetStorage->RestoreConfigRequest);
- FormSetStorage->RestoreConfigRequest = NULL;
- if (FormSetStorage->SyncConfigRequest != NULL) {
- SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
- FreePool (FormSetStorage->SyncConfigRequest);
- FormSetStorage->SyncConfigRequest = NULL;
- }
-
- Status = EFI_SUCCESS;
- }
- } else {
- UiCopyMenuList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
-
- gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
- gCurrentSelection->Handle = FormSet->HiiHandle;
- CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
- gCurrentSelection->FormId = Form->FormId;
- gCurrentSelection->QuestionId = Question->QuestionId;
-
- Status = EFI_UNSUPPORTED;
- }
-
- //
- // Free FormSet save fail list.
- //
- while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
- Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
- FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
- RemoveEntryList (&FormSetStorage->SaveFailLink);
- }
- } else {
- //
- // If in system level, just return error and handle the failed formset later.
- //
- Status = EFI_UNSUPPORTED;
- }
- }
-
- //
- // If user discard the change, send the discard info to driver.
- //
- if (DiscardChange) {
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->FormListHead, Link);
- //
- // Call callback with Changed type to inform the driver.
- //
- SendDiscardInfoToDriver (FormSet, Form);
- }
- }
-
- //
- // 5. Update the NV flag.
- //
- ValueChangeResetFlagUpdate (TRUE, FormSet, NULL);
-
- //
- // 6. Call callback with Submitted type to inform the driver.
- //
- if (!SubmitFormSetFail) {
- SubmitCallback (FormSet, NULL);
- }
-
- return Status;
-}
-
-/**
- Submit data for all formsets.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-SubmitForSystem (
- VOID
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- LIST_ENTRY *FormLink;
- LIST_ENTRY *StorageLink;
- FORMSET_STORAGE *FormSetStorage;
- FORM_BROWSER_FORM *Form;
- FORM_BROWSER_FORMSET *LocalFormSet;
- UINT32 UserSelection;
- FORM_BROWSER_STATEMENT *Question;
-
- mSystemSubmit = TRUE;
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserFormSetList, Link);
- if (!ValidateFormSet (LocalFormSet)) {
- continue;
- }
-
- Status = SubmitForFormSet (LocalFormSet, TRUE);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- //
- // Remove maintain backup list after save except for the current using FormSet.
- //
- if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
- CleanBrowserStorage (LocalFormSet);
- RemoveEntryList (&LocalFormSet->Link);
- DestroyFormSet (LocalFormSet);
- }
- }
-
- mSystemSubmit = FALSE;
-
- Status = EFI_SUCCESS;
-
- //
- // Process the save failed formsets.
- //
- Link = GetFirstNode (&gBrowserSaveFailFormSetList);
- while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
- Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
-
- if (!ValidateFormSet (LocalFormSet)) {
- continue;
- }
-
- Form = LocalFormSet->SaveFailForm;
- Question = LocalFormSet->SaveFailStatement;
-
- //
- // Confirm with user, get user input.
- //
- if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
- //
- // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
- //
- UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
- } else {
- UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
- }
-
- if (UserSelection == BROWSER_ACTION_DISCARD) {
- if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
- StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
- while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
- FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
- StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
-
- SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
- }
- } else {
- StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
- while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
- FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
- StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
- //
- // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
- // base on the SyncConfigRequest to Sync the buffer.
- //
- SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
- FreePool (FormSetStorage->RestoreConfigRequest);
- FormSetStorage->RestoreConfigRequest = NULL;
- if ( FormSetStorage->SyncConfigRequest != NULL) {
- SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
- FreePool (FormSetStorage->SyncConfigRequest);
- FormSetStorage->SyncConfigRequest = NULL;
- }
- }
- }
-
- FormLink = GetFirstNode (&LocalFormSet->FormListHead);
- while (!IsNull (&LocalFormSet->FormListHead, FormLink)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
- FormLink = GetNextNode (&LocalFormSet->FormListHead, FormLink);
- //
- // Call callback with Changed type to inform the driver.
- //
- SendDiscardInfoToDriver (LocalFormSet, Form);
- }
-
- if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
- CleanBrowserStorage (LocalFormSet);
- RemoveEntryList (&LocalFormSet->Link);
- RemoveEntryList (&LocalFormSet->SaveFailLink);
- DestroyFormSet (LocalFormSet);
- } else {
- ValueChangeResetFlagUpdate (FALSE, LocalFormSet, NULL);
- }
- } else {
- if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
- NoSubmitCheck (LocalFormSet, &Form, &Question);
- }
-
- UiCopyMenuList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
-
- gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
- gCurrentSelection->Handle = LocalFormSet->HiiHandle;
- CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
- gCurrentSelection->FormId = Form->FormId;
- gCurrentSelection->QuestionId = Question->QuestionId;
-
- Status = EFI_UNSUPPORTED;
- break;
- }
- }
-
- //
- // Clean the list which will not process.
- //
- while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
- Link = GetFirstNode (&gBrowserSaveFailFormSetList);
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
- RemoveEntryList (&LocalFormSet->SaveFailLink);
-
- while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
- StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
- FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
- RemoveEntryList (&FormSetStorage->SaveFailLink);
- }
- }
-
- return Status;
-}
-
-/**
- Submit data based on the input Setting level (Form, FormSet or System).
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param SettingScope Setting Scope for Submit action.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-SubmitForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN BROWSER_SETTING_SCOPE SettingScope
- )
-{
- EFI_STATUS Status;
-
- switch (SettingScope) {
- case FormLevel:
- Status = SubmitForForm (FormSet, Form);
- break;
-
- case FormSetLevel:
- Status = SubmitForFormSet (FormSet, FALSE);
- break;
-
- case SystemLevel:
- Status = SubmitForSystem ();
- break;
-
- default:
- Status = EFI_UNSUPPORTED;
- break;
- }
-
- return Status;
-}
-
-/**
- Converts the unicode character of the string from uppercase to lowercase.
- This is a internal function.
-
- @param ConfigString String to be converted
-
-**/
-VOID
-EFIAPI
-HiiToLower (
- IN EFI_STRING ConfigString
- )
-{
- EFI_STRING String;
- BOOLEAN Lower;
-
- ASSERT (ConfigString != NULL);
-
- //
- // Convert all hex digits in range [A-F] in the configuration header to [a-f]
- //
- for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
- if (*String == L'=') {
- Lower = TRUE;
- } else if (*String == L'&') {
- Lower = FALSE;
- } else if (Lower && (*String >= L'A') && (*String <= L'F')) {
- *String = (CHAR16)(*String - L'A' + L'a');
- }
- }
-}
-
-/**
- Find the point in the ConfigResp string for this question.
-
- @param Question The question.
- @param ConfigResp Get ConfigResp string.
-
- @retval point to the offset where is for this question.
-
-**/
-CHAR16 *
-GetOffsetFromConfigResp (
- IN FORM_BROWSER_STATEMENT *Question,
- IN CHAR16 *ConfigResp
- )
-{
- CHAR16 *RequestElement;
- CHAR16 *BlockData;
-
- //
- // Type is EFI_HII_VARSTORE_NAME_VALUE.
- //
- if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- RequestElement = StrStr (ConfigResp, Question->VariableName);
- if (RequestElement != NULL) {
- //
- // Skip the "VariableName=" field.
- //
- RequestElement += StrLen (Question->VariableName) + 1;
- }
-
- return RequestElement;
- }
-
- //
- // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
- //
-
- //
- // Convert all hex digits in ConfigResp to lower case before searching.
- //
- HiiToLower (ConfigResp);
-
- //
- // 1. Directly use Question->BlockName to find.
- //
- RequestElement = StrStr (ConfigResp, Question->BlockName);
- if (RequestElement != NULL) {
- //
- // Skip the "Question->BlockName&VALUE=" field.
- //
- RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
- return RequestElement;
- }
-
- //
- // 2. Change all hex digits in Question->BlockName to lower and compare again.
- //
- BlockData = AllocateCopyPool (StrSize (Question->BlockName), Question->BlockName);
- ASSERT (BlockData != NULL);
- HiiToLower (BlockData);
- RequestElement = StrStr (ConfigResp, BlockData);
- FreePool (BlockData);
-
- if (RequestElement != NULL) {
- //
- // Skip the "Question->BlockName&VALUE=" field.
- //
- RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
- }
-
- return RequestElement;
-}
-
-/**
- Get Question default value from AltCfg string.
-
- @param FormSet The form set.
- @param Form The form
- @param Question The question.
-
- @retval EFI_SUCCESS Question is reset to default value.
-
-**/
-EFI_STATUS
-GetDefaultValueFromAltCfg (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question
- )
-{
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormSetStorage;
- CHAR16 *ConfigResp;
- CHAR16 *Value;
- LIST_ENTRY *Link;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
-
- Storage = Question->Storage;
- if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Try to get AltCfg string from form. If not found it, then
- // try to get it from formset.
- //
- ConfigResp = NULL;
- Link = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
- Link = GetNextNode (&Form->ConfigRequestHead, Link);
-
- if (Storage == ConfigInfo->Storage) {
- ConfigResp = ConfigInfo->ConfigAltResp;
- break;
- }
- }
-
- if (ConfigResp == NULL) {
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->StorageListHead, Link);
-
- if (Storage == FormSetStorage->BrowserStorage) {
- ConfigResp = FormSetStorage->ConfigAltResp;
- break;
- }
- }
- }
-
- if (ConfigResp == NULL) {
- return EFI_NOT_FOUND;
- }
-
- Value = GetOffsetFromConfigResp (Question, ConfigResp);
- if (Value == NULL) {
- return EFI_NOT_FOUND;
- }
-
- return BufferToValue (Question, Value);
-}
-
-/**
- Get default Id value used for browser.
-
- @param DefaultId The default id value used by hii.
-
- @retval Browser used default value.
-
-**/
-INTN
-GetDefaultIdForCallBack (
- UINTN DefaultId
- )
-{
- if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
- return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
- } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
- return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
- } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
- return EFI_BROWSER_ACTION_DEFAULT_SAFE;
- } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000)) {
- return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
- } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000)) {
- return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
- } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000)) {
- return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
- } else {
- return -1;
- }
-}
-
-/**
- Return data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
-
- @retval Value The data to be returned
-
-**/
-UINT64
-GetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index
- )
-{
- UINT64 Data;
-
- ASSERT (Array != NULL);
-
- Data = 0;
- switch (Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- Data = (UINT64)*(((UINT8 *)Array) + Index);
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- Data = (UINT64)*(((UINT16 *)Array) + Index);
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- Data = (UINT64)*(((UINT32 *)Array) + Index);
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- Data = (UINT64)*(((UINT64 *)Array) + Index);
- break;
-
- default:
- break;
- }
-
- return Data;
-}
-
-/**
- Set value of a data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
- @param Value The value to be set.
-
-**/
-VOID
-SetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index,
- IN UINT64 Value
- )
-{
- ASSERT (Array != NULL);
-
- switch (Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- *(((UINT8 *)Array) + Index) = (UINT8)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- *(((UINT16 *)Array) + Index) = (UINT16)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- *(((UINT32 *)Array) + Index) = (UINT32)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- *(((UINT64 *)Array) + Index) = (UINT64)Value;
- break;
-
- default:
- break;
- }
-}
-
-/**
- Search an Option of a Question by its value.
-
- @param Question The Question
- @param OptionValue Value for Option to be searched.
-
- @retval Pointer Pointer to the found Option.
- @retval NULL Option not found.
-
-**/
-QUESTION_OPTION *
-ValueToOption (
- IN FORM_BROWSER_STATEMENT *Question,
- IN EFI_HII_VALUE *OptionValue
- )
-{
- LIST_ENTRY *Link;
- QUESTION_OPTION *Option;
- INTN Result;
-
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- Option = QUESTION_OPTION_FROM_LINK (Link);
-
- if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
- //
- // Check the suppressif condition, only a valid option can be return.
- //
- if ((Option->SuppressExpression == NULL) ||
- ((EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)))
- {
- return Option;
- }
- }
-
- Link = GetNextNode (&Question->OptionListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Reset Question to its default value.
-
- @param FormSet The form set.
- @param Form The form.
- @param Question The question.
- @param DefaultId The Class of the default.
-
- @retval EFI_SUCCESS Question is reset to default value.
-
-**/
-EFI_STATUS
-GetQuestionDefault (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question,
- IN UINT16 DefaultId
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- QUESTION_DEFAULT *Default;
- QUESTION_OPTION *Option;
- EFI_HII_VALUE *HiiValue;
- UINT8 Index;
- EFI_STRING StrValue;
- EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
- EFI_BROWSER_ACTION_REQUEST ActionRequest;
- INTN Action;
- CHAR16 *NewString;
- EFI_IFR_TYPE_VALUE *TypeValue;
- UINT16 OriginalDefaultId;
- FORMSET_DEFAULTSTORE *DefaultStore;
- LIST_ENTRY *DefaultLink;
-
- Status = EFI_NOT_FOUND;
- StrValue = NULL;
- OriginalDefaultId = DefaultId;
- DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
-
- //
- // Statement don't have storage, skip them
- //
- if (Question->QuestionId == 0) {
- return Status;
- }
-
- //
- // There are Five ways to specify default value for a Question:
- // 1, use call back function (highest priority)
- // 2, use ExtractConfig function
- // 3, use nested EFI_IFR_DEFAULT
- // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
- // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
- //
-ReGetDefault:
- HiiValue = &Question->HiiValue;
- TypeValue = &HiiValue->Value;
- if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
- //
- // For orderedlist, need to pass the BufferValue to Callback function.
- //
- TypeValue = (EFI_IFR_TYPE_VALUE *)Question->BufferValue;
- }
-
- //
- // Get Question defaut value from call back function.
- //
- ConfigAccess = FormSet->ConfigAccess;
- Action = GetDefaultIdForCallBack (DefaultId);
- if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
- ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
- Status = ConfigAccess->Callback (
- ConfigAccess,
- Action,
- Question->QuestionId,
- HiiValue->Type,
- TypeValue,
- &ActionRequest
- );
- if (!EFI_ERROR (Status)) {
- if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
- NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
- ASSERT (NewString != NULL);
-
- ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
- if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
- ZeroMem (Question->BufferValue, Question->StorageWidth);
- CopyMem (Question->BufferValue, NewString, StrSize (NewString));
- } else {
- CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
- }
-
- FreePool (NewString);
- }
-
- return Status;
- }
- }
-
- //
- // Get default value from altcfg string.
- //
- if (ConfigAccess != NULL) {
- Status = GetDefaultValueFromAltCfg (FormSet, Form, Question);
- if (!EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // EFI_IFR_DEFAULT has highest priority
- //
- if (!IsListEmpty (&Question->DefaultListHead)) {
- Link = GetFirstNode (&Question->DefaultListHead);
- while (!IsNull (&Question->DefaultListHead, Link)) {
- Default = QUESTION_DEFAULT_FROM_LINK (Link);
-
- if (Default->DefaultId == DefaultId) {
- if (Default->ValueExpression != NULL) {
- //
- // Default is provided by an Expression, evaluate it
- //
- Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
- ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
- if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
- CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
- Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
- } else {
- CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
- Question->HiiValue.BufferLen = Question->StorageWidth;
- }
-
- FreePool (Default->ValueExpression->Result.Buffer);
- }
-
- HiiValue->Type = Default->ValueExpression->Result.Type;
- CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
- } else {
- //
- // Default value is embedded in EFI_IFR_DEFAULT
- //
- if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
- ASSERT (HiiValue->Buffer != NULL);
- CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
- } else {
- CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
- }
- }
-
- if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
- StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
- if (StrValue == NULL) {
- return EFI_NOT_FOUND;
- }
-
- if (Question->StorageWidth > StrSize (StrValue)) {
- ZeroMem (Question->BufferValue, Question->StorageWidth);
- CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
- } else {
- CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
- }
- }
-
- return EFI_SUCCESS;
- }
-
- Link = GetNextNode (&Question->DefaultListHead, Link);
- }
- }
-
- //
- // EFI_ONE_OF_OPTION
- //
- if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
- if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
- //
- // OneOfOption could only provide Standard and Manufacturing default
- //
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- Option = QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
-
- if ((Option->SuppressExpression != NULL) &&
- (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse))
- {
- continue;
- }
-
- if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
- ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
- )
- {
- CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
-
- return EFI_SUCCESS;
- }
- }
- }
- }
-
- //
- // EFI_IFR_CHECKBOX - lowest priority
- //
- if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
- if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
- //
- // Checkbox could only provide Standard and Manufacturing default
- //
- if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
- ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
- )
- {
- HiiValue->Value.b = TRUE;
- }
-
- return EFI_SUCCESS;
- }
- }
-
- //
- // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
- // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
- // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
- //
- while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
- DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultLink);
- DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
- DefaultId = DefaultStore->DefaultId;
- if (DefaultId == OriginalDefaultId) {
- continue;
- }
-
- goto ReGetDefault;
- }
-
- //
- // For Questions without default value for all the default id in the DefaultStoreList.
- //
- Status = EFI_NOT_FOUND;
- switch (Question->Operand) {
- case EFI_IFR_CHECKBOX_OP:
- HiiValue->Value.b = FALSE;
- Status = EFI_SUCCESS;
- break;
-
- case EFI_IFR_NUMERIC_OP:
- //
- // Take minimum value as numeric default value
- //
- if ((Question->Flags & EFI_IFR_DISPLAY) == 0) {
- //
- // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
- //
- switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) {
- case EFI_IFR_NUMERIC_SIZE_1:
- if (((INT8)HiiValue->Value.u8 < (INT8)Question->Minimum) || ((INT8)HiiValue->Value.u8 > (INT8)Question->Maximum)) {
- HiiValue->Value.u8 = (UINT8)Question->Minimum;
- Status = EFI_SUCCESS;
- }
-
- break;
- case EFI_IFR_NUMERIC_SIZE_2:
- if (((INT16)HiiValue->Value.u16 < (INT16)Question->Minimum) || ((INT16)HiiValue->Value.u16 > (INT16)Question->Maximum)) {
- HiiValue->Value.u16 = (UINT16)Question->Minimum;
- Status = EFI_SUCCESS;
- }
-
- break;
- case EFI_IFR_NUMERIC_SIZE_4:
- if (((INT32)HiiValue->Value.u32 < (INT32)Question->Minimum) || ((INT32)HiiValue->Value.u32 > (INT32)Question->Maximum)) {
- HiiValue->Value.u32 = (UINT32)Question->Minimum;
- Status = EFI_SUCCESS;
- }
-
- break;
- case EFI_IFR_NUMERIC_SIZE_8:
- if (((INT64)HiiValue->Value.u64 < (INT64)Question->Minimum) || ((INT64)HiiValue->Value.u64 > (INT64)Question->Maximum)) {
- HiiValue->Value.u64 = Question->Minimum;
- Status = EFI_SUCCESS;
- }
-
- break;
- default:
- break;
- }
- } else {
- if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
- HiiValue->Value.u64 = Question->Minimum;
- Status = EFI_SUCCESS;
- }
- }
-
- break;
-
- case EFI_IFR_ONE_OF_OP:
- //
- // Take first oneof option as oneof's default value
- //
- if (ValueToOption (Question, HiiValue) == NULL) {
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- Option = QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
-
- if ((Option->SuppressExpression != NULL) &&
- (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse))
- {
- continue;
- }
-
- CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
- Status = EFI_SUCCESS;
- break;
- }
- }
-
- break;
-
- case EFI_IFR_ORDERED_LIST_OP:
- //
- // Take option sequence in IFR as ordered list's default value
- //
- Index = 0;
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- Status = EFI_SUCCESS;
- Option = QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
-
- if ((Option->SuppressExpression != NULL) &&
- (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse))
- {
- continue;
- }
-
- SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
-
- Index++;
- if (Index >= Question->MaxContainers) {
- break;
- }
- }
-
- break;
-
- default:
- break;
- }
-
- return Status;
-}
-
-/**
- Get AltCfg string for current form.
-
- @param FormSet Form data structure.
- @param Form Form data structure.
- @param DefaultId The Class of the default.
- @param BrowserStorage The input request storage for the questions.
-
-**/
-VOID
-ExtractAltCfgForForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN UINT16 DefaultId,
- IN BROWSER_STORAGE *BrowserStorage
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- CHAR16 *ConfigResp;
- CHAR16 *Progress;
- CHAR16 *Result;
- BROWSER_STORAGE *Storage;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
- FORMSET_STORAGE *FormSetStorage;
-
- //
- // Check whether has get AltCfg string for this formset.
- // If yes, no need to get AltCfg for form.
- //
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
- Storage = FormSetStorage->BrowserStorage;
- Link = GetNextNode (&FormSet->StorageListHead, Link);
- if ((BrowserStorage != NULL) && (BrowserStorage != Storage)) {
- continue;
- }
-
- if ((Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE) &&
- (FormSetStorage->ElementCount != 0) &&
- FormSetStorage->HasCallAltCfg)
- {
- return;
- }
- }
-
- //
- // Get AltCfg string for each form.
- //
- Link = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
- Link = GetNextNode (&Form->ConfigRequestHead, Link);
-
- Storage = ConfigInfo->Storage;
- if ((BrowserStorage != NULL) && (BrowserStorage != Storage)) {
- continue;
- }
-
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- continue;
- }
-
- //
- // 1. Skip if there is no RequestElement
- //
- if (ConfigInfo->ElementCount == 0) {
- continue;
- }
-
- //
- // 2. Get value through hii config routine protocol.
- //
- Status = mHiiConfigRouting->ExtractConfig (
- mHiiConfigRouting,
- ConfigInfo->ConfigRequest,
- &Progress,
- &Result
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- //
- // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
- // Get the default configuration string according to the default ID.
- //
- Status = mHiiConfigRouting->GetAltConfig (
- mHiiConfigRouting,
- Result,
- &Storage->Guid,
- Storage->Name,
- NULL,
- &DefaultId, // it can be NULL to get the current setting.
- &ConfigResp
- );
- FreePool (Result);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- ConfigInfo->ConfigAltResp = ConfigResp;
- }
-}
-
-/**
- Clean AltCfg string for current form.
-
- @param Form Form data structure.
-
-**/
-VOID
-CleanAltCfgForForm (
- IN FORM_BROWSER_FORM *Form
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
-
- Link = GetFirstNode (&Form->ConfigRequestHead);
- while (!IsNull (&Form->ConfigRequestHead, Link)) {
- ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
- Link = GetNextNode (&Form->ConfigRequestHead, Link);
-
- if (ConfigInfo->ConfigAltResp != NULL) {
- FreePool (ConfigInfo->ConfigAltResp);
- ConfigInfo->ConfigAltResp = NULL;
- }
- }
-}
-
-/**
- Get AltCfg string for current formset.
-
- @param FormSet Form data structure.
- @param DefaultId The Class of the default.
- @param BrowserStorage The input request storage for the questions.
-
-**/
-VOID
-ExtractAltCfgForFormSet (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN UINT16 DefaultId,
- IN BROWSER_STORAGE *BrowserStorage
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- CHAR16 *ConfigResp;
- CHAR16 *Progress;
- CHAR16 *Result;
- BROWSER_STORAGE *Storage;
- FORMSET_STORAGE *FormSetStorage;
-
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
- Storage = FormSetStorage->BrowserStorage;
- Link = GetNextNode (&FormSet->StorageListHead, Link);
-
- if ((BrowserStorage != NULL) && (BrowserStorage != Storage)) {
- continue;
- }
-
- if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- continue;
- }
-
- //
- // 1. Skip if there is no RequestElement
- //
- if (FormSetStorage->ElementCount == 0) {
- continue;
- }
-
- FormSetStorage->HasCallAltCfg = TRUE;
-
- //
- // 2. Get value through hii config routine protocol.
- //
- Status = mHiiConfigRouting->ExtractConfig (
- mHiiConfigRouting,
- FormSetStorage->ConfigRequest,
- &Progress,
- &Result
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- //
- // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
- // Get the default configuration string according to the default ID.
- //
- Status = mHiiConfigRouting->GetAltConfig (
- mHiiConfigRouting,
- Result,
- &Storage->Guid,
- Storage->Name,
- NULL,
- &DefaultId, // it can be NULL to get the current setting.
- &ConfigResp
- );
-
- FreePool (Result);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- FormSetStorage->ConfigAltResp = ConfigResp;
- }
-}
-
-/**
- Clean AltCfg string for current formset.
-
- @param FormSet Form data structure.
-
-**/
-VOID
-CleanAltCfgForFormSet (
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- LIST_ENTRY *Link;
- FORMSET_STORAGE *FormSetStorage;
-
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->StorageListHead, Link);
-
- if (FormSetStorage->ConfigAltResp != NULL) {
- FreePool (FormSetStorage->ConfigAltResp);
- FormSetStorage->ConfigAltResp = NULL;
- }
-
- FormSetStorage->HasCallAltCfg = FALSE;
- }
-}
-
-/**
- Reset Questions to their initial value or default value in a Form, Formset or System.
-
- GetDefaultValueScope parameter decides which questions will reset
- to its default value.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param DefaultId The Class of the default.
- @param SettingScope Setting Scope for Default action.
- @param GetDefaultValueScope Get default value scope.
- @param Storage Get default value only for this storage.
- @param RetrieveValueFirst Whether call the retrieve call back to
- get the initial value before get default
- value.
- @param SkipGetAltCfg Whether skip the get altcfg string process.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-ExtractDefault (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN UINT16 DefaultId,
- IN BROWSER_SETTING_SCOPE SettingScope,
- IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
- IN BROWSER_STORAGE *Storage OPTIONAL,
- IN BOOLEAN RetrieveValueFirst,
- IN BOOLEAN SkipGetAltCfg
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *FormLink;
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
- FORM_BROWSER_FORMSET *LocalFormSet;
- FORM_BROWSER_FORMSET *OldFormSet;
-
- Status = EFI_SUCCESS;
-
- //
- // Check the supported setting level.
- //
- if ((SettingScope >= MaxLevel) || (GetDefaultValueScope >= GetDefaultForMax)) {
- return EFI_UNSUPPORTED;
- }
-
- if ((GetDefaultValueScope == GetDefaultForStorage) && (Storage == NULL)) {
- return EFI_UNSUPPORTED;
- }
-
- if (SettingScope == FormLevel) {
- //
- // Prepare the AltCfg String for form.
- //
- if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
- ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);
- }
-
- //
- // Extract Form default
- //
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&Form->StatementListHead, Link);
-
- //
- // If get default value only for this storage, check the storage first.
- //
- if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
- continue;
- }
-
- //
- // If get default value only for no storage question, just skip the question which has storage.
- //
- if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
- continue;
- }
-
- //
- // If Question is disabled, don't reset it to default
- //
- if (Question->Expression != NULL) {
- if (EvaluateExpressionList (Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
- continue;
- }
- }
-
- if (RetrieveValueFirst) {
- //
- // Call the Retrieve call back to get the initial question value.
- //
- Status = ProcessRetrieveForQuestion (FormSet->ConfigAccess, Question, FormSet);
- }
-
- //
- // If not request to get the initial value or get initial value fail, then get default value.
- //
- if (!RetrieveValueFirst || EFI_ERROR (Status)) {
- Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
- if (EFI_ERROR (Status)) {
- continue;
- }
- }
-
- //
- // Synchronize Buffer storage's Edit buffer
- //
- if ((Question->Storage != NULL) &&
- (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE))
- {
- SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
- }
- }
-
- //
- // Clean the AltCfg String.
- //
- if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
- CleanAltCfgForForm (Form);
- }
- } else if (SettingScope == FormSetLevel) {
- //
- // Prepare the AltCfg String for formset.
- //
- if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
- ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);
- }
-
- FormLink = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, FormLink)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
- ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
- FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
- }
-
- //
- // Clean the AltCfg String.
- //
- if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
- CleanAltCfgForFormSet (FormSet);
- }
- } else if (SettingScope == SystemLevel) {
- //
- // Preload all Hii formset.
- //
- LoadAllHiiFormset ();
-
- OldFormSet = mSystemLevelFormSet;
-
- //
- // Set Default Value for each FormSet in the maintain list.
- //
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserFormSetList, Link);
- if (!ValidateFormSet (LocalFormSet)) {
- continue;
- }
-
- mSystemLevelFormSet = LocalFormSet;
-
- ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
- }
-
- mSystemLevelFormSet = OldFormSet;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Validate whether this question's value has changed.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question Question to be initialized.
- @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
-
- @retval TRUE Question's value has changed.
- @retval FALSE Question's value has not changed
-
-**/
-BOOLEAN
-IsQuestionValueChanged (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
- )
-{
- EFI_HII_VALUE BackUpValue;
- CHAR8 *BackUpBuffer;
- EFI_HII_VALUE BackUpValue2;
- CHAR8 *BackUpBuffer2;
- EFI_STATUS Status;
- BOOLEAN ValueChanged;
- UINTN BufferWidth;
-
- //
- // For quetion without storage, always mark it as data not changed.
- //
- if ((Question->Storage == NULL) && (Question->Operand != EFI_IFR_TIME_OP) && (Question->Operand != EFI_IFR_DATE_OP)) {
- return FALSE;
- }
-
- BackUpBuffer = NULL;
- BackUpBuffer2 = NULL;
- ValueChanged = FALSE;
-
- switch (Question->Operand) {
- case EFI_IFR_ORDERED_LIST_OP:
- BufferWidth = Question->StorageWidth;
- BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
- ASSERT (BackUpBuffer != NULL);
- break;
-
- case EFI_IFR_STRING_OP:
- case EFI_IFR_PASSWORD_OP:
- BufferWidth = (UINTN)Question->Maximum * sizeof (CHAR16);
- BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
- ASSERT (BackUpBuffer != NULL);
- break;
-
- default:
- BufferWidth = 0;
- break;
- }
-
- CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
-
- if (GetValueFrom == GetSetValueWithBothBuffer) {
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
- ASSERT_EFI_ERROR (Status);
-
- switch (Question->Operand) {
- case EFI_IFR_ORDERED_LIST_OP:
- BufferWidth = Question->StorageWidth;
- BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
- ASSERT (BackUpBuffer2 != NULL);
- break;
-
- case EFI_IFR_STRING_OP:
- case EFI_IFR_PASSWORD_OP:
- BufferWidth = (UINTN)Question->Maximum * sizeof (CHAR16);
- BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
- ASSERT (BackUpBuffer2 != NULL);
- break;
-
- default:
- BufferWidth = 0;
- break;
- }
-
- CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
-
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
- ASSERT_EFI_ERROR (Status);
-
- if ((CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0) ||
- (CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0))
- {
- ValueChanged = TRUE;
- }
- } else {
- Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
- ASSERT_EFI_ERROR (Status);
-
- if ((CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0) ||
- (CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0))
- {
- ValueChanged = TRUE;
- }
- }
-
- CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
- if (BackUpBuffer != NULL) {
- CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
- FreePool (BackUpBuffer);
- }
-
- if (BackUpBuffer2 != NULL) {
- FreePool (BackUpBuffer2);
- }
-
- Question->ValueChanged = ValueChanged;
-
- return ValueChanged;
-}
-
-/**
- Initialize Question's Edit copy from Storage.
-
- @param Selection Selection contains the information about
- the Selection, form and formset to be displayed.
- Selection action may be updated in retrieve callback.
- If Selection is NULL, only initialize Question value.
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-LoadFormConfig (
- IN OUT UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Question;
-
- Link = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, Link)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-
- //
- // Initialize local copy of Value for each Question
- //
- if ((Question->Operand == EFI_IFR_PASSWORD_OP) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == 0)) {
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
- } else {
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
- HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16 *)Question->BufferValue, NULL);
- }
-
- Link = GetNextNode (&Form->StatementListHead, Link);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Initialize Question's Edit copy from Storage for the whole Formset.
-
- @param Selection Selection contains the information about
- the Selection, form and formset to be displayed.
- Selection action may be updated in retrieve callback.
- If Selection is NULL, only initialize Question value.
- @param FormSet FormSet data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-LoadFormSetConfig (
- IN OUT UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_FORMSET *FormSet
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- FORM_BROWSER_FORM *Form;
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- //
- // Initialize local copy of Value for each Form
- //
- Status = LoadFormConfig (Selection, FormSet, Form);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Link = GetNextNode (&FormSet->FormListHead, Link);
- }
-
- //
- // Finished question initialization.
- //
- FormSet->QuestionInited = TRUE;
-
- return EFI_SUCCESS;
-}
-
-/**
- Remove the Request element from the Config Request.
-
- @param Storage Pointer to the browser storage.
- @param RequestElement The pointer to the Request element.
-
-**/
-VOID
-RemoveElement (
- IN OUT BROWSER_STORAGE *Storage,
- IN CHAR16 *RequestElement
- )
-{
- CHAR16 *NewStr;
- CHAR16 *DestStr;
-
- ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
-
- NewStr = StrStr (Storage->ConfigRequest, RequestElement);
-
- if (NewStr == NULL) {
- return;
- }
-
- //
- // Remove this element from this ConfigRequest.
- //
- DestStr = NewStr;
- NewStr += StrLen (RequestElement);
- CopyMem (DestStr, NewStr, StrSize (NewStr));
-
- Storage->SpareStrLen += StrLen (RequestElement);
-}
-
-/**
- Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
-
- @param Storage Pointer to the formset storage.
- @param ConfigRequest The pointer to the Request element.
-
-**/
-VOID
-RemoveConfigRequest (
- FORMSET_STORAGE *Storage,
- CHAR16 *ConfigRequest
- )
-{
- CHAR16 *RequestElement;
- CHAR16 *NextRequestElement;
- CHAR16 *SearchKey;
-
- //
- // No request element in it, just return.
- //
- if (ConfigRequest == NULL) {
- return;
- }
-
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- //
- // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
- //
- SearchKey = L"&";
- } else {
- //
- // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
- //
- SearchKey = L"&OFFSET";
- }
-
- //
- // Find SearchKey storage
- //
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- RequestElement = StrStr (ConfigRequest, L"PATH");
- ASSERT (RequestElement != NULL);
- RequestElement = StrStr (RequestElement, SearchKey);
- } else {
- RequestElement = StrStr (ConfigRequest, SearchKey);
- }
-
- while (RequestElement != NULL) {
- //
- // +1 to avoid find header itself.
- //
- NextRequestElement = StrStr (RequestElement + 1, SearchKey);
-
- //
- // The last Request element in configRequest string.
- //
- if (NextRequestElement != NULL) {
- //
- // Replace "&" with '\0'.
- //
- *NextRequestElement = L'\0';
- }
-
- RemoveElement (Storage->BrowserStorage, RequestElement);
-
- if (NextRequestElement != NULL) {
- //
- // Restore '&' with '\0' for later used.
- //
- *NextRequestElement = L'&';
- }
-
- RequestElement = NextRequestElement;
- }
-
- //
- // If no request element remain, just remove the ConfigRequest string.
- //
- if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {
- FreePool (Storage->BrowserStorage->ConfigRequest);
- Storage->BrowserStorage->ConfigRequest = NULL;
- Storage->BrowserStorage->SpareStrLen = 0;
- }
-}
-
-/**
- Base on the current formset info, clean the ConfigRequest string in browser storage.
-
- @param FormSet Pointer of the FormSet
-
-**/
-VOID
-CleanBrowserStorage (
- IN OUT FORM_BROWSER_FORMSET *FormSet
- )
-{
- LIST_ENTRY *Link;
- FORMSET_STORAGE *Storage;
-
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- Storage = FORMSET_STORAGE_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->StorageListHead, Link);
-
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
- if ((Storage->ConfigRequest == NULL) || (Storage->BrowserStorage->ConfigRequest == NULL)) {
- continue;
- }
-
- RemoveConfigRequest (Storage, Storage->ConfigRequest);
- } else if ((Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER) ||
- (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE))
- {
- if (Storage->BrowserStorage->ConfigRequest != NULL) {
- FreePool (Storage->BrowserStorage->ConfigRequest);
- Storage->BrowserStorage->ConfigRequest = NULL;
- }
-
- Storage->BrowserStorage->Initialized = FALSE;
- }
- }
-}
-
-/**
- Check whether current element in the ConfigReqeust string.
-
- @param BrowserStorage Storage which includes ConfigReqeust.
- @param RequestElement New element need to check.
-
- @retval TRUE The Element is in the ConfigReqeust string.
- @retval FALSE The Element not in the configReqeust String.
-
-**/
-BOOLEAN
-ElementValidation (
- BROWSER_STORAGE *BrowserStorage,
- CHAR16 *RequestElement
- )
-{
- return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
-}
-
-/**
- Append the Request element to the Config Request.
-
- @param ConfigRequest Current ConfigRequest info.
- @param SpareStrLen Current remain free buffer for config reqeust.
- @param RequestElement New Request element.
-
-**/
-VOID
-AppendConfigRequest (
- IN OUT CHAR16 **ConfigRequest,
- IN OUT UINTN *SpareStrLen,
- IN CHAR16 *RequestElement
- )
-{
- CHAR16 *NewStr;
- UINTN StringSize;
- UINTN StrLength;
- UINTN MaxLen;
-
- StrLength = StrLen (RequestElement);
- StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
- MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen;
-
- //
- // Append <RequestElement> to <ConfigRequest>
- //
- if (StrLength > *SpareStrLen) {
- //
- // Old String buffer is not sufficient for RequestElement, allocate a new one
- //
- MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
- NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (NewStr != NULL);
-
- if (*ConfigRequest != NULL) {
- CopyMem (NewStr, *ConfigRequest, StringSize);
- FreePool (*ConfigRequest);
- }
-
- *ConfigRequest = NewStr;
- *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
- }
-
- StrCatS (*ConfigRequest, MaxLen, RequestElement);
- *SpareStrLen -= StrLength;
-}
-
-/**
- Adjust the config request info, remove the request elements which already in AllConfigRequest string.
-
- @param Storage Form set Storage.
- @param Request The input request string.
- @param RespString Whether the input is ConfigRequest or ConfigResp format.
-
- @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
- @retval FALSE All elements covered by current used elements.
-
-**/
-BOOLEAN
-ConfigRequestAdjust (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Request,
- IN BOOLEAN RespString
- )
-{
- CHAR16 *RequestElement;
- CHAR16 *NextRequestElement;
- CHAR16 *NextElementBakup;
- CHAR16 *SearchKey;
- CHAR16 *ValueKey;
- BOOLEAN RetVal;
- CHAR16 *ConfigRequest;
-
- RetVal = FALSE;
- NextElementBakup = NULL;
- ValueKey = NULL;
-
- if (Request != NULL) {
- ConfigRequest = Request;
- } else {
- ConfigRequest = Storage->ConfigRequest;
- }
-
- if (Storage->ConfigRequest == NULL) {
- Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
- return TRUE;
- }
-
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- //
- // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
- //
- SearchKey = L"&";
- } else {
- //
- // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
- //
- SearchKey = L"&OFFSET";
- ValueKey = L"&VALUE";
- }
-
- //
- // Find SearchKey storage
- //
- if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- RequestElement = StrStr (ConfigRequest, L"PATH");
- ASSERT (RequestElement != NULL);
- RequestElement = StrStr (RequestElement, SearchKey);
- } else {
- RequestElement = StrStr (ConfigRequest, SearchKey);
- }
-
- while (RequestElement != NULL) {
- //
- // +1 to avoid find header itself.
- //
- NextRequestElement = StrStr (RequestElement + 1, SearchKey);
-
- //
- // The last Request element in configRequest string.
- //
- if (NextRequestElement != NULL) {
- if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
- NextElementBakup = NextRequestElement;
- NextRequestElement = StrStr (RequestElement, ValueKey);
- ASSERT (NextRequestElement != NULL);
- }
-
- //
- // Replace "&" with '\0'.
- //
- *NextRequestElement = L'\0';
- } else {
- if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
- NextElementBakup = NextRequestElement;
- NextRequestElement = StrStr (RequestElement, ValueKey);
- ASSERT (NextRequestElement != NULL);
- //
- // Replace "&" with '\0'.
- //
- *NextRequestElement = L'\0';
- }
- }
-
- if (!ElementValidation (Storage, RequestElement)) {
- //
- // Add this element to the Storage->BrowserStorage->AllRequestElement.
- //
- AppendConfigRequest (&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
- RetVal = TRUE;
- }
-
- if (NextRequestElement != NULL) {
- //
- // Restore '&' with '\0' for later used.
- //
- *NextRequestElement = L'&';
- }
-
- if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
- RequestElement = NextElementBakup;
- } else {
- RequestElement = NextRequestElement;
- }
- }
-
- return RetVal;
-}
-
-/**
- Fill storage's edit copy with settings requested from Configuration Driver.
-
- @param FormSet FormSet data structure.
- @param Storage Buffer Storage.
-
-**/
-VOID
-LoadStorage (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORMSET_STORAGE *Storage
- )
-{
- EFI_STATUS Status;
- EFI_STRING Progress;
- EFI_STRING Result;
- CHAR16 *StrPtr;
- EFI_STRING ConfigRequest;
- UINTN StrLen;
-
- ConfigRequest = NULL;
-
- switch (Storage->BrowserStorage->Type) {
- case EFI_HII_VARSTORE_EFI_VARIABLE:
- return;
-
- case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
- if (Storage->BrowserStorage->ConfigRequest != NULL) {
- ConfigRequestAdjust (Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
- return;
- }
-
- break;
-
- case EFI_HII_VARSTORE_BUFFER:
- case EFI_HII_VARSTORE_NAME_VALUE:
- //
- // Skip if there is no RequestElement.
- //
- if (Storage->ElementCount == 0) {
- return;
- }
-
- //
- // Just update the ConfigRequest, if storage already initialized.
- //
- if (Storage->BrowserStorage->Initialized) {
- ConfigRequestAdjust (Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
- return;
- }
-
- Storage->BrowserStorage->Initialized = TRUE;
- break;
-
- default:
- return;
- }
-
- if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
- //
- // Create the config request string to get all fields for this storage.
- // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
- // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
- //
- StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);
- ConfigRequest = AllocateZeroPool (StrLen);
- ASSERT (ConfigRequest != NULL);
- UnicodeSPrint (
- ConfigRequest,
- StrLen,
- L"%s&OFFSET=0&WIDTH=%04x",
- Storage->ConfigHdr,
- Storage->BrowserStorage->Size
- );
- } else {
- ConfigRequest = Storage->ConfigRequest;
- }
-
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
- //
- // Call GetVariable directly for EfiVarStore
- //
- Status = gRT->GetVariable (Storage->BrowserStorage->Name, &(Storage->BrowserStorage->Guid), NULL, (UINTN *)(&(Storage->BrowserStorage->Size)), Storage->BrowserStorage->EditBuffer);
- if (EFI_ERROR (Status)) {
- ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
- }
- } else {
- //
- // Request current settings from Configuration Driver
- //
- Status = mHiiConfigRouting->ExtractConfig (
- mHiiConfigRouting,
- ConfigRequest,
- &Progress,
- &Result
- );
-
- //
- // If get value fail, extract default from IFR binary
- //
- if (EFI_ERROR (Status)) {
- ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
- } else {
- //
- // Convert Result from <ConfigAltResp> to <ConfigResp>
- //
- StrPtr = StrStr (Result, L"&GUID=");
- if (StrPtr != NULL) {
- *StrPtr = L'\0';
- }
-
- Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
- FreePool (Result);
- }
- }
-
- Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
-
- //
- // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
- //
- SynchronizeStorage (Storage->BrowserStorage, NULL, TRUE);
-
- if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
- if (ConfigRequest != NULL) {
- FreePool (ConfigRequest);
- }
- }
-}
-
-/**
- Get Value changed status from old question.
-
- @param NewFormSet FormSet data structure.
- @param OldQuestion Old question which has value changed.
-
-**/
-VOID
-SyncStatusForQuestion (
- IN OUT FORM_BROWSER_FORMSET *NewFormSet,
- IN FORM_BROWSER_STATEMENT *OldQuestion
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *QuestionLink;
- FORM_BROWSER_FORM *Form;
- FORM_BROWSER_STATEMENT *Question;
-
- //
- // For each form in one formset.
- //
- Link = GetFirstNode (&NewFormSet->FormListHead);
- while (!IsNull (&NewFormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&NewFormSet->FormListHead, Link);
-
- //
- // for each question in one form.
- //
- QuestionLink = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, QuestionLink)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
- QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
-
- if (Question->QuestionId == OldQuestion->QuestionId) {
- Question->ValueChanged = TRUE;
- return;
- }
- }
- }
-}
-
-/**
- Get Value changed status from old formset.
-
- @param NewFormSet FormSet data structure.
- @param OldFormSet FormSet data structure.
-
-**/
-VOID
-SyncStatusForFormSet (
- IN OUT FORM_BROWSER_FORMSET *NewFormSet,
- IN FORM_BROWSER_FORMSET *OldFormSet
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *QuestionLink;
- FORM_BROWSER_FORM *Form;
- FORM_BROWSER_STATEMENT *Question;
-
- //
- // For each form in one formset.
- //
- Link = GetFirstNode (&OldFormSet->FormListHead);
- while (!IsNull (&OldFormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- Link = GetNextNode (&OldFormSet->FormListHead, Link);
-
- //
- // for each question in one form.
- //
- QuestionLink = GetFirstNode (&Form->StatementListHead);
- while (!IsNull (&Form->StatementListHead, QuestionLink)) {
- Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
- QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
-
- if (!Question->ValueChanged) {
- continue;
- }
-
- //
- // Find the same question in new formset and update the value changed flag.
- //
- SyncStatusForQuestion (NewFormSet, Question);
- }
- }
-}
-
-/**
- Get current setting of Questions.
-
- @param FormSet FormSet data structure.
-
-**/
-VOID
-InitializeCurrentSetting (
- IN OUT FORM_BROWSER_FORMSET *FormSet
- )
-{
- LIST_ENTRY *Link;
- FORMSET_STORAGE *Storage;
- FORM_BROWSER_FORMSET *OldFormSet;
-
- //
- // Try to find pre FormSet in the maintain backup list.
- // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
- //
- OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
- if (OldFormSet != NULL) {
- SyncStatusForFormSet (FormSet, OldFormSet);
- RemoveEntryList (&OldFormSet->Link);
- DestroyFormSet (OldFormSet);
- }
-
- InsertTailList (&gBrowserFormSetList, &FormSet->Link);
-
- //
- // Extract default from IFR binary for no storage questions.
- //
- ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
-
- //
- // Request current settings from Configuration Driver
- //
- Link = GetFirstNode (&FormSet->StorageListHead);
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- Storage = FORMSET_STORAGE_FROM_LINK (Link);
-
- LoadStorage (FormSet, Storage);
-
- Link = GetNextNode (&FormSet->StorageListHead, Link);
- }
-}
-
-/**
- Fetch the Ifr binary data of a FormSet.
-
- @param Handle PackageList Handle
- @param FormSetGuid On input, GUID or class GUID of a formset. If not
- specified (NULL or zero GUID), take the first
- FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
- found in package list.
- On output, GUID of the formset found(if not NULL).
- @param BinaryLength The length of the FormSet IFR binary.
- @param BinaryData The buffer designed to receive the FormSet.
-
- @retval EFI_SUCCESS Buffer filled with the requested FormSet.
- BufferLength was updated.
- @retval EFI_INVALID_PARAMETER The handle is unknown.
- @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
- be found with the requested FormId.
-
-**/
-EFI_STATUS
-GetIfrBinaryData (
- IN EFI_HII_HANDLE Handle,
- IN OUT EFI_GUID *FormSetGuid,
- OUT UINTN *BinaryLength,
- OUT UINT8 **BinaryData
- )
-{
- EFI_STATUS Status;
- EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
- UINTN BufferSize;
- UINT8 *Package;
- UINT8 *OpCodeData;
- UINT32 Offset;
- UINT32 Offset2;
- UINT32 PackageListLength;
- EFI_HII_PACKAGE_HEADER PackageHeader;
- UINT8 Index;
- UINT8 NumberOfClassGuid;
- BOOLEAN ClassGuidMatch;
- EFI_GUID *ClassGuid;
- EFI_GUID *ComparingGuid;
-
- OpCodeData = NULL;
- Package = NULL;
- ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
-
- //
- // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
- //
- if (FormSetGuid == NULL) {
- ComparingGuid = &gZeroGuid;
- } else {
- ComparingGuid = FormSetGuid;
- }
-
- //
- // Get HII PackageList
- //
- BufferSize = 0;
- HiiPackageList = NULL;
- Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- HiiPackageList = AllocatePool (BufferSize);
- ASSERT (HiiPackageList != NULL);
-
- Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ASSERT (HiiPackageList != NULL);
-
- //
- // Get Form package from this HII package List
- //
- Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
- Offset2 = 0;
- CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
-
- ClassGuidMatch = FALSE;
- while (Offset < PackageListLength) {
- Package = ((UINT8 *)HiiPackageList) + Offset;
- CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
-
- if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
- //
- // Search FormSet in this Form Package
- //
- Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
- while (Offset2 < PackageHeader.Length) {
- OpCodeData = Package + Offset2;
-
- if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
- //
- // Try to compare against formset GUID
- //
- if (IsZeroGuid (ComparingGuid) ||
- CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER))))
- {
- break;
- }
-
- if (((EFI_IFR_OP_HEADER *)OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
- //
- // Try to compare against formset class GUID
- //
- NumberOfClassGuid = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
- ClassGuid = (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET));
- for (Index = 0; Index < NumberOfClassGuid; Index++) {
- if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
- ClassGuidMatch = TRUE;
- break;
- }
- }
-
- if (ClassGuidMatch) {
- break;
- }
- } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
- ClassGuidMatch = TRUE;
- break;
- }
- }
-
- Offset2 += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
- }
-
- if (Offset2 < PackageHeader.Length) {
- //
- // Target formset found
- //
- break;
- }
- }
-
- Offset += PackageHeader.Length;
- }
-
- if (Offset >= PackageListLength) {
- //
- // Form package not found in this Package List
- //
- FreePool (HiiPackageList);
- return EFI_NOT_FOUND;
- }
-
- if (FormSetGuid != NULL) {
- //
- // Return the FormSet GUID
- //
- CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *)OpCodeData)->Guid, sizeof (EFI_GUID));
- }
-
- //
- // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
- // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
- // of the Form Package.
- //
- *BinaryLength = PackageHeader.Length - Offset2;
- *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
-
- FreePool (HiiPackageList);
-
- if (*BinaryData == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Initialize the internal data structure of a FormSet.
-
- @param Handle PackageList Handle
- @param FormSetGuid On input, GUID or class GUID of a formset. If not
- specified (NULL or zero GUID), take the first
- FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
- found in package list.
- On output, GUID of the formset found(if not NULL).
- @param FormSet FormSet data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_NOT_FOUND The specified FormSet could not be found.
-
-**/
-EFI_STATUS
-InitializeFormSet (
- IN EFI_HII_HANDLE Handle,
- IN OUT EFI_GUID *FormSetGuid,
- OUT FORM_BROWSER_FORMSET *FormSet
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE DriverHandle;
-
- Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
- FormSet->HiiHandle = Handle;
- CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
- FormSet->QuestionInited = FALSE;
-
- //
- // Retrieve ConfigAccess Protocol associated with this HiiPackageList
- //
- Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- FormSet->DriverHandle = DriverHandle;
- Status = gBS->HandleProtocol (
- DriverHandle,
- &gEfiHiiConfigAccessProtocolGuid,
- (VOID **)&FormSet->ConfigAccess
- );
- if (EFI_ERROR (Status)) {
- //
- // Configuration Driver don't attach ConfigAccess protocol to its HII package
- // list, then there will be no configuration action required
- //
- FormSet->ConfigAccess = NULL;
- }
-
- //
- // Parse the IFR binary OpCodes
- //
- Status = ParseOpCodes (FormSet);
-
- return Status;
-}
-
-/**
- Save globals used by previous call to SendForm(). SendForm() may be called from
- HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
- So, save globals of previous call to SendForm() and restore them upon exit.
-
-**/
-VOID
-SaveBrowserContext (
- VOID
- )
-{
- BROWSER_CONTEXT *Context;
- FORM_ENTRY_INFO *MenuList;
- FORM_BROWSER_FORMSET *FormSet;
-
- gBrowserContextCount++;
- if (gBrowserContextCount == 1) {
- //
- // This is not reentry of SendForm(), no context to save
- //
- return;
- }
-
- Context = AllocatePool (sizeof (BROWSER_CONTEXT));
- ASSERT (Context != NULL);
-
- Context->Signature = BROWSER_CONTEXT_SIGNATURE;
-
- //
- // Save FormBrowser context
- //
- Context->Selection = gCurrentSelection;
- Context->ResetRequired = gResetRequiredFormLevel;
- Context->FlagReconnect = gFlagReconnect;
- Context->CallbackReconnect = gCallbackReconnect;
- Context->ExitRequired = gExitRequired;
- Context->HiiHandle = mCurrentHiiHandle;
- Context->FormId = mCurrentFormId;
- CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
- Context->SystemLevelFormSet = mSystemLevelFormSet;
- Context->CurFakeQestId = mCurFakeQestId;
- Context->HiiPackageListUpdated = mHiiPackageListUpdated;
- Context->FinishRetrieveCall = mFinishRetrieveCall;
-
- //
- // Save the menu history data.
- //
- InitializeListHead (&Context->FormHistoryList);
- while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
- MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
- RemoveEntryList (&MenuList->Link);
-
- InsertTailList (&Context->FormHistoryList, &MenuList->Link);
- }
-
- //
- // Save formset list.
- //
- InitializeListHead (&Context->FormSetList);
- while (!IsListEmpty (&gBrowserFormSetList)) {
- FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink);
- RemoveEntryList (&FormSet->Link);
-
- InsertTailList (&Context->FormSetList, &FormSet->Link);
- }
-
- //
- // Insert to FormBrowser context list
- //
- InsertHeadList (&gBrowserContextList, &Context->Link);
-}
-
-/**
- Restore globals used by previous call to SendForm().
-
-**/
-VOID
-RestoreBrowserContext (
- VOID
- )
-{
- LIST_ENTRY *Link;
- BROWSER_CONTEXT *Context;
- FORM_ENTRY_INFO *MenuList;
- FORM_BROWSER_FORMSET *FormSet;
-
- ASSERT (gBrowserContextCount != 0);
- gBrowserContextCount--;
- if (gBrowserContextCount == 0) {
- //
- // This is not reentry of SendForm(), no context to restore
- //
- return;
- }
-
- ASSERT (!IsListEmpty (&gBrowserContextList));
-
- Link = GetFirstNode (&gBrowserContextList);
- Context = BROWSER_CONTEXT_FROM_LINK (Link);
-
- //
- // Restore FormBrowser context
- //
- gCurrentSelection = Context->Selection;
- gResetRequiredFormLevel = Context->ResetRequired;
- gFlagReconnect = Context->FlagReconnect;
- gCallbackReconnect = Context->CallbackReconnect;
- gExitRequired = Context->ExitRequired;
- mCurrentHiiHandle = Context->HiiHandle;
- mCurrentFormId = Context->FormId;
- CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
- mSystemLevelFormSet = Context->SystemLevelFormSet;
- mCurFakeQestId = Context->CurFakeQestId;
- mHiiPackageListUpdated = Context->HiiPackageListUpdated;
- mFinishRetrieveCall = Context->FinishRetrieveCall;
-
- //
- // Restore the menu history data.
- //
- while (!IsListEmpty (&Context->FormHistoryList)) {
- MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
- RemoveEntryList (&MenuList->Link);
-
- InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
- }
-
- //
- // Restore the Formset data.
- //
- while (!IsListEmpty (&Context->FormSetList)) {
- FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink);
- RemoveEntryList (&FormSet->Link);
-
- InsertTailList (&gBrowserFormSetList, &FormSet->Link);
- }
-
- //
- // Remove from FormBrowser context list
- //
- RemoveEntryList (&Context->Link);
- gBS->FreePool (Context);
-}
-
-/**
- Find the matched FormSet context in the backup maintain list based on HiiHandle.
-
- @param Handle The Hii Handle.
-
- @return the found FormSet context. If no found, NULL will return.
-
-**/
-FORM_BROWSER_FORMSET *
-GetFormSetFromHiiHandle (
- EFI_HII_HANDLE Handle
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORMSET *FormSet;
-
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserFormSetList, Link);
- if (!ValidateFormSet (FormSet)) {
- continue;
- }
-
- if (FormSet->HiiHandle == Handle) {
- return FormSet;
- }
- }
-
- return NULL;
-}
-
-/**
- Check whether the input HII handle is the FormSet that is being used.
-
- @param Handle The Hii Handle.
-
- @retval TRUE HII handle is being used.
- @retval FALSE HII handle is not being used.
-
-**/
-BOOLEAN
-IsHiiHandleInBrowserContext (
- EFI_HII_HANDLE Handle
- )
-{
- LIST_ENTRY *Link;
- BROWSER_CONTEXT *Context;
-
- //
- // HiiHandle is Current FormSet.
- //
- if (mCurrentHiiHandle == Handle) {
- return TRUE;
- }
-
- //
- // Check whether HiiHandle is in BrowserContext.
- //
- Link = GetFirstNode (&gBrowserContextList);
- while (!IsNull (&gBrowserContextList, Link)) {
- Context = BROWSER_CONTEXT_FROM_LINK (Link);
- if (Context->HiiHandle == Handle) {
- //
- // HiiHandle is in BrowserContext
- //
- return TRUE;
- }
-
- Link = GetNextNode (&gBrowserContextList, Link);
- }
-
- return FALSE;
-}
-
-/**
- Perform Password check.
- Passwork may be encrypted by driver that requires the specific check.
-
- @param Form Form where Password Statement is in.
- @param Statement Password statement
- @param PasswordString Password string to be checked. It may be NULL.
- NULL means to restore password.
- "" string can be used to checked whether old password does exist.
-
- @return Status Status of Password check.
-**/
-EFI_STATUS
-EFIAPI
-PasswordCheck (
- IN FORM_DISPLAY_ENGINE_FORM *Form,
- IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
- IN EFI_STRING PasswordString OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
- EFI_BROWSER_ACTION_REQUEST ActionRequest;
- EFI_IFR_TYPE_VALUE IfrTypeValue;
- FORM_BROWSER_STATEMENT *Question;
-
- ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
- Question = GetBrowserStatement (Statement);
- ASSERT (Question != NULL);
-
- if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
- if (ConfigAccess == NULL) {
- return EFI_UNSUPPORTED;
- }
- } else {
- //
- // If a password doesn't have the CALLBACK flag, browser will not handle it.
- //
- return EFI_UNSUPPORTED;
- }
-
- //
- // Prepare password string in HII database
- //
- if (PasswordString != NULL) {
- IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
- } else {
- IfrTypeValue.string = 0;
- }
-
- //
- // Send password to Configuration Driver for validation
- //
- Status = ConfigAccess->Callback (
- ConfigAccess,
- EFI_BROWSER_ACTION_CHANGING,
- Question->QuestionId,
- Question->HiiValue.Type,
- &IfrTypeValue,
- &ActionRequest
- );
-
- //
- // Remove password string from HII database
- //
- if (PasswordString != NULL) {
- DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
- }
-
- return Status;
-}
-
-/**
- Find the registered HotKey based on KeyData.
-
- @param[in] KeyData A pointer to a buffer that describes the keystroke
- information for the hot key.
-
- @return The registered HotKey context. If no found, NULL will return.
-**/
-BROWSER_HOT_KEY *
-GetHotKeyFromRegisterList (
- IN EFI_INPUT_KEY *KeyData
- )
-{
- LIST_ENTRY *Link;
- BROWSER_HOT_KEY *HotKey;
-
- Link = GetFirstNode (&gBrowserHotKeyList);
- while (!IsNull (&gBrowserHotKeyList, Link)) {
- HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
- if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
- return HotKey;
- }
-
- Link = GetNextNode (&gBrowserHotKeyList, Link);
- }
-
- return NULL;
-}
-
-/**
- Configure what scope the hot key will impact.
- All hot keys have the same scope. The mixed hot keys with the different level are not supported.
- If no scope is set, the default scope will be FormSet level.
- After all registered hot keys are removed, previous Scope can reset to another level.
-
- @param[in] Scope Scope level to be set.
-
- @retval EFI_SUCCESS Scope is set correctly.
- @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
- @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
-
-**/
-EFI_STATUS
-EFIAPI
-SetScope (
- IN BROWSER_SETTING_SCOPE Scope
- )
-{
- if (Scope >= MaxLevel) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // When no hot key registered in system or on the first setting,
- // Scope can be set.
- //
- if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
- gBrowserSettingScope = Scope;
- mBrowserScopeFirstSet = FALSE;
- } else if (Scope != gBrowserSettingScope) {
- return EFI_UNSUPPORTED;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Register the hot key with its browser action, or unregistered the hot key.
- Only support hot key that is not printable character (control key, function key, etc.).
- If the action value is zero, the hot key will be unregistered if it has been registered.
- If the same hot key has been registered, the new action and help string will override the previous ones.
-
- @param[in] KeyData A pointer to a buffer that describes the keystroke
- information for the hot key. Its type is EFI_INPUT_KEY to
- be supported by all ConsoleIn devices.
- @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
- @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
- @param[in] HelpString Help string that describes the hot key information.
- Its value may be NULL for the unregistered hot key.
-
- @retval EFI_SUCCESS Hot key is registered or unregistered.
- @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
- @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
- @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
- @retval EFI_ALREADY_STARTED Key already been registered for one hot key.
-**/
-EFI_STATUS
-EFIAPI
-RegisterHotKey (
- IN EFI_INPUT_KEY *KeyData,
- IN UINT32 Action,
- IN UINT16 DefaultId,
- IN EFI_STRING HelpString OPTIONAL
- )
-{
- BROWSER_HOT_KEY *HotKey;
-
- //
- // Check input parameters.
- //
- if ((KeyData == NULL) || (KeyData->UnicodeChar != CHAR_NULL) ||
- ((Action != BROWSER_ACTION_UNREGISTER) && (HelpString == NULL)))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Check whether the input KeyData is in BrowserHotKeyList.
- //
- HotKey = GetHotKeyFromRegisterList (KeyData);
-
- //
- // Unregister HotKey
- //
- if (Action == BROWSER_ACTION_UNREGISTER) {
- if (HotKey != NULL) {
- //
- // The registered HotKey is found.
- // Remove it from List, and free its resource.
- //
- RemoveEntryList (&HotKey->Link);
- FreePool (HotKey->KeyData);
- FreePool (HotKey->HelpString);
- return EFI_SUCCESS;
- } else {
- //
- // The registered HotKey is not found.
- //
- return EFI_NOT_FOUND;
- }
- }
-
- if (HotKey != NULL) {
- return EFI_ALREADY_STARTED;
- }
-
- //
- // Create new Key, and add it into List.
- //
- HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
- ASSERT (HotKey != NULL);
- HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
- HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
- InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
-
- //
- // Fill HotKey information.
- //
- HotKey->Action = Action;
- HotKey->DefaultId = DefaultId;
- if (HotKey->HelpString != NULL) {
- FreePool (HotKey->HelpString);
- }
-
- HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
-
- return EFI_SUCCESS;
-}
-
-/**
- Register Exit handler function.
- When more than one handler function is registered, the latter one will override the previous one.
- When NULL handler is specified, the previous Exit handler will be unregistered.
-
- @param[in] Handler Pointer to handler function.
-
-**/
-VOID
-EFIAPI
-RegiserExitHandler (
- IN EXIT_HANDLER Handler
- )
-{
- ExitHandlerFunction = Handler;
- return;
-}
-
-/**
- Check whether the browser data has been modified.
-
- @retval TRUE Browser data is modified.
- @retval FALSE No browser data is modified.
-
-**/
-BOOLEAN
-EFIAPI
-IsBrowserDataModified (
- VOID
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORMSET *FormSet;
-
- switch (gBrowserSettingScope) {
- case FormLevel:
- if (gCurrentSelection == NULL) {
- return FALSE;
- }
-
- return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
-
- case FormSetLevel:
- if (gCurrentSelection == NULL) {
- return FALSE;
- }
-
- return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
-
- case SystemLevel:
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- if (!ValidateFormSet (FormSet)) {
- continue;
- }
-
- if (IsNvUpdateRequiredForFormSet (FormSet)) {
- return TRUE;
- }
-
- Link = GetNextNode (&gBrowserFormSetList, Link);
- }
-
- return FALSE;
-
- default:
- return FALSE;
- }
-}
-
-/**
- Execute the action requested by the Action parameter.
-
- @param[in] Action Execute the request action.
- @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
-
- @retval EFI_SUCCESS Execute the request action succss.
- @retval EFI_INVALID_PARAMETER The input action value is invalid.
-
-**/
-EFI_STATUS
-EFIAPI
-ExecuteAction (
- IN UINT32 Action,
- IN UINT16 DefaultId
- )
-{
- EFI_STATUS Status;
- FORM_BROWSER_FORMSET *FormSet;
- FORM_BROWSER_FORM *Form;
-
- if ((gBrowserSettingScope < SystemLevel) && (gCurrentSelection == NULL)) {
- return EFI_NOT_READY;
- }
-
- Status = EFI_SUCCESS;
- FormSet = NULL;
- Form = NULL;
- if (gBrowserSettingScope < SystemLevel) {
- FormSet = gCurrentSelection->FormSet;
- Form = gCurrentSelection->Form;
- }
-
- //
- // Executet the discard action.
- //
- if ((Action & BROWSER_ACTION_DISCARD) != 0) {
- Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Executet the difault action.
- //
- if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
- Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
- }
-
- //
- // Executet the submit action.
- //
- if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
- Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Executet the reset action.
- //
- if ((Action & BROWSER_ACTION_RESET) != 0) {
- gResetRequiredFormLevel = TRUE;
- gResetRequiredSystemLevel = TRUE;
- }
-
- //
- // Executet the exit action.
- //
- if ((Action & BROWSER_ACTION_EXIT) != 0) {
- DiscardForm (FormSet, Form, gBrowserSettingScope);
- if (gBrowserSettingScope == SystemLevel) {
- if (ExitHandlerFunction != NULL) {
- ExitHandlerFunction ();
- }
- }
-
- gExitRequired = TRUE;
- }
-
- return Status;
-}
-
-/**
- Create reminder to let user to choose save or discard the changed browser data.
- Caller can use it to actively check the changed browser data.
-
- @retval BROWSER_NO_CHANGES No browser data is changed.
- @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
- @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
- @retval BROWSER_KEEP_CURRENT Browser keep current changes.
-
-**/
-UINT32
-EFIAPI
-SaveReminder (
- VOID
- )
-{
- LIST_ENTRY *Link;
- FORM_BROWSER_FORMSET *FormSet;
- BOOLEAN IsDataChanged;
- UINT32 DataSavedAction;
- UINT32 ConfirmRet;
-
- DataSavedAction = BROWSER_NO_CHANGES;
- IsDataChanged = FALSE;
- Link = GetFirstNode (&gBrowserFormSetList);
- while (!IsNull (&gBrowserFormSetList, Link)) {
- FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
- Link = GetNextNode (&gBrowserFormSetList, Link);
- if (!ValidateFormSet (FormSet)) {
- continue;
- }
-
- if (IsNvUpdateRequiredForFormSet (FormSet)) {
- IsDataChanged = TRUE;
- break;
- }
- }
-
- //
- // No data is changed. No save is required.
- //
- if (!IsDataChanged) {
- return DataSavedAction;
- }
-
- //
- // If data is changed, prompt user to save or discard it.
- //
- do {
- ConfirmRet = (UINT32)mFormDisplay->ConfirmDataChange ();
-
- if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
- SubmitForm (NULL, NULL, SystemLevel);
- DataSavedAction = BROWSER_SAVE_CHANGES;
- break;
- } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
- DiscardForm (NULL, NULL, SystemLevel);
- DataSavedAction = BROWSER_DISCARD_CHANGES;
- break;
- } else if (ConfirmRet == BROWSER_ACTION_NONE) {
- DataSavedAction = BROWSER_KEEP_CURRENT;
- break;
- }
- } while (1);
-
- return DataSavedAction;
-}
-
-/**
- Check whether the Reset Required for the browser
-
- @retval TRUE Browser required to reset after exit.
- @retval FALSE Browser not need to reset after exit.
-
-**/
-BOOLEAN
-EFIAPI
-IsResetRequired (
- VOID
- )
-{
- return gResetRequiredSystemLevel;
-}
+/** @file +Entry and initialization module for the browser. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2020 - 2022 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Setup.h" + +SETUP_DRIVER_PRIVATE_DATA mPrivateData = { + SETUP_DRIVER_SIGNATURE, + NULL, + { + SendForm, + BrowserCallback + }, + { + SetScope, + RegisterHotKey, + RegiserExitHandler, + SaveReminder + }, + { + BROWSER_EXTENSION2_VERSION_1_1, + SetScope, + RegisterHotKey, + RegiserExitHandler, + IsBrowserDataModified, + ExecuteAction, + { NULL, NULL }, + { NULL, NULL }, + IsResetRequired + } +}; + +EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; +EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText; +EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay; + +UINTN gBrowserContextCount = 0; +LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList); +LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList); +LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList); +LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList); +LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList); + +BOOLEAN mSystemSubmit = FALSE; +BOOLEAN gResetRequiredFormLevel; +BOOLEAN gResetRequiredSystemLevel = FALSE; +BOOLEAN gExitRequired; +BOOLEAN gFlagReconnect; +BOOLEAN gCallbackReconnect; +BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel; +BOOLEAN mBrowserScopeFirstSet = TRUE; +EXIT_HANDLER ExitHandlerFunction = NULL; +FORM_BROWSER_FORMSET *mSystemLevelFormSet; + +// +// Browser Global Strings +// +CHAR16 *gEmptyString; +CHAR16 *mUnknownString = L"!"; + +extern EFI_GUID mCurrentFormSetGuid; +extern EFI_HII_HANDLE mCurrentHiiHandle; +extern UINT16 mCurrentFormId; +extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData; + +/** + Create a menu with specified formset GUID and form ID, and add it as a child + of the given parent menu. + + @param HiiHandle Hii handle related to this formset. + @param FormSetGuid The Formset Guid of menu to be added. + @param FormId The Form ID of menu to be added. + @param QuestionId The question id of this menu to be added. + + @return A pointer to the newly added menu or NULL if memory is insufficient. + +**/ +FORM_ENTRY_INFO * +UiAddMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId, + IN UINT16 QuestionId + ) +{ + FORM_ENTRY_INFO *MenuList; + + MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); + if (MenuList == NULL) { + return NULL; + } + + MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE; + + MenuList->HiiHandle = HiiHandle; + CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + MenuList->FormId = FormId; + MenuList->QuestionId = QuestionId; + + // + // If parent is not specified, it is the root Form of a Formset + // + InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); + + return MenuList; +} + +/** + Return the form id for the input hiihandle and formset. + + @param HiiHandle HiiHandle for FormSet. + @param FormSetGuid The Formset GUID of the menu to search. + + @return First form's id for this form set. + +**/ +EFI_FORM_ID +GetFirstFormId ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead); + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + return Form->FormId; +} + +/** + Search Menu with given FormSetGuid and FormId in all cached menu list. + + @param HiiHandle HiiHandle for FormSet. + @param FormSetGuid The Formset GUID of the menu to search. + @param FormId The Form ID of menu to search. + + @return A pointer to menu found or NULL if not found. + +**/ +FORM_ENTRY_INFO * +UiFindMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId + ) +{ + LIST_ENTRY *Link; + FORM_ENTRY_INFO *MenuList; + FORM_ENTRY_INFO *RetMenu; + EFI_FORM_ID FirstFormId; + + RetMenu = NULL; + + Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); + while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); + Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link); + + // + // If already find the menu, free the menus behind it. + // + if (RetMenu != NULL) { + RemoveEntryList (&MenuList->Link); + FreePool (MenuList); + continue; + } + + // + // Find the same FromSet. + // + if (MenuList->HiiHandle == HiiHandle) { + if (IsZeroGuid (&MenuList->FormSetGuid)) { + // + // FormSetGuid is not specified. + // + RetMenu = MenuList; + } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) { + if (MenuList->FormId == FormId) { + RetMenu = MenuList; + } else if ((FormId == 0) || (MenuList->FormId == 0)) { + FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid); + if (((FormId == 0) && (FirstFormId == MenuList->FormId)) || ((MenuList->FormId == 0) && (FirstFormId == FormId))) { + RetMenu = MenuList; + } + } + } + } + } + + return RetMenu; +} + +/** + Find parent menu for current menu. + + @param CurrentMenu Current Menu + @param SettingLevel Whether find parent menu in Form Level or Formset level. + In form level, just find the parent menu; + In formset level, find the parent menu which has different + formset guid value. + + @retval The parent menu for current menu. +**/ +FORM_ENTRY_INFO * +UiFindParentMenu ( + IN FORM_ENTRY_INFO *CurrentMenu, + IN BROWSER_SETTING_SCOPE SettingLevel + ) +{ + FORM_ENTRY_INFO *ParentMenu; + LIST_ENTRY *Link; + + ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel); + + if (CurrentMenu == NULL) { + return NULL; + } + + ParentMenu = NULL; + Link = &CurrentMenu->Link; + + while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { + ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink); + + if (SettingLevel == FormLevel) { + // + // For FormLevel, just find the parent menu, return. + // + break; + } + + if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { + // + // For SystemLevel, must find the menu which has different formset. + // + break; + } + + Link = Link->BackLink; + } + + // + // Not find the parent menu, just return NULL. + // + if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { + return NULL; + } + + return ParentMenu; +} + +/** + Free Menu list linked list. + + @param MenuListHead One Menu list point in the menu list. + +**/ +VOID +UiFreeMenuList ( + LIST_ENTRY *MenuListHead + ) +{ + FORM_ENTRY_INFO *MenuList; + + while (!IsListEmpty (MenuListHead)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink); + RemoveEntryList (&MenuList->Link); + + FreePool (MenuList); + } +} + +/** + Copy current Menu list to the new menu list. + + @param NewMenuListHead New create Menu list. + @param CurrentMenuListHead Current Menu list. + +**/ +VOID +UiCopyMenuList ( + OUT LIST_ENTRY *NewMenuListHead, + IN LIST_ENTRY *CurrentMenuListHead + ) +{ + LIST_ENTRY *Link; + FORM_ENTRY_INFO *MenuList; + FORM_ENTRY_INFO *NewMenuEntry; + + // + // If new menu list not empty, free it first. + // + UiFreeMenuList (NewMenuListHead); + + Link = GetFirstNode (CurrentMenuListHead); + while (!IsNull (CurrentMenuListHead, Link)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); + Link = GetNextNode (CurrentMenuListHead, Link); + + NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); + ASSERT (NewMenuEntry != NULL); + NewMenuEntry->Signature = FORM_ENTRY_INFO_SIGNATURE; + NewMenuEntry->HiiHandle = MenuList->HiiHandle; + CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID)); + NewMenuEntry->FormId = MenuList->FormId; + NewMenuEntry->QuestionId = MenuList->QuestionId; + + InsertTailList (NewMenuListHead, &NewMenuEntry->Link); + } +} + +/** + Load all hii formset to the browser. + +**/ +VOID +LoadAllHiiFormset ( + VOID + ) +{ + FORM_BROWSER_FORMSET *LocalFormSet; + EFI_HII_HANDLE *HiiHandles; + UINTN Index; + EFI_GUID ZeroGuid; + EFI_STATUS Status; + FORM_BROWSER_FORMSET *OldFormset; + + OldFormset = mSystemLevelFormSet; + + // + // Get all the Hii handles + // + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); + + // + // Search for formset of each class type + // + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + // + // Check HiiHandles[Index] does exist in global maintain list. + // + if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) { + continue; + } + + // + // Initilize FormSet Setting + // + LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (LocalFormSet != NULL); + mSystemLevelFormSet = LocalFormSet; + + ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); + Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet); + if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) { + DestroyFormSet (LocalFormSet); + continue; + } + + InitializeCurrentSetting (LocalFormSet); + + // + // Initilize Questions' Value + // + Status = LoadFormSetConfig (NULL, LocalFormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (LocalFormSet); + continue; + } + } + + // + // Free resources, and restore gOldFormSet and gClassOfVfr + // + FreePool (HiiHandles); + + mSystemLevelFormSet = OldFormset; +} + +/** + Pop up the error info. + + @param BrowserStatus The input browser status. + @param HiiHandle The Hiihandle for this opcode. + @param OpCode The opcode use to get the erro info and timeout value. + @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF. + +**/ +UINT32 +PopupErrorMessage ( + IN UINT32 BrowserStatus, + IN EFI_HII_HANDLE HiiHandle, + IN EFI_IFR_OP_HEADER *OpCode OPTIONAL, + IN CHAR16 *ErrorString + ) +{ + FORM_DISPLAY_ENGINE_STATEMENT *Statement; + USER_INPUT UserInputData; + + Statement = NULL; + + if (OpCode != NULL) { + Statement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT)); + ASSERT (Statement != NULL); + Statement->OpCode = OpCode; + gDisplayFormData.HighLightedStatement = Statement; + } + + // + // Used to compatible with old display engine. + // New display engine not use this field. + // + gDisplayFormData.ErrorString = ErrorString; + gDisplayFormData.BrowserStatus = BrowserStatus; + + if (HiiHandle != NULL) { + gDisplayFormData.HiiHandle = HiiHandle; + } + + mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData); + + gDisplayFormData.BrowserStatus = BROWSER_SUCCESS; + gDisplayFormData.ErrorString = NULL; + + if (OpCode != NULL) { + FreePool (Statement); + } + + return UserInputData.Action; +} + +/** + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + + + @param This The Form Browser protocol instanse. + @param Handles A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + @param HandleCount The number of Handles specified in Handle. + @param FormSetGuid This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + @param FormId This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in + characters. + @param ActionRequest Points to the action recommended by the form. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_NOT_FOUND No valid forms could be found to display. + +**/ +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid OPTIONAL, + IN UINT16 FormId OPTIONAL, + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions OPTIONAL, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +{ + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + UINTN Index; + FORM_BROWSER_FORMSET *FormSet; + FORM_ENTRY_INFO *MenuList; + BOOLEAN RetVal; + + // + // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED. + // + if (mFormDisplay == NULL) { + DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!")); + return EFI_UNSUPPORTED; + } + + // + // Save globals used by SendForm() + // + SaveBrowserContext (); + + gFlagReconnect = FALSE; + gResetRequiredFormLevel = FALSE; + gExitRequired = FALSE; + gCallbackReconnect = FALSE; + Status = EFI_SUCCESS; + gEmptyString = L""; + gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *)ScreenDimensions; + + for (Index = 0; Index < HandleCount; Index++) { + Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); + ASSERT (Selection != NULL); + + Selection->Handle = Handles[Index]; + if (FormSetGuid != NULL) { + CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = FormId; + } else { + CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID)); + } + + do { + FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (FormSet != NULL); + + // + // Validate the HiiHandle + // if validate failed, find the first validate parent HiiHandle. + // + if (!ValidateHiiHandle (Selection->Handle)) { + FindNextMenu (Selection, FormSetLevel); + } + + // + // Initialize internal data structures of FormSet + // + Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); + if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) { + DestroyFormSet (FormSet); + break; + } + + Selection->FormSet = FormSet; + mSystemLevelFormSet = FormSet; + + // + // Display this formset + // + gCurrentSelection = Selection; + + Status = SetupBrowser (Selection); + + gCurrentSelection = NULL; + mSystemLevelFormSet = NULL; + + // + // Check incoming formset whether is same with previous. If yes, that means action is not exiting of formset so do not reconnect controller. + // + if ((gFlagReconnect || gCallbackReconnect) && !CompareGuid (&FormSet->Guid, &Selection->FormSetGuid)) { + RetVal = ReconnectController (FormSet->DriverHandle); + if (!RetVal) { + PopupErrorMessage (BROWSER_RECONNECT_FAIL, NULL, NULL, NULL); + } + + gFlagReconnect = FALSE; + gCallbackReconnect = FALSE; + } + + // + // If no data is changed, don't need to save current FormSet into the maintain list. + // + if (!IsNvUpdateRequiredForFormSet (FormSet)) { + CleanBrowserStorage (FormSet); + RemoveEntryList (&FormSet->Link); + DestroyFormSet (FormSet); + } + + if (EFI_ERROR (Status)) { + break; + } + } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); + + FreePool (Selection); + } + + if (ActionRequest != NULL) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + if (gResetRequiredFormLevel) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; + } + } + + mFormDisplay->ExitDisplay (); + + // + // Clear the menu history data. + // + while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); + RemoveEntryList (&MenuList->Link); + FreePool (MenuList); + } + + // + // Restore globals used by SendForm() + // + RestoreBrowserContext (); + + return Status; +} + +/** + Get or set data to the storage. + + @param ResultsDataSize The size of the buffer associatedwith ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param Storage The pointer to the storage. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + +**/ +EFI_STATUS +ProcessStorage ( + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING *ResultsData, + IN BOOLEAN RetrieveData, + IN BROWSER_STORAGE *Storage + ) +{ + CHAR16 *ConfigResp; + EFI_STATUS Status; + CHAR16 *StrPtr; + UINTN BufferSize; + UINTN TmpSize; + UINTN MaxLen; + FORMSET_STORAGE *BrowserStorage; + + if (RetrieveData) { + // + // Generate <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody. + // Also need to consider add "\0" at first time. + // + StrPtr = StrStr (ConfigResp, L"PATH"); + ASSERT (StrPtr != NULL); + StrPtr = StrStr (StrPtr, L"&"); + StrPtr += 1; + BufferSize = StrSize (StrPtr); + + // + // Copy the data if the input buffer is bigger enough. + // + if (*ResultsDataSize >= BufferSize) { + StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr); + } + + *ResultsDataSize = BufferSize; + FreePool (ConfigResp); + } else { + // + // Prepare <ConfigResp> + // + BrowserStorage = GetFstStgFromBrsStg (Storage); + ASSERT (BrowserStorage != NULL); + TmpSize = StrLen (*ResultsData); + BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16); + MaxLen = BufferSize / sizeof (CHAR16); + ConfigResp = AllocateZeroPool (BufferSize); + ASSERT (ConfigResp != NULL); + + StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr); + StrCatS (ConfigResp, MaxLen, L"&"); + StrCatS (ConfigResp, MaxLen, *ResultsData); + + // + // Update Browser uncommited data + // + Status = ConfigRespToStorage (Storage, ConfigResp); + FreePool (ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + This routine called this service in the browser to retrieve or set certain uncommitted + state information that resides in the open formsets. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid OPTIONAL, + IN CONST CHAR16 *VariableName OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormsetStorage; + UINTN TotalSize; + BOOLEAN Found; + + if ((ResultsDataSize == NULL) || (ResultsData == NULL)) { + return EFI_INVALID_PARAMETER; + } + + TotalSize = *ResultsDataSize; + Storage = NULL; + Found = FALSE; + Status = EFI_SUCCESS; + + if (VariableGuid != NULL) { + // + // Try to find target storage in the current formset. + // + Link = GetFirstNode (&gBrowserStorageList); + while (!IsNull (&gBrowserStorageList, Link)) { + Storage = BROWSER_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&gBrowserStorageList, Link); + // + // Check the current storage. + // + if (!CompareGuid (&Storage->Guid, (EFI_GUID *)VariableGuid)) { + continue; + } + + if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) + { + // + // Buffer storage require both GUID and Name + // + if (VariableName == NULL) { + return EFI_NOT_FOUND; + } + + if (StrCmp (Storage->Name, (CHAR16 *)VariableName) != 0) { + continue; + } + } + + if ((Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) || + (Storage->Type == EFI_HII_VARSTORE_BUFFER)) + { + if ((mSystemLevelFormSet == NULL) || (mSystemLevelFormSet->HiiHandle == NULL)) { + return EFI_NOT_FOUND; + } + + if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) { + continue; + } + } + + Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { + ConfigRequestAdjust (Storage, ResultsData, TRUE); + } + + // + // Different formsets may have same varstore, so here just set the flag + // not exit the circle. + // + Found = TRUE; + break; + } + + if (!Found) { + return EFI_NOT_FOUND; + } + } else { + // + // GUID/Name is not specified, take the first storage in FormSet + // + if (mSystemLevelFormSet == NULL) { + return EFI_NOT_READY; + } + + // + // Generate <ConfigResp> + // + Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead); + if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) { + return EFI_UNSUPPORTED; + } + + FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link); + + Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (RetrieveData) { + Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; + *ResultsDataSize = TotalSize; + } + + return Status; +} + +/** + Callback function for SimpleTextInEx protocol install events + + @param Event the event that is signaled. + @param Context not used here. + +**/ +VOID +EFIAPI +FormDisplayCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + if (mFormDisplay != NULL) { + return; + } + + gBS->LocateProtocol ( + &gEdkiiFormDisplayEngineProtocolGuid, + NULL, + (VOID **)&mFormDisplay + ); +} + +/** + Initialize Setup Browser driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS The Setup Browser module is initialized correctly.. + @return Other value if failed to initialize the Setup Browser module. + +**/ +EFI_STATUS +EFIAPI +InitializeSetup ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *Registration; + + // + // Locate required Hii relative protocols + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **)&mHiiDatabase + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **)&mHiiConfigRouting + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiDevicePathFromTextProtocolGuid, + NULL, + (VOID **)&mPathFromText + ); + + // + // Install FormBrowser2 protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiFormBrowser2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowser2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Install FormBrowserEx2 protocol + // + InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); + InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead); + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEdkiiFormBrowserEx2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowserEx2 + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEdkiiFormBrowserExProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowserEx + ); + ASSERT_EFI_ERROR (Status); + + InitializeDisplayFormData (); + + Status = gBS->LocateProtocol ( + &gEdkiiFormDisplayEngineProtocolGuid, + NULL, + (VOID **)&mFormDisplay + ); + + if (EFI_ERROR (Status)) { + EfiCreateProtocolNotifyEvent ( + &gEdkiiFormDisplayEngineProtocolGuid, + TPL_CALLBACK, + FormDisplayCallback, + NULL, + &Registration + ); + } + + return EFI_SUCCESS; +} + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING_ID StringId; + + StringId = HiiSetString (HiiHandle, 0, String, NULL); + ASSERT (StringId != 0); + + return StringId; +} + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 NullChar; + + NullChar = CHAR_NULL; + HiiSetString (HiiHandle, StringId, &NullChar, NULL); + return EFI_SUCCESS; +} + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING String; + + if (HiiHandle == NULL) { + return NULL; + } + + String = HiiGetString (HiiHandle, Token, NULL); + if (String == NULL) { + String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString); + ASSERT (String != NULL); + } + + return (CHAR16 *)String; +} + +/** + Allocate new memory and then copy the Unicode string Source to Destination. + + @param Dest Location to copy string + @param Src String to copy + +**/ +VOID +NewStringCpy ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + if (*Dest != NULL) { + FreePool (*Dest); + } + + *Dest = AllocateCopyPool (StrSize (Src), Src); + ASSERT (*Dest != NULL); +} + +/** + Allocate new memory and concatinate Source on the end of Destination. + + @param Dest String to added to the end of. + @param Src String to concatinate. + +**/ +VOID +NewStringCat ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + CHAR16 *NewString; + UINTN MaxLen; + + if (*Dest == NULL) { + NewStringCpy (Dest, Src); + return; + } + + MaxLen = (StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16); + NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (NewString != NULL); + + StrCpyS (NewString, MaxLen, *Dest); + StrCatS (NewString, MaxLen, Src); + + FreePool (*Dest); + *Dest = NewString; +} + +/** + Get Value for given Name from a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The retured Value. + @param GetValueFrom Where to get source value, from EditValue or Value. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +GetValueByName ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Name, + IN OUT CHAR16 **Value, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + if ((GetValueFrom != GetSetValueWithEditBuffer) && (GetValueFrom != GetSetValueWithBuffer)) { + return EFI_INVALID_PARAMETER; + } + + *Value = NULL; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + if (GetValueFrom == GetSetValueWithEditBuffer) { + NewStringCpy (Value, Node->EditValue); + } else { + NewStringCpy (Value, Node->Value); + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + +/** + Set Value of given Name in a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The Value to set. + @param SetValueTo Whether update editValue or Value. + @param ReturnNode The node use the input name. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +SetValueByName ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value, + IN GET_SET_QUESTION_VALUE_WITH SetValueTo, + OUT NAME_VALUE_NODE **ReturnNode + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + CHAR16 *Buffer; + + if ((SetValueTo != GetSetValueWithEditBuffer) && (SetValueTo != GetSetValueWithBuffer)) { + return EFI_INVALID_PARAMETER; + } + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + if (SetValueTo == GetSetValueWithEditBuffer) { + Buffer = Node->EditValue; + } else { + Buffer = Node->Value; + } + + if (Buffer != NULL) { + FreePool (Buffer); + } + + Buffer = AllocateCopyPool (StrSize (Value), Value); + ASSERT (Buffer != NULL); + if (SetValueTo == GetSetValueWithEditBuffer) { + Node->EditValue = Buffer; + } else { + Node->Value = Buffer; + } + + if (ReturnNode != NULL) { + *ReturnNode = Node; + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + +/** + Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>. + + @param Storage The Storage to be conveted. + @param ConfigResp The returned <ConfigResp>. + @param ConfigRequest The ConfigRequest string. + @param GetEditBuf Get the data from editbuffer or buffer. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 **ConfigResp, + IN CHAR16 *ConfigRequest, + IN BOOLEAN GetEditBuf + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + UINT8 *SourceBuf; + FORMSET_STORAGE *FormsetStorage; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer; + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + ConfigRequest, + SourceBuf, + Storage->Size, + ConfigResp, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + *ConfigResp = NULL; + FormsetStorage = GetFstStgFromBrsStg (Storage); + ASSERT (FormsetStorage != NULL); + NewStringCat (ConfigResp, FormsetStorage->ConfigHdr); + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrStr (ConfigRequest, Node->Name) != NULL) { + NewStringCat (ConfigResp, L"&"); + NewStringCat (ConfigResp, Node->Name); + NewStringCat (ConfigResp, L"="); + if (GetEditBuf) { + NewStringCat (ConfigResp, Node->EditValue); + } else { + NewStringCat (ConfigResp, Node->Value); + } + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + +/** + Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The <ConfigResp> to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + UINTN BufferSize; + CHAR16 *StrPtr; + CHAR16 *Name; + CHAR16 *Value; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + BufferSize = Storage->Size; + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + ConfigResp, + Storage->EditBuffer, + &BufferSize, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + StrPtr = StrStr (ConfigResp, L"PATH"); + if (StrPtr == NULL) { + break; + } + + StrPtr = StrStr (ConfigResp, L"&"); + while (StrPtr != NULL) { + // + // Skip '&' + // + StrPtr = StrPtr + 1; + Name = StrPtr; + StrPtr = StrStr (StrPtr, L"="); + if (StrPtr == NULL) { + break; + } + + *StrPtr = 0; + + // + // Skip '=' + // + StrPtr = StrPtr + 1; + Value = StrPtr; + StrPtr = StrStr (StrPtr, L"&"); + if (StrPtr != NULL) { + *StrPtr = 0; + } + + SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL); + } + + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + +/** + Get bit field value from the buffer and then set the value for the question. + Note: Data type UINT32 can cover all the bit field value. + + @param Question The question refer to bit field. + @param Buffer Point to the buffer which the question value get from. + +**/ +VOID +GetBitsQuestionValue ( + IN FORM_BROWSER_STATEMENT *Question, + IN UINT8 *Buffer + ) +{ + UINTN StartBit; + UINTN EndBit; + UINT32 RetVal; + UINT32 BufferValue; + + StartBit = Question->BitVarOffset % 8; + EndBit = StartBit + Question->BitStorageWidth - 1; + + CopyMem ((UINT8 *)&BufferValue, Buffer, Question->StorageWidth); + + RetVal = BitFieldRead32 (BufferValue, StartBit, EndBit); + + // + // Set question value. + // Note: Since Question with BufferValue (orderedlist, password, string)are not supported to refer bit field. + // Only oneof/checkbox/oneof can support bit field.So we can copy the value to the Hiivalue of Question directly. + // + CopyMem ((UINT8 *)&Question->HiiValue.Value, (UINT8 *)&RetVal, Question->StorageWidth); +} + +/** + Set bit field value to the buffer. + Note: Data type UINT32 can cover all the bit field value. + + @param Question The question refer to bit field. + @param Buffer Point to the buffer which the question value set to. + @param Value The bit field value need to set. + +**/ +VOID +SetBitsQuestionValue ( + IN FORM_BROWSER_STATEMENT *Question, + IN OUT UINT8 *Buffer, + IN UINT32 Value + ) +{ + UINT32 Operand; + UINTN StartBit; + UINTN EndBit; + UINT32 RetVal; + + StartBit = Question->BitVarOffset % 8; + EndBit = StartBit + Question->BitStorageWidth - 1; + + CopyMem ((UINT8 *)&Operand, Buffer, Question->StorageWidth); + + RetVal = BitFieldWrite32 (Operand, StartBit, EndBit, Value); + + CopyMem (Buffer, (UINT8 *)&RetVal, Question->StorageWidth); +} + +/** + Convert the buffer value to HiiValue. + + @param Question The question. + @param Value Unicode buffer save the question value. + + @retval Status whether convert the value success. + +**/ +EFI_STATUS +BufferToValue ( + IN OUT FORM_BROWSER_STATEMENT *Question, + IN CHAR16 *Value + ) +{ + CHAR16 *StringPtr; + BOOLEAN IsBufferStorage; + CHAR16 *DstBuf; + CHAR16 TempChar; + UINTN LengthStr; + UINT8 *Dst; + CHAR16 TemStr[5]; + UINTN Index; + UINT8 DigitUint8; + BOOLEAN IsString; + UINTN Length; + EFI_STATUS Status; + UINT8 *Buffer; + + Buffer = NULL; + + IsString = (BOOLEAN)((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if ((Question->Storage->Type == EFI_HII_VARSTORE_BUFFER) || + (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) + { + IsBufferStorage = TRUE; + } else { + IsBufferStorage = FALSE; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + // + // This Question is password or orderedlist + // + Dst = Question->BufferValue; + } else { + // + // Other type of Questions + // + if (Question->QuestionReferToBitField) { + Buffer = (UINT8 *)AllocateZeroPool (Question->StorageWidth); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Dst = Buffer; + } else { + Dst = (UINT8 *)&Question->HiiValue.Value; + } + } + + // + // Temp cut at the end of this section, end with '\0' or '&'. + // + StringPtr = Value; + while (*StringPtr != L'\0' && *StringPtr != L'&') { + StringPtr++; + } + + TempChar = *StringPtr; + *StringPtr = L'\0'; + + LengthStr = StrLen (Value); + + // + // Value points to a Unicode hexadecimal string, we need to convert the string to the value with CHAR16/UINT8...type. + // When generating the Value string, we follow this rule: 1 byte -> 2 Unicode characters (for string: 2 byte(CHAR16) ->4 Unicode characters). + // So the maximum value string length of a question is : Question->StorageWidth * 2. + // If the value string length > Question->StorageWidth * 2, only set the string length as Question->StorageWidth * 2, then convert. + // + if (LengthStr > (UINTN)Question->StorageWidth * 2) { + Length = (UINTN)Question->StorageWidth * 2; + } else { + Length = LengthStr; + } + + Status = EFI_SUCCESS; + if (!IsBufferStorage && IsString) { + // + // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" + // Add string tail char L'\0' into Length + // + DstBuf = (CHAR16 *)Dst; + ZeroMem (TemStr, sizeof (TemStr)); + for (Index = 0; Index < Length; Index += 4) { + StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4); + DstBuf[Index/4] = (CHAR16)StrHexToUint64 (TemStr); + } + + // + // Add tailing L'\0' character + // + DstBuf[Index/4] = L'\0'; + } else { + ZeroMem (TemStr, sizeof (TemStr)); + for (Index = 0; Index < Length; Index++) { + TemStr[0] = Value[LengthStr - Index - 1]; + DigitUint8 = (UINT8)StrHexToUint64 (TemStr); + if ((Index & 1) == 0) { + Dst[Index/2] = DigitUint8; + } else { + Dst[Index/2] = (UINT8)((DigitUint8 << 4) + Dst[Index/2]); + } + } + } + + *StringPtr = TempChar; + + if ((Buffer != NULL) && Question->QuestionReferToBitField) { + GetBitsQuestionValue (Question, Buffer); + FreePool (Buffer); + } + + return Status; +} + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Dst; + UINTN StorageWidth; + EFI_TIME EfiTime; + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormsetStorage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigRequest; + CHAR16 *Progress; + CHAR16 *Result; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + UINTN MaxLen; + + Status = EFI_SUCCESS; + Value = NULL; + Result = NULL; + + if (GetValueFrom >= GetSetValueWithMax) { + return EFI_INVALID_PARAMETER; + } + + // + // Question value is provided by an Expression, evaluate it + // + if (Question->ValueExpression != NULL) { + Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); + if (!EFI_ERROR (Status)) { + if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { + ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL); + if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) { + CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen); + Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen; + } else { + CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth); + Question->HiiValue.BufferLen = Question->StorageWidth; + } + + FreePool (Question->ValueExpression->Result.Buffer); + } + + Question->HiiValue.Type = Question->ValueExpression->Result.Type; + CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); + } + + return Status; + } + + // + // Get question value by read expression. + // + if ((Question->ReadExpression != NULL) && (Form->FormType == STANDARD_MAP_FORM_TYPE)) { + Status = EvaluateExpression (FormSet, Form, Question->ReadExpression); + if (!EFI_ERROR (Status) && + ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) + { + // + // Only update question value to the valid result. + // + if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { + ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL); + if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) { + CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen); + Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen; + } else { + CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth); + Question->HiiValue.BufferLen = Question->StorageWidth; + } + + FreePool (Question->ReadExpression->Result.Buffer); + } + + Question->HiiValue.Type = Question->ReadExpression->Result.Type; + CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); + return EFI_SUCCESS; + } + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + if (Question->Operand == EFI_IFR_DATE_OP) { + QuestionValue->date.Year = 0xff; + QuestionValue->date.Month = 0xff; + QuestionValue->date.Day = 0xff; + } else { + QuestionValue->time.Hour = 0xff; + QuestionValue->time.Minute = 0xff; + QuestionValue->time.Second = 0xff; + } + + return EFI_SUCCESS; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + QuestionValue->date.Year = EfiTime.Year; + QuestionValue->date.Month = EfiTime.Month; + QuestionValue->date.Day = EfiTime.Day; + } else { + QuestionValue->time.Hour = EfiTime.Hour; + QuestionValue->time.Minute = EfiTime.Minute; + QuestionValue->time.Second = EfiTime.Second; + } + } + + return EFI_SUCCESS; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Dst = Question->BufferValue; + } else { + Dst = (UINT8 *)QuestionValue; + } + + Status = gRT->GetVariable ( + Question->VariableName, + &Storage->Guid, + NULL, + &StorageWidth, + Dst + ); + // + // Always return success, even this EFI variable doesn't exist + // + return EFI_SUCCESS; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + // + // This Question is password or orderedlist + // + Dst = Question->BufferValue; + } else { + // + // Other type of Questions + // + Dst = (UINT8 *)&Question->HiiValue.Value; + } + + if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) + { + IsBufferStorage = TRUE; + } else { + IsBufferStorage = FALSE; + } + + if ((GetValueFrom == GetSetValueWithEditBuffer) || (GetValueFrom == GetSetValueWithBuffer)) { + if (IsBufferStorage) { + if (GetValueFrom == GetSetValueWithEditBuffer) { + // + // Copy from storage Edit buffer + // If the Question refer to bit filed, get the value in the related bit filed. + // + if (Question->QuestionReferToBitField) { + GetBitsQuestionValue (Question, Storage->EditBuffer + Question->VarStoreInfo.VarOffset); + } else { + CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); + } + } else { + // + // Copy from storage Edit buffer + // If the Question refer to bit filed, get the value in the related bit filed. + // + if (Question->QuestionReferToBitField) { + GetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset); + } else { + CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth); + } + } + } else { + Value = NULL; + Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (Value != NULL); + Status = BufferToValue (Question, Value); + FreePool (Value); + } + } else { + FormsetStorage = GetFstStgFromVarId (FormSet, Question->VarStoreId); + ASSERT (FormsetStorage != NULL); + // + // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || + // <ConfigHdr> + "&" + <VariableName> + // + if (IsBufferStorage) { + Length = StrLen (FormsetStorage->ConfigHdr); + Length += StrLen (Question->BlockName); + } else { + Length = StrLen (FormsetStorage->ConfigHdr); + Length += StrLen (Question->VariableName) + 1; + } + + // Allocate buffer include '\0' + MaxLen = Length + 1; + ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (ConfigRequest != NULL); + + StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr); + if (IsBufferStorage) { + StrCatS (ConfigRequest, MaxLen, Question->BlockName); + } else { + StrCatS (ConfigRequest, MaxLen, L"&"); + StrCatS (ConfigRequest, MaxLen, Question->VariableName); + } + + // + // Request current settings from Configuration Driver + // + Status = mHiiConfigRouting->ExtractConfig ( + mHiiConfigRouting, + ConfigRequest, + &Progress, + &Result + ); + FreePool (ConfigRequest); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigRequest> + // + if (IsBufferStorage) { + Value = StrStr (Result, L"&VALUE"); + if (Value == NULL) { + FreePool (Result); + return EFI_NOT_FOUND; + } + + // + // Skip "&VALUE" + // + Value = Value + 6; + } else { + Value = Result + Length; + } + + if (*Value != '=') { + FreePool (Result); + return EFI_NOT_FOUND; + } + + // + // Skip '=', point to value + // + Value = Value + 1; + + Status = BufferToValue (Question, Value); + if (EFI_ERROR (Status)) { + FreePool (Result); + return Status; + } + + // + // Synchronize Edit Buffer + // + if (IsBufferStorage) { + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); + } else { + SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL); + } + + if (Result != NULL) { + FreePool (Result); + } + } + + return Status; +} + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param SetValueTo Update the question value to editbuffer , buffer or hii driver. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH SetValueTo + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Src; + EFI_TIME EfiTime; + UINTN BufferLen; + UINTN StorageWidth; + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormsetStorage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + UINT8 *TemBuffer; + CHAR16 *TemName; + CHAR16 *TemString; + UINTN Index; + NAME_VALUE_NODE *Node; + UINTN MaxLen; + + Status = EFI_SUCCESS; + Node = NULL; + + if (SetValueTo >= GetSetValueWithMax) { + return EFI_INVALID_PARAMETER; + } + + // + // If Question value is provided by an Expression, then it is read only + // + if (Question->ValueExpression != NULL) { + return Status; + } + + // + // Before set question value, evaluate its write expression. + // + if ((Question->WriteExpression != NULL) && (Form->FormType == STANDARD_MAP_FORM_TYPE)) { + Status = EvaluateExpression (FormSet, Form, Question->WriteExpression); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + EfiTime.Year = QuestionValue->date.Year; + EfiTime.Month = QuestionValue->date.Month; + EfiTime.Day = QuestionValue->date.Day; + } else { + EfiTime.Hour = QuestionValue->time.Hour; + EfiTime.Minute = QuestionValue->time.Minute; + EfiTime.Second = QuestionValue->time.Second; + } + + if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { + Status = gRT->SetTime (&EfiTime); + } else { + Status = gRT->SetWakeupTime (TRUE, &EfiTime); + } + } + + return Status; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *)QuestionValue; + } + + Status = gRT->SetVariable ( + Question->VariableName, + &Storage->Guid, + Storage->Attributes, + StorageWidth, + Src + ); + return Status; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *)&Question->HiiValue.Value; + } + + if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) + { + IsBufferStorage = TRUE; + } else { + IsBufferStorage = FALSE; + } + + IsString = (BOOLEAN)((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + + if ((SetValueTo == GetSetValueWithEditBuffer) || (SetValueTo == GetSetValueWithBuffer)) { + if (IsBufferStorage) { + if (SetValueTo == GetSetValueWithEditBuffer) { + // + // Copy to storage edit buffer + // If the Question refer to bit filed, copy the value in related bit filed to storage edit buffer. + // + if (Question->QuestionReferToBitField) { + SetBitsQuestionValue (Question, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src)); + } else { + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } + } else if (SetValueTo == GetSetValueWithBuffer) { + // + // Copy to storage buffer + // If the Question refer to bit filed, copy the value in related bit filed to storage buffer. + // + if (Question->QuestionReferToBitField) { + SetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src)); + } else { + CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } + } + } else { + if (IsString) { + // + // Allocate enough string buffer. + // + Value = NULL; + BufferLen = ((StrLen ((CHAR16 *)Src) * 4) + 1) * sizeof (CHAR16); + Value = AllocateZeroPool (BufferLen); + ASSERT (Value != NULL); + // + // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" + // + TemName = (CHAR16 *)Src; + TemString = Value; + for ( ; *TemName != L'\0'; TemName++) { + UnicodeValueToStringS ( + TemString, + BufferLen - ((UINTN)TemString - (UINTN)Value), + PREFIX_ZERO | RADIX_HEX, + *TemName, + 4 + ); + TemString += StrnLenS (TemString, (BufferLen - ((UINTN)TemString - (UINTN)Value)) / sizeof (CHAR16)); + } + } else { + BufferLen = StorageWidth * 2 + 1; + Value = AllocateZeroPool (BufferLen * sizeof (CHAR16)); + ASSERT (Value != NULL); + // + // Convert Buffer to Hex String + // + TemBuffer = Src + StorageWidth - 1; + TemString = Value; + for (Index = 0; Index < StorageWidth; Index++, TemBuffer--) { + UnicodeValueToStringS ( + TemString, + BufferLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)Value), + PREFIX_ZERO | RADIX_HEX, + *TemBuffer, + 2 + ); + TemString += StrnLenS (TemString, BufferLen - ((UINTN)TemString - (UINTN)Value) / sizeof (CHAR16)); + } + } + + Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node); + FreePool (Value); + if (EFI_ERROR (Status)) { + return Status; + } + } + } else if (SetValueTo == GetSetValueWithHiiDriver) { + // + // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" || + // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>" + // + if (IsBufferStorage) { + Length = StrLen (Question->BlockName) + 7; + } else { + Length = StrLen (Question->VariableName) + 2; + } + + if (!IsBufferStorage && IsString) { + Length += (StrLen ((CHAR16 *)Src) * 4); + } else { + Length += (StorageWidth * 2); + } + + FormsetStorage = GetFstStgFromVarId (FormSet, Question->VarStoreId); + ASSERT (FormsetStorage != NULL); + MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1; + ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (ConfigResp != NULL); + + StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr); + if (IsBufferStorage) { + StrCatS (ConfigResp, MaxLen, Question->BlockName); + StrCatS (ConfigResp, MaxLen, L"&VALUE="); + } else { + StrCatS (ConfigResp, MaxLen, L"&"); + StrCatS (ConfigResp, MaxLen, Question->VariableName); + StrCatS (ConfigResp, MaxLen, L"="); + } + + Value = ConfigResp + StrLen (ConfigResp); + + if (!IsBufferStorage && IsString) { + // + // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" + // + TemName = (CHAR16 *)Src; + TemString = Value; + for ( ; *TemName != L'\0'; TemName++) { + UnicodeValueToStringS ( + TemString, + MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp), + PREFIX_ZERO | RADIX_HEX, + *TemName, + 4 + ); + TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16)); + } + } else { + // + // Convert Buffer to Hex String + // + TemBuffer = Src + StorageWidth - 1; + TemString = Value; + for (Index = 0; Index < StorageWidth; Index++, TemBuffer--) { + UnicodeValueToStringS ( + TemString, + MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp), + PREFIX_ZERO | RADIX_HEX, + *TemBuffer, + 2 + ); + TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16)); + } + } + + // + // Convert to lower char. + // + for (TemString = Value; *Value != L'\0'; Value++) { + if ((*Value >= L'A') && (*Value <= L'Z')) { + *Value = (CHAR16)(*Value - L'A' + L'a'); + } + } + + // + // Submit Question Value to Configuration Driver + // + Status = mHiiConfigRouting->RouteConfig ( + mHiiConfigRouting, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + FreePool (ConfigResp); + return Status; + } + + FreePool (ConfigResp); + + // + // Sync storage, from editbuffer to buffer. + // + CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } + + return Status; +} + +/** + Perform nosubmitif check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + LIST_ENTRY *ListHead; + FORM_EXPRESSION *Expression; + UINT32 BrowserStatus; + CHAR16 *ErrorStr; + + BrowserStatus = BROWSER_SUCCESS; + ErrorStr = NULL; + + switch (Type) { + case EFI_HII_EXPRESSION_INCONSISTENT_IF: + ListHead = &Question->InconsistentListHead; + break; + + case EFI_HII_EXPRESSION_WARNING_IF: + ListHead = &Question->WarningListHead; + break; + + case EFI_HII_EXPRESSION_NO_SUBMIT_IF: + ListHead = &Question->NoSubmitListHead; + break; + + default: + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Link = GetFirstNode (ListHead); + while (!IsNull (ListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + // + // Evaluate the expression + // + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsTrue (&Expression->Result)) { + switch (Type) { + case EFI_HII_EXPRESSION_INCONSISTENT_IF: + BrowserStatus = BROWSER_INCONSISTENT_IF; + break; + + case EFI_HII_EXPRESSION_WARNING_IF: + BrowserStatus = BROWSER_WARNING_IF; + break; + + case EFI_HII_EXPRESSION_NO_SUBMIT_IF: + BrowserStatus = BROWSER_NO_SUBMIT_IF; + // + // This code only used to compatible with old display engine, + // New display engine will not use this field. + // + if (Expression->Error != 0) { + ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle); + } + + break; + + default: + ASSERT (FALSE); + break; + } + + if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) { + // + // If in system submit process and for no_submit_if check, not popup this error message. + // Will process this fail again later in not system submit process. + // + PopupErrorMessage (BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr); + } + + if (ErrorStr != NULL) { + FreePool (ErrorStr); + } + + if (Type == EFI_HII_EXPRESSION_WARNING_IF) { + return EFI_SUCCESS; + } else { + return EFI_NOT_READY; + } + } + + Link = GetNextNode (ListHead, Link); + } + + return EFI_SUCCESS; +} + +/** + Perform question check. + + If one question has more than one check, process form high priority to low. + Only one error info will be popup. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValueChangedValidation ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + // + // Do the inconsistentif check. + // + if (!IsListEmpty (&Question->InconsistentListHead)) { + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Do the warningif check. + // + if (!IsListEmpty (&Question->WarningListHead)) { + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF); + } + + return Status; +} + +/** + Perform NoSubmit check for each Form in FormSet. + + @param FormSet FormSet data structure. + @param CurrentForm Current input form data structure. + @param Statement The statement for this check. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +NoSubmitCheck ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM **CurrentForm, + OUT FORM_BROWSER_STATEMENT **Statement + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + FORM_BROWSER_FORM *Form; + LIST_ENTRY *LinkForm; + + LinkForm = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, LinkForm)) { + Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm); + LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm); + + if ((*CurrentForm != NULL) && (*CurrentForm != Form)) { + continue; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); + if (EFI_ERROR (Status)) { + if (*CurrentForm == NULL) { + *CurrentForm = Form; + } + + if (Statement != NULL) { + *Statement = Question; + } + + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + } + + return EFI_SUCCESS; +} + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param Storage The storage which need to sync. + @param ConfigRequest The config request string which used to sync storage. + @param SyncOrRestore Sync the buffer to editbuffer or Restore the + editbuffer to buffer + if TRUE, copy the editbuffer to the buffer. + if FALSE, copy the buffer to the editbuffer. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SynchronizeStorage ( + OUT BROWSER_STORAGE *Storage, + IN CHAR16 *ConfigRequest, + IN BOOLEAN SyncOrRestore + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + UINTN BufferSize; + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + UINT8 *Src; + UINT8 *Dst; + + Status = EFI_SUCCESS; + Result = NULL; + + if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || + (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) + { + BufferSize = Storage->Size; + + if (SyncOrRestore) { + Src = Storage->EditBuffer; + Dst = Storage->Buffer; + } else { + Src = Storage->Buffer; + Dst = Storage->EditBuffer; + } + + if (ConfigRequest != NULL) { + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + ConfigRequest, + Src, + BufferSize, + &Result, + &Progress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + Result, + Dst, + &BufferSize, + &Progress + ); + if (Result != NULL) { + FreePool (Result); + } + } else { + CopyMem (Dst, Src, BufferSize); + } + } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (((ConfigRequest != NULL) && (StrStr (ConfigRequest, Node->Name) != NULL)) || + (ConfigRequest == NULL)) + { + if (SyncOrRestore) { + NewStringCpy (&Node->Value, Node->EditValue); + } else { + NewStringCpy (&Node->EditValue, Node->Value); + } + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + } + + return Status; +} + +/** + When discard the question value, call the callback function with Changed type + to inform the hii driver. + + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +SendDiscardInfoToDriver ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + EFI_IFR_TYPE_VALUE *TypeValue; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + + if (FormSet->ConfigAccess == NULL) { + return; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + if ((Question->Storage == NULL) || (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { + continue; + } + + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { + continue; + } + + if (Question->Operand == EFI_IFR_PASSWORD_OP) { + continue; + } + + if (!Question->ValueChanged) { + continue; + } + + // + // Restore the question value before call the CHANGED callback type. + // + GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + + if (Question->Operand == EFI_IFR_STRING_OP) { + HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16 *)Question->BufferValue, NULL); + } + + if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { + TypeValue = (EFI_IFR_TYPE_VALUE *)Question->BufferValue; + } else { + TypeValue = &Question->HiiValue.Value; + } + + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + FormSet->ConfigAccess->Callback ( + FormSet->ConfigAccess, + EFI_BROWSER_ACTION_CHANGED, + Question->QuestionId, + Question->HiiValue.Type, + TypeValue, + &ActionRequest + ); + } +} + +/** + When submit the question value, call the callback function with Submitted type + to inform the hii driver. + + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +SubmitCallbackForForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + EFI_IFR_TYPE_VALUE *TypeValue; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + + if (FormSet->ConfigAccess == NULL) { + return; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + if ((Question->Storage == NULL) || (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { + continue; + } + + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { + continue; + } + + if (Question->Operand == EFI_IFR_PASSWORD_OP) { + continue; + } + + if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { + TypeValue = (EFI_IFR_TYPE_VALUE *)Question->BufferValue; + } else { + TypeValue = &Question->HiiValue.Value; + } + + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + FormSet->ConfigAccess->Callback ( + FormSet->ConfigAccess, + EFI_BROWSER_ACTION_SUBMITTED, + Question->QuestionId, + Question->HiiValue.Type, + TypeValue, + &ActionRequest + ); + } +} + +/** + When value set Success, call the submit callback function. + + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +SubmitCallback ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_FORM *CurrentForm; + LIST_ENTRY *Link; + + if (Form != NULL) { + SubmitCallbackForForm (FormSet, Form); + return; + } + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + + SubmitCallbackForForm (FormSet, CurrentForm); + } +} + +/** + Validate the HiiHandle. + + @param HiiHandle The input HiiHandle which need to validate. + + @retval TRUE The handle is validate. + @retval FALSE The handle is invalidate. + +**/ +BOOLEAN +ValidateHiiHandle ( + EFI_HII_HANDLE HiiHandle + ) +{ + EFI_HII_HANDLE *HiiHandles; + UINTN Index; + BOOLEAN Find; + + if (HiiHandle == NULL) { + return FALSE; + } + + Find = FALSE; + + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); + + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + if (HiiHandles[Index] == HiiHandle) { + Find = TRUE; + break; + } + } + + FreePool (HiiHandles); + + return Find; +} + +/** + Validate the FormSet. If the formset is not validate, remove it from the list. + + @param FormSet The input FormSet which need to validate. + + @retval TRUE The handle is validate. + @retval FALSE The handle is invalidate. + +**/ +BOOLEAN +ValidateFormSet ( + FORM_BROWSER_FORMSET *FormSet + ) +{ + BOOLEAN Find; + + ASSERT (FormSet != NULL); + + Find = ValidateHiiHandle (FormSet->HiiHandle); + // + // Should not remove the formset which is being used. + // + if (!Find && (FormSet != gCurrentSelection->FormSet)) { + CleanBrowserStorage (FormSet); + RemoveEntryList (&FormSet->Link); + DestroyFormSet (FormSet); + } + + return Find; +} + +/** + Check whether need to enable the reset flag in form level. + Also clean all ValueChanged flag in question. + + @param SetFlag Whether need to set the Reset Flag. + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +UpdateFlagForForm ( + IN BOOLEAN SetFlag, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + BOOLEAN OldValue; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + if (!Question->ValueChanged) { + continue; + } + + OldValue = Question->ValueChanged; + + // + // Compare the buffer and editbuffer data to see whether the data has been saved. + // + Question->ValueChanged = IsQuestionValueChanged (FormSet, Form, Question, GetSetValueWithBothBuffer); + + // + // Only the changed data has been saved, then need to set the reset flag. + // + if (SetFlag && OldValue && !Question->ValueChanged) { + if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { + gResetRequiredFormLevel = TRUE; + gResetRequiredSystemLevel = TRUE; + } + + if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { + gFlagReconnect = TRUE; + } + } + } +} + +/** + Check whether need to enable the reset flag. + Also clean ValueChanged flag for all statements. + + Form level or formset level, only one. + + @param SetFlag Whether need to set the Reset Flag. + @param FormSet FormSet data structure. + @param Form Form data structure. + +**/ +VOID +ValueChangeResetFlagUpdate ( + IN BOOLEAN SetFlag, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_FORM *CurrentForm; + LIST_ENTRY *Link; + + if (Form != NULL) { + UpdateFlagForForm (SetFlag, FormSet, Form); + return; + } + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + + UpdateFlagForForm (SetFlag, FormSet, CurrentForm); + } +} + +/** + Base on the return Progress string to find the form. + + Base on the first return Offset/Width (Name) string to find the form + which keep this string. + + @param FormSet FormSet data structure. + @param Storage Storage which has this Progress string. + @param Progress The Progress string which has the first fail string. + @param RetForm The return form for this progress string. + @param RetQuestion The return question for the error progress string. + + @retval TRUE Find the error form and statement for this error progress string. + @retval FALSE Not find the error form. + +**/ +BOOLEAN +FindQuestionFromProgress ( + IN FORM_BROWSER_FORMSET *FormSet, + IN BROWSER_STORAGE *Storage, + IN EFI_STRING Progress, + OUT FORM_BROWSER_FORM **RetForm, + OUT FORM_BROWSER_STATEMENT **RetQuestion + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *LinkStorage; + LIST_ENTRY *LinkStatement; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + FORM_BROWSER_FORM *Form; + EFI_STRING EndStr; + FORM_BROWSER_STATEMENT *Statement; + + ASSERT ((*Progress == '&') || (*Progress == 'G')); + + ConfigInfo = NULL; + *RetForm = NULL; + *RetQuestion = NULL; + + // + // Skip the first "&" or the ConfigHdr part. + // + if (*Progress == '&') { + Progress++; + } else { + // + // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // For Name/Value type, Skip the ConfigHdr part. + // + EndStr = StrStr (Progress, L"PATH="); + ASSERT (EndStr != NULL); + while (*EndStr != '&') { + EndStr++; + } + + *EndStr = '\0'; + } else { + // + // For Buffer type, Skip the ConfigHdr part. + // + EndStr = StrStr (Progress, L"&OFFSET="); + ASSERT (EndStr != NULL); + *EndStr = '\0'; + } + + Progress = EndStr + 1; + } + + // + // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset, + // here, just keep the "Fred" string. + // + EndStr = StrStr (Progress, L"="); + ASSERT (EndStr != NULL); + *EndStr = '\0'; + } else { + // + // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####", + // here, just keep the "OFFSET=0x####&WIDTH=0x####" string. + // + EndStr = StrStr (Progress, L"&VALUE="); + ASSERT (EndStr != NULL); + *EndStr = '\0'; + } + + // + // Search in the form list. + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + + // + // Search in the ConfigReqeust list in this form. + // + LinkStorage = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage); + LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage); + + if (Storage != ConfigInfo->Storage) { + continue; + } + + if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) { + // + // Find the OffsetWidth string in this form. + // + *RetForm = Form; + break; + } + } + + if (*RetForm != NULL) { + LinkStatement = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, LinkStatement)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement); + LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement); + + if ((Statement->BlockName != NULL) && (StrStr (Statement->BlockName, Progress) != NULL)) { + *RetQuestion = Statement; + break; + } + + if ((Statement->VariableName != NULL) && (StrStr (Statement->VariableName, Progress) != NULL)) { + *RetQuestion = Statement; + break; + } + } + } + + if (*RetForm != NULL) { + break; + } + } + + // + // restore the OffsetWidth string to the original format. + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + *EndStr = '='; + } else { + *EndStr = '&'; + } + + return (BOOLEAN)(*RetForm != NULL); +} + +/** + Base on the return Progress string to get the SyncConfigRequest and RestoreConfigRequest + for form and formset. + + @param Storage Storage which has this Progress string. + @param ConfigRequest The ConfigRequest string. + @param Progress The Progress string which has the first fail string. + @param RestoreConfigRequest Return the RestoreConfigRequest string. + @param SyncConfigRequest Return the SyncConfigRequest string. + +**/ +VOID +GetSyncRestoreConfigRequest ( + IN BROWSER_STORAGE *Storage, + IN EFI_STRING ConfigRequest, + IN EFI_STRING Progress, + OUT EFI_STRING *RestoreConfigRequest, + OUT EFI_STRING *SyncConfigRequest + ) +{ + EFI_STRING EndStr; + EFI_STRING ConfigHdrEndStr; + EFI_STRING ElementStr; + UINTN TotalSize; + UINTN RestoreEleSize; + UINTN SyncSize; + + ASSERT ((*Progress == L'&') || (*Progress == L'G')); + // + // If the Progress starts with ConfigHdr, means the failure is in the first name / value pair. + // Need to restore all the fields in the ConfigRequest. + // + if (*Progress == L'G') { + *RestoreConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); + ASSERT (*RestoreConfigRequest != NULL); + return; + } + + // + // Find the first fail "NAME" or "OFFSET=0x####&WIDTH=0x####" string. + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset, + // here, just keep the "Fred" string. + // + EndStr = StrStr (Progress, L"="); + ASSERT (EndStr != NULL); + *EndStr = L'\0'; + // + // Find the ConfigHdr in ConfigRequest. + // + ConfigHdrEndStr = StrStr (ConfigRequest, L"PATH="); + ASSERT (ConfigHdrEndStr != NULL); + while (*ConfigHdrEndStr != L'&') { + ConfigHdrEndStr++; + } + } else { + // + // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####", + // here, just keep the "OFFSET=0x####&WIDTH=0x####" string. + // + EndStr = StrStr (Progress, L"&VALUE="); + ASSERT (EndStr != NULL); + *EndStr = L'\0'; + // + // Find the ConfigHdr in ConfigRequest. + // + ConfigHdrEndStr = StrStr (ConfigRequest, L"&OFFSET="); + } + + // + // Find the first fail pair in the ConfigRequest. + // + ElementStr = StrStr (ConfigRequest, Progress); + ASSERT (ElementStr != NULL); + // + // To get the RestoreConfigRequest. + // + RestoreEleSize = StrSize (ElementStr); + TotalSize = (ConfigHdrEndStr - ConfigRequest) * sizeof (CHAR16) + RestoreEleSize + sizeof (CHAR16); + *RestoreConfigRequest = AllocateZeroPool (TotalSize); + ASSERT (*RestoreConfigRequest != NULL); + StrnCpyS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ConfigRequest, ConfigHdrEndStr - ConfigRequest); + StrCatS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ElementStr); + // + // To get the SyncConfigRequest. + // + SyncSize = StrSize (ConfigRequest) - RestoreEleSize + sizeof (CHAR16); + *SyncConfigRequest = AllocateZeroPool (SyncSize); + ASSERT (*SyncConfigRequest != NULL); + StrnCpyS (*SyncConfigRequest, SyncSize / sizeof (CHAR16), ConfigRequest, SyncSize / sizeof (CHAR16) - 1); + + // + // restore the Progress string to the original format. + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + *EndStr = L'='; + } else { + *EndStr = L'&'; + } +} + +/** + Popup an save error info and get user input. + + @param TitleId The form title id. + @param HiiHandle The hii handle for this package. + + @retval UINT32 The user select option for the save fail. + BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET +**/ +UINT32 +ConfirmSaveFail ( + IN EFI_STRING_ID TitleId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 *FormTitle; + CHAR16 *StringBuffer; + UINT32 RetVal; + + FormTitle = GetToken (TitleId, HiiHandle); + + StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); + ASSERT (StringBuffer != NULL); + + UnicodeSPrint ( + StringBuffer, + 24 * sizeof (CHAR16) + StrSize (FormTitle), + L"Submit Fail For Form: %s.", + FormTitle + ); + + RetVal = PopupErrorMessage (BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer); + + FreePool (StringBuffer); + FreePool (FormTitle); + + return RetVal; +} + +/** + Popup an NO_SUBMIT_IF error info and get user input. + + @param TitleId The form title id. + @param HiiHandle The hii handle for this package. + + @retval UINT32 The user select option for the save fail. + BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET +**/ +UINT32 +ConfirmNoSubmitFail ( + IN EFI_STRING_ID TitleId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 *FormTitle; + CHAR16 *StringBuffer; + UINT32 RetVal; + + FormTitle = GetToken (TitleId, HiiHandle); + + StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); + ASSERT (StringBuffer != NULL); + + UnicodeSPrint ( + StringBuffer, + 24 * sizeof (CHAR16) + StrSize (FormTitle), + L"NO_SUBMIT_IF error For Form: %s.", + FormTitle + ); + + RetVal = PopupErrorMessage (BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer); + + FreePool (StringBuffer); + FreePool (FormTitle); + + return RetVal; +} + +/** + Discard data based on the input setting scope (Form, FormSet or System). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param SettingScope Setting Scope for Discard action. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +DiscardForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN BROWSER_SETTING_SCOPE SettingScope + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + FORM_BROWSER_FORMSET *LocalFormSet; + FORM_BROWSER_FORMSET *OldFormSet; + + // + // Check the supported setting level. + // + if (SettingScope >= MaxLevel) { + return EFI_UNSUPPORTED; + } + + if ((SettingScope == FormLevel) && IsNvUpdateRequiredForForm (Form)) { + ConfigInfo = NULL; + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + Link = GetNextNode (&Form->ConfigRequestHead, Link); + + if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (ConfigInfo->ElementCount == 0) { + continue; + } + + // + // Prepare <ConfigResp> + // + SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); + + // + // Call callback with Changed type to inform the driver. + // + SendDiscardInfoToDriver (FormSet, Form); + } + + ValueChangeResetFlagUpdate (FALSE, FormSet, Form); + } else if ((SettingScope == FormSetLevel) && IsNvUpdateRequiredForFormSet (FormSet)) { + // + // Discard Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + continue; + } + + SynchronizeStorage (Storage->BrowserStorage, Storage->ConfigRequest, FALSE); + } + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + + // + // Call callback with Changed type to inform the driver. + // + SendDiscardInfoToDriver (FormSet, Form); + } + + ValueChangeResetFlagUpdate (FALSE, FormSet, NULL); + } else if (SettingScope == SystemLevel) { + // + // System Level Discard. + // + OldFormSet = mSystemLevelFormSet; + + // + // Discard changed value for each FormSet in the maintain list. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!ValidateFormSet (LocalFormSet)) { + continue; + } + + mSystemLevelFormSet = LocalFormSet; + + DiscardForm (LocalFormSet, NULL, FormSetLevel); + if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { + // + // Remove maintain backup list after discard except for the current using FormSet. + // + CleanBrowserStorage (LocalFormSet); + RemoveEntryList (&LocalFormSet->Link); + DestroyFormSet (LocalFormSet); + } + } + + mSystemLevelFormSet = OldFormSet; + } + + return EFI_SUCCESS; +} + +/** + Submit data for a form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +SubmitForForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_STRING ConfigResp; + EFI_STRING Progress; + BROWSER_STORAGE *Storage; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + BOOLEAN SubmitFormFail; + + SubmitFormFail = FALSE; + + if (!IsNvUpdateRequiredForForm (Form)) { + return EFI_SUCCESS; + } + + Status = NoSubmitCheck (FormSet, &Form, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + Link = GetNextNode (&Form->ConfigRequestHead, Link); + + Storage = ConfigInfo->Storage; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (ConfigInfo->ElementCount == 0) { + continue; + } + + // + // 1. Prepare <ConfigResp> + // + Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 2. Set value to hii config routine protocol. + // + Status = mHiiConfigRouting->RouteConfig ( + mHiiConfigRouting, + ConfigResp, + &Progress + ); + + if (EFI_ERROR (Status)) { + // + // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest. + // + SubmitFormFail = TRUE; + GetSyncRestoreConfigRequest (ConfigInfo->Storage, ConfigInfo->ConfigRequest, Progress, &ConfigInfo->RestoreConfigRequest, &ConfigInfo->SyncConfigRequest); + InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink); + FreePool (ConfigResp); + continue; + } + + FreePool (ConfigResp); + // + // 3. Config success, update storage shadow Buffer, only update the data belong to this form. + // + SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE); + } + + // + // 4. Process the save failed storage. + // + if (!IsListEmpty (&gBrowserSaveFailFormSetList)) { + if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { + Link = GetFirstNode (&gBrowserSaveFailFormSetList); + while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); + Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); + // + // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer + // base on the SyncConfigRequest to Sync the buffer. + // + SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->RestoreConfigRequest, FALSE); + FreePool (ConfigInfo->RestoreConfigRequest); + ConfigInfo->RestoreConfigRequest = NULL; + if (ConfigInfo->SyncConfigRequest != NULL) { + SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->SyncConfigRequest, TRUE); + FreePool (ConfigInfo->SyncConfigRequest); + ConfigInfo->SyncConfigRequest = NULL; + } + + Status = EFI_SUCCESS; + } + + SendDiscardInfoToDriver (FormSet, Form); + } else { + Status = EFI_UNSUPPORTED; + } + + // + // Free Form save fail list. + // + while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { + Link = GetFirstNode (&gBrowserSaveFailFormSetList); + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); + RemoveEntryList (&ConfigInfo->SaveFailLink); + } + } + + // + // 5. Update the NV flag. + // + ValueChangeResetFlagUpdate (TRUE, FormSet, Form); + + // + // 6 Call callback with Submitted type to inform the driver. + // + if (!SubmitFormFail) { + SubmitCallback (FormSet, Form); + } + + return Status; +} + +/** + Submit data for a formset. + + @param FormSet FormSet data structure. + @param SkipProcessFail Whether skip to process the save failed storage. + If submit formset is called when do system level save, + set this value to true and process the failed formset + together. + if submit formset is called when do formset level save, + set the value to false and process the failed storage + right after process all storages for this formset. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +SubmitForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet, + IN BOOLEAN SkipProcessFail + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_STRING ConfigResp; + EFI_STRING Progress; + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormSetStorage; + FORM_BROWSER_FORM *Form; + BOOLEAN HasInserted; + FORM_BROWSER_STATEMENT *Question; + BOOLEAN SubmitFormSetFail; + BOOLEAN DiscardChange; + + HasInserted = FALSE; + SubmitFormSetFail = FALSE; + DiscardChange = FALSE; + + if (!IsNvUpdateRequiredForFormSet (FormSet)) { + return EFI_SUCCESS; + } + + Form = NULL; + Status = NoSubmitCheck (FormSet, &Form, &Question); + if (EFI_ERROR (Status)) { + if (SkipProcessFail) { + // + // Process NO_SUBMIT check first, so insert it at head. + // + FormSet->SaveFailForm = Form; + FormSet->SaveFailStatement = Question; + InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); + } + + return Status; + } + + Form = NULL; + Question = NULL; + // + // Submit Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); + Storage = FormSetStorage->BrowserStorage; + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (FormSetStorage->ElementCount == 0) { + continue; + } + + // + // 1. Prepare <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 2. Send <ConfigResp> to Routine config Protocol. + // + Status = mHiiConfigRouting->RouteConfig ( + mHiiConfigRouting, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + // + // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest. + // + SubmitFormSetFail = TRUE; + GetSyncRestoreConfigRequest (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, Progress, &FormSetStorage->RestoreConfigRequest, &FormSetStorage->SyncConfigRequest); + InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink); + if (!HasInserted) { + // + // Call submit formset for system level, save the formset info + // and process later. + // + FindQuestionFromProgress (FormSet, Storage, Progress, &Form, &Question); + ASSERT (Form != NULL && Question != NULL); + FormSet->SaveFailForm = Form; + FormSet->SaveFailStatement = Question; + if (SkipProcessFail) { + InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); + } + + HasInserted = TRUE; + } + + FreePool (ConfigResp); + continue; + } + + FreePool (ConfigResp); + // + // 3. Config success, update storage shadow Buffer + // + SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE); + } + + // + // 4. Has save fail storage need to handle. + // + if (Form != NULL) { + if (!SkipProcessFail) { + // + // If not in system level, just handl the save failed storage here. + // + if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { + DiscardChange = TRUE; + Link = GetFirstNode (&FormSet->SaveFailStorageListHead); + while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) { + FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); + Storage = FormSetStorage->BrowserStorage; + Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link); + // + // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer + // base on the SyncConfigRequest to Sync the buffer. + // + SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE); + FreePool (FormSetStorage->RestoreConfigRequest); + FormSetStorage->RestoreConfigRequest = NULL; + if (FormSetStorage->SyncConfigRequest != NULL) { + SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE); + FreePool (FormSetStorage->SyncConfigRequest); + FormSetStorage->SyncConfigRequest = NULL; + } + + Status = EFI_SUCCESS; + } + } else { + UiCopyMenuList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); + + gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; + gCurrentSelection->Handle = FormSet->HiiHandle; + CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid); + gCurrentSelection->FormId = Form->FormId; + gCurrentSelection->QuestionId = Question->QuestionId; + + Status = EFI_UNSUPPORTED; + } + + // + // Free FormSet save fail list. + // + while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) { + Link = GetFirstNode (&FormSet->SaveFailStorageListHead); + FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); + RemoveEntryList (&FormSetStorage->SaveFailLink); + } + } else { + // + // If in system level, just return error and handle the failed formset later. + // + Status = EFI_UNSUPPORTED; + } + } + + // + // If user discard the change, send the discard info to driver. + // + if (DiscardChange) { + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&FormSet->FormListHead, Link); + // + // Call callback with Changed type to inform the driver. + // + SendDiscardInfoToDriver (FormSet, Form); + } + } + + // + // 5. Update the NV flag. + // + ValueChangeResetFlagUpdate (TRUE, FormSet, NULL); + + // + // 6. Call callback with Submitted type to inform the driver. + // + if (!SubmitFormSetFail) { + SubmitCallback (FormSet, NULL); + } + + return Status; +} + +/** + Submit data for all formsets. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +SubmitForSystem ( + VOID + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + LIST_ENTRY *FormLink; + LIST_ENTRY *StorageLink; + FORMSET_STORAGE *FormSetStorage; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_FORMSET *LocalFormSet; + UINT32 UserSelection; + FORM_BROWSER_STATEMENT *Question; + + mSystemSubmit = TRUE; + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!ValidateFormSet (LocalFormSet)) { + continue; + } + + Status = SubmitForFormSet (LocalFormSet, TRUE); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Remove maintain backup list after save except for the current using FormSet. + // + if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { + CleanBrowserStorage (LocalFormSet); + RemoveEntryList (&LocalFormSet->Link); + DestroyFormSet (LocalFormSet); + } + } + + mSystemSubmit = FALSE; + + Status = EFI_SUCCESS; + + // + // Process the save failed formsets. + // + Link = GetFirstNode (&gBrowserSaveFailFormSetList); + while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); + Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); + + if (!ValidateFormSet (LocalFormSet)) { + continue; + } + + Form = LocalFormSet->SaveFailForm; + Question = LocalFormSet->SaveFailStatement; + + // + // Confirm with user, get user input. + // + if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { + // + // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check. + // + UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle); + } else { + UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle); + } + + if (UserSelection == BROWSER_ACTION_DISCARD) { + if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { + StorageLink = GetFirstNode (&LocalFormSet->StorageListHead); + while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) { + FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink); + StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink); + + SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); + } + } else { + StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); + while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) { + FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); + StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink); + // + // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer + // base on the SyncConfigRequest to Sync the buffer. + // + SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE); + FreePool (FormSetStorage->RestoreConfigRequest); + FormSetStorage->RestoreConfigRequest = NULL; + if ( FormSetStorage->SyncConfigRequest != NULL) { + SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE); + FreePool (FormSetStorage->SyncConfigRequest); + FormSetStorage->SyncConfigRequest = NULL; + } + } + } + + FormLink = GetFirstNode (&LocalFormSet->FormListHead); + while (!IsNull (&LocalFormSet->FormListHead, FormLink)) { + Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); + FormLink = GetNextNode (&LocalFormSet->FormListHead, FormLink); + // + // Call callback with Changed type to inform the driver. + // + SendDiscardInfoToDriver (LocalFormSet, Form); + } + + if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { + CleanBrowserStorage (LocalFormSet); + RemoveEntryList (&LocalFormSet->Link); + RemoveEntryList (&LocalFormSet->SaveFailLink); + DestroyFormSet (LocalFormSet); + } else { + ValueChangeResetFlagUpdate (FALSE, LocalFormSet, NULL); + } + } else { + if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { + NoSubmitCheck (LocalFormSet, &Form, &Question); + } + + UiCopyMenuList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); + + gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; + gCurrentSelection->Handle = LocalFormSet->HiiHandle; + CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid); + gCurrentSelection->FormId = Form->FormId; + gCurrentSelection->QuestionId = Question->QuestionId; + + Status = EFI_UNSUPPORTED; + break; + } + } + + // + // Clean the list which will not process. + // + while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { + Link = GetFirstNode (&gBrowserSaveFailFormSetList); + LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); + RemoveEntryList (&LocalFormSet->SaveFailLink); + + while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { + StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); + FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); + RemoveEntryList (&FormSetStorage->SaveFailLink); + } + } + + return Status; +} + +/** + Submit data based on the input Setting level (Form, FormSet or System). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param SettingScope Setting Scope for Submit action. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN BROWSER_SETTING_SCOPE SettingScope + ) +{ + EFI_STATUS Status; + + switch (SettingScope) { + case FormLevel: + Status = SubmitForForm (FormSet, Form); + break; + + case FormSetLevel: + Status = SubmitForFormSet (FormSet, FALSE); + break; + + case SystemLevel: + Status = SubmitForSystem (); + break; + + default: + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +EFIAPI +HiiToLower ( + IN EFI_STRING ConfigString + ) +{ + EFI_STRING String; + BOOLEAN Lower; + + ASSERT (ConfigString != NULL); + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { + if (*String == L'=') { + Lower = TRUE; + } else if (*String == L'&') { + Lower = FALSE; + } else if (Lower && (*String >= L'A') && (*String <= L'F')) { + *String = (CHAR16)(*String - L'A' + L'a'); + } + } +} + +/** + Find the point in the ConfigResp string for this question. + + @param Question The question. + @param ConfigResp Get ConfigResp string. + + @retval point to the offset where is for this question. + +**/ +CHAR16 * +GetOffsetFromConfigResp ( + IN FORM_BROWSER_STATEMENT *Question, + IN CHAR16 *ConfigResp + ) +{ + CHAR16 *RequestElement; + CHAR16 *BlockData; + + // + // Type is EFI_HII_VARSTORE_NAME_VALUE. + // + if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + RequestElement = StrStr (ConfigResp, Question->VariableName); + if (RequestElement != NULL) { + // + // Skip the "VariableName=" field. + // + RequestElement += StrLen (Question->VariableName) + 1; + } + + return RequestElement; + } + + // + // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER + // + + // + // Convert all hex digits in ConfigResp to lower case before searching. + // + HiiToLower (ConfigResp); + + // + // 1. Directly use Question->BlockName to find. + // + RequestElement = StrStr (ConfigResp, Question->BlockName); + if (RequestElement != NULL) { + // + // Skip the "Question->BlockName&VALUE=" field. + // + RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); + return RequestElement; + } + + // + // 2. Change all hex digits in Question->BlockName to lower and compare again. + // + BlockData = AllocateCopyPool (StrSize (Question->BlockName), Question->BlockName); + ASSERT (BlockData != NULL); + HiiToLower (BlockData); + RequestElement = StrStr (ConfigResp, BlockData); + FreePool (BlockData); + + if (RequestElement != NULL) { + // + // Skip the "Question->BlockName&VALUE=" field. + // + RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); + } + + return RequestElement; +} + +/** + Get Question default value from AltCfg string. + + @param FormSet The form set. + @param Form The form + @param Question The question. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetDefaultValueFromAltCfg ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question + ) +{ + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormSetStorage; + CHAR16 *ConfigResp; + CHAR16 *Value; + LIST_ENTRY *Link; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + + Storage = Question->Storage; + if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { + return EFI_NOT_FOUND; + } + + // + // Try to get AltCfg string from form. If not found it, then + // try to get it from formset. + // + ConfigResp = NULL; + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + Link = GetNextNode (&Form->ConfigRequestHead, Link); + + if (Storage == ConfigInfo->Storage) { + ConfigResp = ConfigInfo->ConfigAltResp; + break; + } + } + + if (ConfigResp == NULL) { + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage == FormSetStorage->BrowserStorage) { + ConfigResp = FormSetStorage->ConfigAltResp; + break; + } + } + } + + if (ConfigResp == NULL) { + return EFI_NOT_FOUND; + } + + Value = GetOffsetFromConfigResp (Question, ConfigResp); + if (Value == NULL) { + return EFI_NOT_FOUND; + } + + return BufferToValue (Question, Value); +} + +/** + Get default Id value used for browser. + + @param DefaultId The default id value used by hii. + + @retval Browser used default value. + +**/ +INTN +GetDefaultIdForCallBack ( + UINTN DefaultId + ) +{ + if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) { + return EFI_BROWSER_ACTION_DEFAULT_STANDARD; + } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING; + } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) { + return EFI_BROWSER_ACTION_DEFAULT_SAFE; + } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000)) { + return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN; + } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000)) { + return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN; + } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000)) { + return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN; + } else { + return -1; + } +} + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ) +{ + UINT64 Data; + + ASSERT (Array != NULL); + + Data = 0; + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data = (UINT64)*(((UINT8 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Data = (UINT64)*(((UINT16 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Data = (UINT64)*(((UINT32 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Data = (UINT64)*(((UINT64 *)Array) + Index); + break; + + default: + break; + } + + return Data; +} + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ) +{ + ASSERT (Array != NULL); + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + *(((UINT8 *)Array) + Index) = (UINT8)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + *(((UINT16 *)Array) + Index) = (UINT16)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + *(((UINT32 *)Array) + Index) = (UINT32)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + *(((UINT64 *)Array) + Index) = (UINT64)Value; + break; + + default: + break; + } +} + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +{ + LIST_ENTRY *Link; + QUESTION_OPTION *Option; + INTN Result; + + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + // + // Check the suppressif condition, only a valid option can be return. + // + if ((Option->SuppressExpression == NULL) || + ((EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) + { + return Option; + } + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + return NULL; +} + +/** + Reset Question to its default value. + + @param FormSet The form set. + @param Form The form. + @param Question The question. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + EFI_HII_VALUE *HiiValue; + UINT8 Index; + EFI_STRING StrValue; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + INTN Action; + CHAR16 *NewString; + EFI_IFR_TYPE_VALUE *TypeValue; + UINT16 OriginalDefaultId; + FORMSET_DEFAULTSTORE *DefaultStore; + LIST_ENTRY *DefaultLink; + + Status = EFI_NOT_FOUND; + StrValue = NULL; + OriginalDefaultId = DefaultId; + DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead); + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // There are Five ways to specify default value for a Question: + // 1, use call back function (highest priority) + // 2, use ExtractConfig function + // 3, use nested EFI_IFR_DEFAULT + // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) + // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) + // +ReGetDefault: + HiiValue = &Question->HiiValue; + TypeValue = &HiiValue->Value; + if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { + // + // For orderedlist, need to pass the BufferValue to Callback function. + // + TypeValue = (EFI_IFR_TYPE_VALUE *)Question->BufferValue; + } + + // + // Get Question defaut value from call back function. + // + ConfigAccess = FormSet->ConfigAccess; + Action = GetDefaultIdForCallBack (DefaultId); + if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) { + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + Status = ConfigAccess->Callback ( + ConfigAccess, + Action, + Question->QuestionId, + HiiValue->Type, + TypeValue, + &ActionRequest + ); + if (!EFI_ERROR (Status)) { + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle); + ASSERT (NewString != NULL); + + ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth); + if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) { + ZeroMem (Question->BufferValue, Question->StorageWidth); + CopyMem (Question->BufferValue, NewString, StrSize (NewString)); + } else { + CopyMem (Question->BufferValue, NewString, Question->StorageWidth); + } + + FreePool (NewString); + } + + return Status; + } + } + + // + // Get default value from altcfg string. + // + if (ConfigAccess != NULL) { + Status = GetDefaultValueFromAltCfg (FormSet, Form, Question); + if (!EFI_ERROR (Status)) { + return Status; + } + } + + // + // EFI_IFR_DEFAULT has highest priority + // + if (!IsListEmpty (&Question->DefaultListHead)) { + Link = GetFirstNode (&Question->DefaultListHead); + while (!IsNull (&Question->DefaultListHead, Link)) { + Default = QUESTION_DEFAULT_FROM_LINK (Link); + + if (Default->DefaultId == DefaultId) { + if (Default->ValueExpression != NULL) { + // + // Default is provided by an Expression, evaluate it + // + Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { + ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL); + if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) { + CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen); + Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen; + } else { + CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth); + Question->HiiValue.BufferLen = Question->StorageWidth; + } + + FreePool (Default->ValueExpression->Result.Buffer); + } + + HiiValue->Type = Default->ValueExpression->Result.Type; + CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); + } else { + // + // Default value is embedded in EFI_IFR_DEFAULT + // + if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) { + ASSERT (HiiValue->Buffer != NULL); + CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen); + } else { + CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); + } + } + + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL); + if (StrValue == NULL) { + return EFI_NOT_FOUND; + } + + if (Question->StorageWidth > StrSize (StrValue)) { + ZeroMem (Question->BufferValue, Question->StorageWidth); + CopyMem (Question->BufferValue, StrValue, StrSize (StrValue)); + } else { + CopyMem (Question->BufferValue, StrValue, Question->StorageWidth); + } + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->DefaultListHead, Link); + } + } + + // + // EFI_ONE_OF_OPTION + // + if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // OneOfOption could only provide Standard and Manufacturing default + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + if ((Option->SuppressExpression != NULL) && + (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse)) + { + continue; + } + + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0)) + ) + { + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; + } + } + } + } + + // + // EFI_IFR_CHECKBOX - lowest priority + // + if (Question->Operand == EFI_IFR_CHECKBOX_OP) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // Checkbox could only provide Standard and Manufacturing default + // + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0)) + ) + { + HiiValue->Value.b = TRUE; + } + + return EFI_SUCCESS; + } + } + + // + // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList. + // If get, will exit the function, if not, will choose next default id in the DefaultStoreList. + // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time. + // + while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) { + DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultLink); + DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink); + DefaultId = DefaultStore->DefaultId; + if (DefaultId == OriginalDefaultId) { + continue; + } + + goto ReGetDefault; + } + + // + // For Questions without default value for all the default id in the DefaultStoreList. + // + Status = EFI_NOT_FOUND; + switch (Question->Operand) { + case EFI_IFR_CHECKBOX_OP: + HiiValue->Value.b = FALSE; + Status = EFI_SUCCESS; + break; + + case EFI_IFR_NUMERIC_OP: + // + // Take minimum value as numeric default value + // + if ((Question->Flags & EFI_IFR_DISPLAY) == 0) { + // + // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type. + // + switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + if (((INT8)HiiValue->Value.u8 < (INT8)Question->Minimum) || ((INT8)HiiValue->Value.u8 > (INT8)Question->Maximum)) { + HiiValue->Value.u8 = (UINT8)Question->Minimum; + Status = EFI_SUCCESS; + } + + break; + case EFI_IFR_NUMERIC_SIZE_2: + if (((INT16)HiiValue->Value.u16 < (INT16)Question->Minimum) || ((INT16)HiiValue->Value.u16 > (INT16)Question->Maximum)) { + HiiValue->Value.u16 = (UINT16)Question->Minimum; + Status = EFI_SUCCESS; + } + + break; + case EFI_IFR_NUMERIC_SIZE_4: + if (((INT32)HiiValue->Value.u32 < (INT32)Question->Minimum) || ((INT32)HiiValue->Value.u32 > (INT32)Question->Maximum)) { + HiiValue->Value.u32 = (UINT32)Question->Minimum; + Status = EFI_SUCCESS; + } + + break; + case EFI_IFR_NUMERIC_SIZE_8: + if (((INT64)HiiValue->Value.u64 < (INT64)Question->Minimum) || ((INT64)HiiValue->Value.u64 > (INT64)Question->Maximum)) { + HiiValue->Value.u64 = Question->Minimum; + Status = EFI_SUCCESS; + } + + break; + default: + break; + } + } else { + if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) { + HiiValue->Value.u64 = Question->Minimum; + Status = EFI_SUCCESS; + } + } + + break; + + case EFI_IFR_ONE_OF_OP: + // + // Take first oneof option as oneof's default value + // + if (ValueToOption (Question, HiiValue) == NULL) { + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + if ((Option->SuppressExpression != NULL) && + (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse)) + { + continue; + } + + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + Status = EFI_SUCCESS; + break; + } + } + + break; + + case EFI_IFR_ORDERED_LIST_OP: + // + // Take option sequence in IFR as ordered list's default value + // + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Status = EFI_SUCCESS; + Option = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + if ((Option->SuppressExpression != NULL) && + (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse)) + { + continue; + } + + SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64); + + Index++; + if (Index >= Question->MaxContainers) { + break; + } + } + + break; + + default: + break; + } + + return Status; +} + +/** + Get AltCfg string for current form. + + @param FormSet Form data structure. + @param Form Form data structure. + @param DefaultId The Class of the default. + @param BrowserStorage The input request storage for the questions. + +**/ +VOID +ExtractAltCfgForForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId, + IN BROWSER_STORAGE *BrowserStorage + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Result; + BROWSER_STORAGE *Storage; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + FORMSET_STORAGE *FormSetStorage; + + // + // Check whether has get AltCfg string for this formset. + // If yes, no need to get AltCfg for form. + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); + Storage = FormSetStorage->BrowserStorage; + Link = GetNextNode (&FormSet->StorageListHead, Link); + if ((BrowserStorage != NULL) && (BrowserStorage != Storage)) { + continue; + } + + if ((Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE) && + (FormSetStorage->ElementCount != 0) && + FormSetStorage->HasCallAltCfg) + { + return; + } + } + + // + // Get AltCfg string for each form. + // + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + Link = GetNextNode (&Form->ConfigRequestHead, Link); + + Storage = ConfigInfo->Storage; + if ((BrowserStorage != NULL) && (BrowserStorage != Storage)) { + continue; + } + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // 1. Skip if there is no RequestElement + // + if (ConfigInfo->ElementCount == 0) { + continue; + } + + // + // 2. Get value through hii config routine protocol. + // + Status = mHiiConfigRouting->ExtractConfig ( + mHiiConfigRouting, + ConfigInfo->ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp) + // Get the default configuration string according to the default ID. + // + Status = mHiiConfigRouting->GetAltConfig ( + mHiiConfigRouting, + Result, + &Storage->Guid, + Storage->Name, + NULL, + &DefaultId, // it can be NULL to get the current setting. + &ConfigResp + ); + FreePool (Result); + if (EFI_ERROR (Status)) { + continue; + } + + ConfigInfo->ConfigAltResp = ConfigResp; + } +} + +/** + Clean AltCfg string for current form. + + @param Form Form data structure. + +**/ +VOID +CleanAltCfgForForm ( + IN FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + Link = GetNextNode (&Form->ConfigRequestHead, Link); + + if (ConfigInfo->ConfigAltResp != NULL) { + FreePool (ConfigInfo->ConfigAltResp); + ConfigInfo->ConfigAltResp = NULL; + } + } +} + +/** + Get AltCfg string for current formset. + + @param FormSet Form data structure. + @param DefaultId The Class of the default. + @param BrowserStorage The input request storage for the questions. + +**/ +VOID +ExtractAltCfgForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 DefaultId, + IN BROWSER_STORAGE *BrowserStorage + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Result; + BROWSER_STORAGE *Storage; + FORMSET_STORAGE *FormSetStorage; + + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); + Storage = FormSetStorage->BrowserStorage; + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if ((BrowserStorage != NULL) && (BrowserStorage != Storage)) { + continue; + } + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // 1. Skip if there is no RequestElement + // + if (FormSetStorage->ElementCount == 0) { + continue; + } + + FormSetStorage->HasCallAltCfg = TRUE; + + // + // 2. Get value through hii config routine protocol. + // + Status = mHiiConfigRouting->ExtractConfig ( + mHiiConfigRouting, + FormSetStorage->ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp) + // Get the default configuration string according to the default ID. + // + Status = mHiiConfigRouting->GetAltConfig ( + mHiiConfigRouting, + Result, + &Storage->Guid, + Storage->Name, + NULL, + &DefaultId, // it can be NULL to get the current setting. + &ConfigResp + ); + + FreePool (Result); + if (EFI_ERROR (Status)) { + continue; + } + + FormSetStorage->ConfigAltResp = ConfigResp; + } +} + +/** + Clean AltCfg string for current formset. + + @param FormSet Form data structure. + +**/ +VOID +CleanAltCfgForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *FormSetStorage; + + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (FormSetStorage->ConfigAltResp != NULL) { + FreePool (FormSetStorage->ConfigAltResp); + FormSetStorage->ConfigAltResp = NULL; + } + + FormSetStorage->HasCallAltCfg = FALSE; + } +} + +/** + Reset Questions to their initial value or default value in a Form, Formset or System. + + GetDefaultValueScope parameter decides which questions will reset + to its default value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param DefaultId The Class of the default. + @param SettingScope Setting Scope for Default action. + @param GetDefaultValueScope Get default value scope. + @param Storage Get default value only for this storage. + @param RetrieveValueFirst Whether call the retrieve call back to + get the initial value before get default + value. + @param SkipGetAltCfg Whether skip the get altcfg string process. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +ExtractDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId, + IN BROWSER_SETTING_SCOPE SettingScope, + IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope, + IN BROWSER_STORAGE *Storage OPTIONAL, + IN BOOLEAN RetrieveValueFirst, + IN BOOLEAN SkipGetAltCfg + ) +{ + EFI_STATUS Status; + LIST_ENTRY *FormLink; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + FORM_BROWSER_FORMSET *LocalFormSet; + FORM_BROWSER_FORMSET *OldFormSet; + + Status = EFI_SUCCESS; + + // + // Check the supported setting level. + // + if ((SettingScope >= MaxLevel) || (GetDefaultValueScope >= GetDefaultForMax)) { + return EFI_UNSUPPORTED; + } + + if ((GetDefaultValueScope == GetDefaultForStorage) && (Storage == NULL)) { + return EFI_UNSUPPORTED; + } + + if (SettingScope == FormLevel) { + // + // Prepare the AltCfg String for form. + // + if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { + ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage); + } + + // + // Extract Form default + // + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // If get default value only for this storage, check the storage first. + // + if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) { + continue; + } + + // + // If get default value only for no storage question, just skip the question which has storage. + // + if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) { + continue; + } + + // + // If Question is disabled, don't reset it to default + // + if (Question->Expression != NULL) { + if (EvaluateExpressionList (Question->Expression, TRUE, FormSet, Form) == ExpressDisable) { + continue; + } + } + + if (RetrieveValueFirst) { + // + // Call the Retrieve call back to get the initial question value. + // + Status = ProcessRetrieveForQuestion (FormSet->ConfigAccess, Question, FormSet); + } + + // + // If not request to get the initial value or get initial value fail, then get default value. + // + if (!RetrieveValueFirst || EFI_ERROR (Status)) { + Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); + if (EFI_ERROR (Status)) { + continue; + } + } + + // + // Synchronize Buffer storage's Edit buffer + // + if ((Question->Storage != NULL) && + (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) + { + SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + } + } + + // + // Clean the AltCfg String. + // + if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { + CleanAltCfgForForm (Form); + } + } else if (SettingScope == FormSetLevel) { + // + // Prepare the AltCfg String for formset. + // + if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { + ExtractAltCfgForFormSet (FormSet, DefaultId, Storage); + } + + FormLink = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, FormLink)) { + Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); + ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); + FormLink = GetNextNode (&FormSet->FormListHead, FormLink); + } + + // + // Clean the AltCfg String. + // + if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { + CleanAltCfgForFormSet (FormSet); + } + } else if (SettingScope == SystemLevel) { + // + // Preload all Hii formset. + // + LoadAllHiiFormset (); + + OldFormSet = mSystemLevelFormSet; + + // + // Set Default Value for each FormSet in the maintain list. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!ValidateFormSet (LocalFormSet)) { + continue; + } + + mSystemLevelFormSet = LocalFormSet; + + ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); + } + + mSystemLevelFormSet = OldFormSet; + } + + return EFI_SUCCESS; +} + +/** + Validate whether this question's value has changed. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. + + @retval TRUE Question's value has changed. + @retval FALSE Question's value has not changed + +**/ +BOOLEAN +IsQuestionValueChanged ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ) +{ + EFI_HII_VALUE BackUpValue; + CHAR8 *BackUpBuffer; + EFI_HII_VALUE BackUpValue2; + CHAR8 *BackUpBuffer2; + EFI_STATUS Status; + BOOLEAN ValueChanged; + UINTN BufferWidth; + + // + // For quetion without storage, always mark it as data not changed. + // + if ((Question->Storage == NULL) && (Question->Operand != EFI_IFR_TIME_OP) && (Question->Operand != EFI_IFR_DATE_OP)) { + return FALSE; + } + + BackUpBuffer = NULL; + BackUpBuffer2 = NULL; + ValueChanged = FALSE; + + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + BufferWidth = Question->StorageWidth; + BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); + ASSERT (BackUpBuffer != NULL); + break; + + case EFI_IFR_STRING_OP: + case EFI_IFR_PASSWORD_OP: + BufferWidth = (UINTN)Question->Maximum * sizeof (CHAR16); + BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); + ASSERT (BackUpBuffer != NULL); + break; + + default: + BufferWidth = 0; + break; + } + + CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); + + if (GetValueFrom == GetSetValueWithBothBuffer) { + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + ASSERT_EFI_ERROR (Status); + + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + BufferWidth = Question->StorageWidth; + BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); + ASSERT (BackUpBuffer2 != NULL); + break; + + case EFI_IFR_STRING_OP: + case EFI_IFR_PASSWORD_OP: + BufferWidth = (UINTN)Question->Maximum * sizeof (CHAR16); + BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); + ASSERT (BackUpBuffer2 != NULL); + break; + + default: + BufferWidth = 0; + break; + } + + CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)); + + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer); + ASSERT_EFI_ERROR (Status); + + if ((CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0) || + (CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0)) + { + ValueChanged = TRUE; + } + } else { + Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom); + ASSERT_EFI_ERROR (Status); + + if ((CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0) || + (CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0)) + { + ValueChanged = TRUE; + } + } + + CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE)); + if (BackUpBuffer != NULL) { + CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth); + FreePool (BackUpBuffer); + } + + if (BackUpBuffer2 != NULL) { + FreePool (BackUpBuffer2); + } + + Question->ValueChanged = ValueChanged; + + return ValueChanged; +} + +/** + Initialize Question's Edit copy from Storage. + + @param Selection Selection contains the information about + the Selection, form and formset to be displayed. + Selection action may be updated in retrieve callback. + If Selection is NULL, only initialize Question value. + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN OUT UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + // + // Initialize local copy of Value for each Question + // + if ((Question->Operand == EFI_IFR_PASSWORD_OP) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == 0)) { + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); + } else { + Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) { + HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16 *)Question->BufferValue, NULL); + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + +/** + Initialize Question's Edit copy from Storage for the whole Formset. + + @param Selection Selection contains the information about + the Selection, form and formset to be displayed. + Selection action may be updated in retrieve callback. + If Selection is NULL, only initialize Question value. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormSetConfig ( + IN OUT UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + // + // Initialize local copy of Value for each Form + // + Status = LoadFormConfig (Selection, FormSet, Form); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + // + // Finished question initialization. + // + FormSet->QuestionInited = TRUE; + + return EFI_SUCCESS; +} + +/** + Remove the Request element from the Config Request. + + @param Storage Pointer to the browser storage. + @param RequestElement The pointer to the Request element. + +**/ +VOID +RemoveElement ( + IN OUT BROWSER_STORAGE *Storage, + IN CHAR16 *RequestElement + ) +{ + CHAR16 *NewStr; + CHAR16 *DestStr; + + ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL); + + NewStr = StrStr (Storage->ConfigRequest, RequestElement); + + if (NewStr == NULL) { + return; + } + + // + // Remove this element from this ConfigRequest. + // + DestStr = NewStr; + NewStr += StrLen (RequestElement); + CopyMem (DestStr, NewStr, StrSize (NewStr)); + + Storage->SpareStrLen += StrLen (RequestElement); +} + +/** + Adjust config request in storage, remove the request elements existed in the input ConfigRequest. + + @param Storage Pointer to the formset storage. + @param ConfigRequest The pointer to the Request element. + +**/ +VOID +RemoveConfigRequest ( + FORMSET_STORAGE *Storage, + CHAR16 *ConfigRequest + ) +{ + CHAR16 *RequestElement; + CHAR16 *NextRequestElement; + CHAR16 *SearchKey; + + // + // No request element in it, just return. + // + if (ConfigRequest == NULL) { + return; + } + + if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage + // + SearchKey = L"&"; + } else { + // + // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage + // + SearchKey = L"&OFFSET"; + } + + // + // Find SearchKey storage + // + if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + RequestElement = StrStr (ConfigRequest, L"PATH"); + ASSERT (RequestElement != NULL); + RequestElement = StrStr (RequestElement, SearchKey); + } else { + RequestElement = StrStr (ConfigRequest, SearchKey); + } + + while (RequestElement != NULL) { + // + // +1 to avoid find header itself. + // + NextRequestElement = StrStr (RequestElement + 1, SearchKey); + + // + // The last Request element in configRequest string. + // + if (NextRequestElement != NULL) { + // + // Replace "&" with '\0'. + // + *NextRequestElement = L'\0'; + } + + RemoveElement (Storage->BrowserStorage, RequestElement); + + if (NextRequestElement != NULL) { + // + // Restore '&' with '\0' for later used. + // + *NextRequestElement = L'&'; + } + + RequestElement = NextRequestElement; + } + + // + // If no request element remain, just remove the ConfigRequest string. + // + if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) { + FreePool (Storage->BrowserStorage->ConfigRequest); + Storage->BrowserStorage->ConfigRequest = NULL; + Storage->BrowserStorage->SpareStrLen = 0; + } +} + +/** + Base on the current formset info, clean the ConfigRequest string in browser storage. + + @param FormSet Pointer of the FormSet + +**/ +VOID +CleanBrowserStorage ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { + if ((Storage->ConfigRequest == NULL) || (Storage->BrowserStorage->ConfigRequest == NULL)) { + continue; + } + + RemoveConfigRequest (Storage, Storage->ConfigRequest); + } else if ((Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER) || + (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE)) + { + if (Storage->BrowserStorage->ConfigRequest != NULL) { + FreePool (Storage->BrowserStorage->ConfigRequest); + Storage->BrowserStorage->ConfigRequest = NULL; + } + + Storage->BrowserStorage->Initialized = FALSE; + } + } +} + +/** + Check whether current element in the ConfigReqeust string. + + @param BrowserStorage Storage which includes ConfigReqeust. + @param RequestElement New element need to check. + + @retval TRUE The Element is in the ConfigReqeust string. + @retval FALSE The Element not in the configReqeust String. + +**/ +BOOLEAN +ElementValidation ( + BROWSER_STORAGE *BrowserStorage, + CHAR16 *RequestElement + ) +{ + return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE; +} + +/** + Append the Request element to the Config Request. + + @param ConfigRequest Current ConfigRequest info. + @param SpareStrLen Current remain free buffer for config reqeust. + @param RequestElement New Request element. + +**/ +VOID +AppendConfigRequest ( + IN OUT CHAR16 **ConfigRequest, + IN OUT UINTN *SpareStrLen, + IN CHAR16 *RequestElement + ) +{ + CHAR16 *NewStr; + UINTN StringSize; + UINTN StrLength; + UINTN MaxLen; + + StrLength = StrLen (RequestElement); + StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16); + MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen; + + // + // Append <RequestElement> to <ConfigRequest> + // + if (StrLength > *SpareStrLen) { + // + // Old String buffer is not sufficient for RequestElement, allocate a new one + // + MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL; + NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (NewStr != NULL); + + if (*ConfigRequest != NULL) { + CopyMem (NewStr, *ConfigRequest, StringSize); + FreePool (*ConfigRequest); + } + + *ConfigRequest = NewStr; + *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; + } + + StrCatS (*ConfigRequest, MaxLen, RequestElement); + *SpareStrLen -= StrLength; +} + +/** + Adjust the config request info, remove the request elements which already in AllConfigRequest string. + + @param Storage Form set Storage. + @param Request The input request string. + @param RespString Whether the input is ConfigRequest or ConfigResp format. + + @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig + @retval FALSE All elements covered by current used elements. + +**/ +BOOLEAN +ConfigRequestAdjust ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Request, + IN BOOLEAN RespString + ) +{ + CHAR16 *RequestElement; + CHAR16 *NextRequestElement; + CHAR16 *NextElementBakup; + CHAR16 *SearchKey; + CHAR16 *ValueKey; + BOOLEAN RetVal; + CHAR16 *ConfigRequest; + + RetVal = FALSE; + NextElementBakup = NULL; + ValueKey = NULL; + + if (Request != NULL) { + ConfigRequest = Request; + } else { + ConfigRequest = Storage->ConfigRequest; + } + + if (Storage->ConfigRequest == NULL) { + Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); + return TRUE; + } + + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage + // + SearchKey = L"&"; + } else { + // + // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage + // + SearchKey = L"&OFFSET"; + ValueKey = L"&VALUE"; + } + + // + // Find SearchKey storage + // + if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + RequestElement = StrStr (ConfigRequest, L"PATH"); + ASSERT (RequestElement != NULL); + RequestElement = StrStr (RequestElement, SearchKey); + } else { + RequestElement = StrStr (ConfigRequest, SearchKey); + } + + while (RequestElement != NULL) { + // + // +1 to avoid find header itself. + // + NextRequestElement = StrStr (RequestElement + 1, SearchKey); + + // + // The last Request element in configRequest string. + // + if (NextRequestElement != NULL) { + if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { + NextElementBakup = NextRequestElement; + NextRequestElement = StrStr (RequestElement, ValueKey); + ASSERT (NextRequestElement != NULL); + } + + // + // Replace "&" with '\0'. + // + *NextRequestElement = L'\0'; + } else { + if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { + NextElementBakup = NextRequestElement; + NextRequestElement = StrStr (RequestElement, ValueKey); + ASSERT (NextRequestElement != NULL); + // + // Replace "&" with '\0'. + // + *NextRequestElement = L'\0'; + } + } + + if (!ElementValidation (Storage, RequestElement)) { + // + // Add this element to the Storage->BrowserStorage->AllRequestElement. + // + AppendConfigRequest (&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement); + RetVal = TRUE; + } + + if (NextRequestElement != NULL) { + // + // Restore '&' with '\0' for later used. + // + *NextRequestElement = L'&'; + } + + if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { + RequestElement = NextElementBakup; + } else { + RequestElement = NextRequestElement; + } + } + + return RetVal; +} + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + +**/ +VOID +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + CHAR16 *StrPtr; + EFI_STRING ConfigRequest; + UINTN StrLen; + + ConfigRequest = NULL; + + switch (Storage->BrowserStorage->Type) { + case EFI_HII_VARSTORE_EFI_VARIABLE: + return; + + case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: + if (Storage->BrowserStorage->ConfigRequest != NULL) { + ConfigRequestAdjust (Storage->BrowserStorage, Storage->ConfigRequest, FALSE); + return; + } + + break; + + case EFI_HII_VARSTORE_BUFFER: + case EFI_HII_VARSTORE_NAME_VALUE: + // + // Skip if there is no RequestElement. + // + if (Storage->ElementCount == 0) { + return; + } + + // + // Just update the ConfigRequest, if storage already initialized. + // + if (Storage->BrowserStorage->Initialized) { + ConfigRequestAdjust (Storage->BrowserStorage, Storage->ConfigRequest, FALSE); + return; + } + + Storage->BrowserStorage->Initialized = TRUE; + break; + + default: + return; + } + + if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { + // + // Create the config request string to get all fields for this storage. + // Allocate and fill a buffer large enough to hold the <ConfigHdr> template + // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator + // + StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (StrLen); + ASSERT (ConfigRequest != NULL); + UnicodeSPrint ( + ConfigRequest, + StrLen, + L"%s&OFFSET=0&WIDTH=%04x", + Storage->ConfigHdr, + Storage->BrowserStorage->Size + ); + } else { + ConfigRequest = Storage->ConfigRequest; + } + + if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { + // + // Call GetVariable directly for EfiVarStore + // + Status = gRT->GetVariable (Storage->BrowserStorage->Name, &(Storage->BrowserStorage->Guid), NULL, (UINTN *)(&(Storage->BrowserStorage->Size)), Storage->BrowserStorage->EditBuffer); + if (EFI_ERROR (Status)) { + ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE); + } + } else { + // + // Request current settings from Configuration Driver + // + Status = mHiiConfigRouting->ExtractConfig ( + mHiiConfigRouting, + ConfigRequest, + &Progress, + &Result + ); + + // + // If get value fail, extract default from IFR binary + // + if (EFI_ERROR (Status)) { + ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE); + } else { + // + // Convert Result from <ConfigAltResp> to <ConfigResp> + // + StrPtr = StrStr (Result, L"&GUID="); + if (StrPtr != NULL) { + *StrPtr = L'\0'; + } + + Status = ConfigRespToStorage (Storage->BrowserStorage, Result); + FreePool (Result); + } + } + + Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); + + // + // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. + // + SynchronizeStorage (Storage->BrowserStorage, NULL, TRUE); + + if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { + if (ConfigRequest != NULL) { + FreePool (ConfigRequest); + } + } +} + +/** + Get Value changed status from old question. + + @param NewFormSet FormSet data structure. + @param OldQuestion Old question which has value changed. + +**/ +VOID +SyncStatusForQuestion ( + IN OUT FORM_BROWSER_FORMSET *NewFormSet, + IN FORM_BROWSER_STATEMENT *OldQuestion + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *QuestionLink; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Question; + + // + // For each form in one formset. + // + Link = GetFirstNode (&NewFormSet->FormListHead); + while (!IsNull (&NewFormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&NewFormSet->FormListHead, Link); + + // + // for each question in one form. + // + QuestionLink = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, QuestionLink)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); + QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); + + if (Question->QuestionId == OldQuestion->QuestionId) { + Question->ValueChanged = TRUE; + return; + } + } + } +} + +/** + Get Value changed status from old formset. + + @param NewFormSet FormSet data structure. + @param OldFormSet FormSet data structure. + +**/ +VOID +SyncStatusForFormSet ( + IN OUT FORM_BROWSER_FORMSET *NewFormSet, + IN FORM_BROWSER_FORMSET *OldFormSet + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *QuestionLink; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Question; + + // + // For each form in one formset. + // + Link = GetFirstNode (&OldFormSet->FormListHead); + while (!IsNull (&OldFormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Link = GetNextNode (&OldFormSet->FormListHead, Link); + + // + // for each question in one form. + // + QuestionLink = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, QuestionLink)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); + QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); + + if (!Question->ValueChanged) { + continue; + } + + // + // Find the same question in new formset and update the value changed flag. + // + SyncStatusForQuestion (NewFormSet, Question); + } + } +} + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + +**/ +VOID +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORMSET *OldFormSet; + + // + // Try to find pre FormSet in the maintain backup list. + // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList. + // + OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle); + if (OldFormSet != NULL) { + SyncStatusForFormSet (FormSet, OldFormSet); + RemoveEntryList (&OldFormSet->Link); + DestroyFormSet (OldFormSet); + } + + InsertTailList (&gBrowserFormSetList, &FormSet->Link); + + // + // Extract default from IFR binary for no storage questions. + // + ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE); + + // + // Request current settings from Configuration Driver + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + LoadStorage (FormSet, Storage); + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } +} + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid On input, GUID or class GUID of a formset. If not + specified (NULL or zero GUID), take the first + FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID + found in package list. + On output, GUID of the formset found(if not NULL). + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT8 *Package; + UINT8 *OpCodeData; + UINT32 Offset; + UINT32 Offset2; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINT8 Index; + UINT8 NumberOfClassGuid; + BOOLEAN ClassGuidMatch; + EFI_GUID *ClassGuid; + EFI_GUID *ComparingGuid; + + OpCodeData = NULL; + Package = NULL; + ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER)); + + // + // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list + // + if (FormSetGuid == NULL) { + ComparingGuid = &gZeroGuid; + } else { + ComparingGuid = FormSetGuid; + } + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (HiiPackageList != NULL); + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + ClassGuidMatch = FALSE; + while (Offset < PackageListLength) { + Package = ((UINT8 *)HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + // + // Try to compare against formset GUID + // + if (IsZeroGuid (ComparingGuid) || + CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) + { + break; + } + + if (((EFI_IFR_OP_HEADER *)OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) { + // + // Try to compare against formset class GUID + // + NumberOfClassGuid = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3); + ClassGuid = (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET)); + for (Index = 0; Index < NumberOfClassGuid; Index++) { + if (CompareGuid (ComparingGuid, ClassGuid + Index)) { + ClassGuidMatch = TRUE; + break; + } + } + + if (ClassGuidMatch) { + break; + } + } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) { + ClassGuidMatch = TRUE; + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length; + } + + if (Offset2 < PackageHeader.Length) { + // + // Target formset found + // + break; + } + } + + Offset += PackageHeader.Length; + } + + if (Offset >= PackageListLength) { + // + // Form package not found in this Package List + // + FreePool (HiiPackageList); + return EFI_NOT_FOUND; + } + + if (FormSetGuid != NULL) { + // + // Return the FormSet GUID + // + CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *)OpCodeData)->Guid, sizeof (EFI_GUID)); + } + + // + // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes + // in this FormSet; So, here just simply copy the data from start of a FormSet to the end + // of the Form Package. + // + *BinaryLength = PackageHeader.Length - Offset2; + *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); + + FreePool (HiiPackageList); + + if (*BinaryData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid On input, GUID or class GUID of a formset. If not + specified (NULL or zero GUID), take the first + FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID + found in package list. + On output, GUID of the formset found(if not NULL). + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + + Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); + if (EFI_ERROR (Status)) { + return Status; + } + + FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE; + FormSet->HiiHandle = Handle; + CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); + FormSet->QuestionInited = FALSE; + + // + // Retrieve ConfigAccess Protocol associated with this HiiPackageList + // + Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + FormSet->DriverHandle = DriverHandle; + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + (VOID **)&FormSet->ConfigAccess + ); + if (EFI_ERROR (Status)) { + // + // Configuration Driver don't attach ConfigAccess protocol to its HII package + // list, then there will be no configuration action required + // + FormSet->ConfigAccess = NULL; + } + + // + // Parse the IFR binary OpCodes + // + Status = ParseOpCodes (FormSet); + + return Status; +} + +/** + Save globals used by previous call to SendForm(). SendForm() may be called from + HiiConfigAccess.Callback(), this will cause SendForm() be reentried. + So, save globals of previous call to SendForm() and restore them upon exit. + +**/ +VOID +SaveBrowserContext ( + VOID + ) +{ + BROWSER_CONTEXT *Context; + FORM_ENTRY_INFO *MenuList; + FORM_BROWSER_FORMSET *FormSet; + + gBrowserContextCount++; + if (gBrowserContextCount == 1) { + // + // This is not reentry of SendForm(), no context to save + // + return; + } + + Context = AllocatePool (sizeof (BROWSER_CONTEXT)); + ASSERT (Context != NULL); + + Context->Signature = BROWSER_CONTEXT_SIGNATURE; + + // + // Save FormBrowser context + // + Context->Selection = gCurrentSelection; + Context->ResetRequired = gResetRequiredFormLevel; + Context->FlagReconnect = gFlagReconnect; + Context->CallbackReconnect = gCallbackReconnect; + Context->ExitRequired = gExitRequired; + Context->HiiHandle = mCurrentHiiHandle; + Context->FormId = mCurrentFormId; + CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid); + Context->SystemLevelFormSet = mSystemLevelFormSet; + Context->CurFakeQestId = mCurFakeQestId; + Context->HiiPackageListUpdated = mHiiPackageListUpdated; + Context->FinishRetrieveCall = mFinishRetrieveCall; + + // + // Save the menu history data. + // + InitializeListHead (&Context->FormHistoryList); + while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); + RemoveEntryList (&MenuList->Link); + + InsertTailList (&Context->FormHistoryList, &MenuList->Link); + } + + // + // Save formset list. + // + InitializeListHead (&Context->FormSetList); + while (!IsListEmpty (&gBrowserFormSetList)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink); + RemoveEntryList (&FormSet->Link); + + InsertTailList (&Context->FormSetList, &FormSet->Link); + } + + // + // Insert to FormBrowser context list + // + InsertHeadList (&gBrowserContextList, &Context->Link); +} + +/** + Restore globals used by previous call to SendForm(). + +**/ +VOID +RestoreBrowserContext ( + VOID + ) +{ + LIST_ENTRY *Link; + BROWSER_CONTEXT *Context; + FORM_ENTRY_INFO *MenuList; + FORM_BROWSER_FORMSET *FormSet; + + ASSERT (gBrowserContextCount != 0); + gBrowserContextCount--; + if (gBrowserContextCount == 0) { + // + // This is not reentry of SendForm(), no context to restore + // + return; + } + + ASSERT (!IsListEmpty (&gBrowserContextList)); + + Link = GetFirstNode (&gBrowserContextList); + Context = BROWSER_CONTEXT_FROM_LINK (Link); + + // + // Restore FormBrowser context + // + gCurrentSelection = Context->Selection; + gResetRequiredFormLevel = Context->ResetRequired; + gFlagReconnect = Context->FlagReconnect; + gCallbackReconnect = Context->CallbackReconnect; + gExitRequired = Context->ExitRequired; + mCurrentHiiHandle = Context->HiiHandle; + mCurrentFormId = Context->FormId; + CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid); + mSystemLevelFormSet = Context->SystemLevelFormSet; + mCurFakeQestId = Context->CurFakeQestId; + mHiiPackageListUpdated = Context->HiiPackageListUpdated; + mFinishRetrieveCall = Context->FinishRetrieveCall; + + // + // Restore the menu history data. + // + while (!IsListEmpty (&Context->FormHistoryList)) { + MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink); + RemoveEntryList (&MenuList->Link); + + InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); + } + + // + // Restore the Formset data. + // + while (!IsListEmpty (&Context->FormSetList)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink); + RemoveEntryList (&FormSet->Link); + + InsertTailList (&gBrowserFormSetList, &FormSet->Link); + } + + // + // Remove from FormBrowser context list + // + RemoveEntryList (&Context->Link); + gBS->FreePool (Context); +} + +/** + Find the matched FormSet context in the backup maintain list based on HiiHandle. + + @param Handle The Hii Handle. + + @return the found FormSet context. If no found, NULL will return. + +**/ +FORM_BROWSER_FORMSET * +GetFormSetFromHiiHandle ( + EFI_HII_HANDLE Handle + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *FormSet; + + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!ValidateFormSet (FormSet)) { + continue; + } + + if (FormSet->HiiHandle == Handle) { + return FormSet; + } + } + + return NULL; +} + +/** + Check whether the input HII handle is the FormSet that is being used. + + @param Handle The Hii Handle. + + @retval TRUE HII handle is being used. + @retval FALSE HII handle is not being used. + +**/ +BOOLEAN +IsHiiHandleInBrowserContext ( + EFI_HII_HANDLE Handle + ) +{ + LIST_ENTRY *Link; + BROWSER_CONTEXT *Context; + + // + // HiiHandle is Current FormSet. + // + if (mCurrentHiiHandle == Handle) { + return TRUE; + } + + // + // Check whether HiiHandle is in BrowserContext. + // + Link = GetFirstNode (&gBrowserContextList); + while (!IsNull (&gBrowserContextList, Link)) { + Context = BROWSER_CONTEXT_FROM_LINK (Link); + if (Context->HiiHandle == Handle) { + // + // HiiHandle is in BrowserContext + // + return TRUE; + } + + Link = GetNextNode (&gBrowserContextList, Link); + } + + return FALSE; +} + +/** + Perform Password check. + Passwork may be encrypted by driver that requires the specific check. + + @param Form Form where Password Statement is in. + @param Statement Password statement + @param PasswordString Password string to be checked. It may be NULL. + NULL means to restore password. + "" string can be used to checked whether old password does exist. + + @return Status Status of Password check. +**/ +EFI_STATUS +EFIAPI +PasswordCheck ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_STRING PasswordString OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_IFR_TYPE_VALUE IfrTypeValue; + FORM_BROWSER_STATEMENT *Question; + + ConfigAccess = gCurrentSelection->FormSet->ConfigAccess; + Question = GetBrowserStatement (Statement); + ASSERT (Question != NULL); + + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) { + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + } else { + // + // If a password doesn't have the CALLBACK flag, browser will not handle it. + // + return EFI_UNSUPPORTED; + } + + // + // Prepare password string in HII database + // + if (PasswordString != NULL) { + IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle); + } else { + IfrTypeValue.string = 0; + } + + // + // Send password to Configuration Driver for validation + // + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + Question->QuestionId, + Question->HiiValue.Type, + &IfrTypeValue, + &ActionRequest + ); + + // + // Remove password string from HII database + // + if (PasswordString != NULL) { + DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle); + } + + return Status; +} + +/** + Find the registered HotKey based on KeyData. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. + + @return The registered HotKey context. If no found, NULL will return. +**/ +BROWSER_HOT_KEY * +GetHotKeyFromRegisterList ( + IN EFI_INPUT_KEY *KeyData + ) +{ + LIST_ENTRY *Link; + BROWSER_HOT_KEY *HotKey; + + Link = GetFirstNode (&gBrowserHotKeyList); + while (!IsNull (&gBrowserHotKeyList, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + if (HotKey->KeyData->ScanCode == KeyData->ScanCode) { + return HotKey; + } + + Link = GetNextNode (&gBrowserHotKeyList, Link); + } + + return NULL; +} + +/** + Configure what scope the hot key will impact. + All hot keys have the same scope. The mixed hot keys with the different level are not supported. + If no scope is set, the default scope will be FormSet level. + After all registered hot keys are removed, previous Scope can reset to another level. + + @param[in] Scope Scope level to be set. + + @retval EFI_SUCCESS Scope is set correctly. + @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. + @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. + +**/ +EFI_STATUS +EFIAPI +SetScope ( + IN BROWSER_SETTING_SCOPE Scope + ) +{ + if (Scope >= MaxLevel) { + return EFI_INVALID_PARAMETER; + } + + // + // When no hot key registered in system or on the first setting, + // Scope can be set. + // + if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) { + gBrowserSettingScope = Scope; + mBrowserScopeFirstSet = FALSE; + } else if (Scope != gBrowserSettingScope) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Register the hot key with its browser action, or unregistered the hot key. + Only support hot key that is not printable character (control key, function key, etc.). + If the action value is zero, the hot key will be unregistered if it has been registered. + If the same hot key has been registered, the new action and help string will override the previous ones. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. Its type is EFI_INPUT_KEY to + be supported by all ConsoleIn devices. + @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. + @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. + @param[in] HelpString Help string that describes the hot key information. + Its value may be NULL for the unregistered hot key. + + @retval EFI_SUCCESS Hot key is registered or unregistered. + @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register. + @retval EFI_NOT_FOUND KeyData is not found to be unregistered. + @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. + @retval EFI_ALREADY_STARTED Key already been registered for one hot key. +**/ +EFI_STATUS +EFIAPI +RegisterHotKey ( + IN EFI_INPUT_KEY *KeyData, + IN UINT32 Action, + IN UINT16 DefaultId, + IN EFI_STRING HelpString OPTIONAL + ) +{ + BROWSER_HOT_KEY *HotKey; + + // + // Check input parameters. + // + if ((KeyData == NULL) || (KeyData->UnicodeChar != CHAR_NULL) || + ((Action != BROWSER_ACTION_UNREGISTER) && (HelpString == NULL))) + { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether the input KeyData is in BrowserHotKeyList. + // + HotKey = GetHotKeyFromRegisterList (KeyData); + + // + // Unregister HotKey + // + if (Action == BROWSER_ACTION_UNREGISTER) { + if (HotKey != NULL) { + // + // The registered HotKey is found. + // Remove it from List, and free its resource. + // + RemoveEntryList (&HotKey->Link); + FreePool (HotKey->KeyData); + FreePool (HotKey->HelpString); + return EFI_SUCCESS; + } else { + // + // The registered HotKey is not found. + // + return EFI_NOT_FOUND; + } + } + + if (HotKey != NULL) { + return EFI_ALREADY_STARTED; + } + + // + // Create new Key, and add it into List. + // + HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY)); + ASSERT (HotKey != NULL); + HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE; + HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData); + InsertTailList (&gBrowserHotKeyList, &HotKey->Link); + + // + // Fill HotKey information. + // + HotKey->Action = Action; + HotKey->DefaultId = DefaultId; + if (HotKey->HelpString != NULL) { + FreePool (HotKey->HelpString); + } + + HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString); + + return EFI_SUCCESS; +} + +/** + Register Exit handler function. + When more than one handler function is registered, the latter one will override the previous one. + When NULL handler is specified, the previous Exit handler will be unregistered. + + @param[in] Handler Pointer to handler function. + +**/ +VOID +EFIAPI +RegiserExitHandler ( + IN EXIT_HANDLER Handler + ) +{ + ExitHandlerFunction = Handler; + return; +} + +/** + Check whether the browser data has been modified. + + @retval TRUE Browser data is modified. + @retval FALSE No browser data is modified. + +**/ +BOOLEAN +EFIAPI +IsBrowserDataModified ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *FormSet; + + switch (gBrowserSettingScope) { + case FormLevel: + if (gCurrentSelection == NULL) { + return FALSE; + } + + return IsNvUpdateRequiredForForm (gCurrentSelection->Form); + + case FormSetLevel: + if (gCurrentSelection == NULL) { + return FALSE; + } + + return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet); + + case SystemLevel: + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (!ValidateFormSet (FormSet)) { + continue; + } + + if (IsNvUpdateRequiredForFormSet (FormSet)) { + return TRUE; + } + + Link = GetNextNode (&gBrowserFormSetList, Link); + } + + return FALSE; + + default: + return FALSE; + } +} + +/** + Execute the action requested by the Action parameter. + + @param[in] Action Execute the request action. + @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT. + + @retval EFI_SUCCESS Execute the request action succss. + @retval EFI_INVALID_PARAMETER The input action value is invalid. + +**/ +EFI_STATUS +EFIAPI +ExecuteAction ( + IN UINT32 Action, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + + if ((gBrowserSettingScope < SystemLevel) && (gCurrentSelection == NULL)) { + return EFI_NOT_READY; + } + + Status = EFI_SUCCESS; + FormSet = NULL; + Form = NULL; + if (gBrowserSettingScope < SystemLevel) { + FormSet = gCurrentSelection->FormSet; + Form = gCurrentSelection->Form; + } + + // + // Executet the discard action. + // + if ((Action & BROWSER_ACTION_DISCARD) != 0) { + Status = DiscardForm (FormSet, Form, gBrowserSettingScope); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Executet the difault action. + // + if ((Action & BROWSER_ACTION_DEFAULT) != 0) { + Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + + UpdateStatementStatus (FormSet, Form, gBrowserSettingScope); + } + + // + // Executet the submit action. + // + if ((Action & BROWSER_ACTION_SUBMIT) != 0) { + Status = SubmitForm (FormSet, Form, gBrowserSettingScope); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Executet the reset action. + // + if ((Action & BROWSER_ACTION_RESET) != 0) { + gResetRequiredFormLevel = TRUE; + gResetRequiredSystemLevel = TRUE; + } + + // + // Executet the exit action. + // + if ((Action & BROWSER_ACTION_EXIT) != 0) { + DiscardForm (FormSet, Form, gBrowserSettingScope); + if (gBrowserSettingScope == SystemLevel) { + if (ExitHandlerFunction != NULL) { + ExitHandlerFunction (); + } + } + + gExitRequired = TRUE; + } + + return Status; +} + +/** + Create reminder to let user to choose save or discard the changed browser data. + Caller can use it to actively check the changed browser data. + + @retval BROWSER_NO_CHANGES No browser data is changed. + @retval BROWSER_SAVE_CHANGES The changed browser data is saved. + @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. + @retval BROWSER_KEEP_CURRENT Browser keep current changes. + +**/ +UINT32 +EFIAPI +SaveReminder ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *FormSet; + BOOLEAN IsDataChanged; + UINT32 DataSavedAction; + UINT32 ConfirmRet; + + DataSavedAction = BROWSER_NO_CHANGES; + IsDataChanged = FALSE; + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!ValidateFormSet (FormSet)) { + continue; + } + + if (IsNvUpdateRequiredForFormSet (FormSet)) { + IsDataChanged = TRUE; + break; + } + } + + // + // No data is changed. No save is required. + // + if (!IsDataChanged) { + return DataSavedAction; + } + + // + // If data is changed, prompt user to save or discard it. + // + do { + ConfirmRet = (UINT32)mFormDisplay->ConfirmDataChange (); + + if (ConfirmRet == BROWSER_ACTION_SUBMIT) { + SubmitForm (NULL, NULL, SystemLevel); + DataSavedAction = BROWSER_SAVE_CHANGES; + break; + } else if (ConfirmRet == BROWSER_ACTION_DISCARD) { + DiscardForm (NULL, NULL, SystemLevel); + DataSavedAction = BROWSER_DISCARD_CHANGES; + break; + } else if (ConfirmRet == BROWSER_ACTION_NONE) { + DataSavedAction = BROWSER_KEEP_CURRENT; + break; + } + } while (1); + + return DataSavedAction; +} + +/** + Check whether the Reset Required for the browser + + @retval TRUE Browser required to reset after exit. + @retval FALSE Browser not need to reset after exit. + +**/ +BOOLEAN +EFIAPI +IsResetRequired ( + VOID + ) +{ + return gResetRequiredSystemLevel; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index b66806d343..d580a3bccc 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -1,1868 +1,1868 @@ -/** @file
-Private MACRO, structure and function definitions for Setup Browser module.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-
-**/
-
-#ifndef _SETUP_H_
-#define _SETUP_H_
-
-#include <PiDxe.h>
-
-#include <Protocol/SimpleTextOut.h>
-#include <Protocol/SimpleTextIn.h>
-#include <Protocol/FormBrowser2.h>
-#include <Protocol/FormBrowserEx2.h>
-#include <Protocol/DisplayProtocol.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/UnicodeCollation.h>
-#include <Protocol/HiiConfigAccess.h>
-#include <Protocol/HiiConfigRouting.h>
-#include <Protocol/HiiDatabase.h>
-#include <Protocol/HiiString.h>
-#include <Protocol/UserManager.h>
-#include <Protocol/DevicePathFromText.h>
-#include <Protocol/RegularExpressionProtocol.h>
-
-#include <Guid/MdeModuleHii.h>
-#include <Guid/HiiPlatformSetupFormset.h>
-#include <Guid/HiiFormMapMethodGuid.h>
-#include <Guid/ZeroGuid.h>
-
-#include <Library/PrintLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/UefiDriverEntryPoint.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/BaseLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/HiiLib.h>
-#include <Library/PcdLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/UefiLib.h>
-
-//
-// This is the generated header file which includes whatever needs to be exported (strings + IFR)
-//
-
-#define UI_ACTION_NONE 0
-#define UI_ACTION_REFRESH_FORM 1
-#define UI_ACTION_REFRESH_FORMSET 2
-#define UI_ACTION_EXIT 3
-
-//
-//
-// Time definitions
-//
-#define ONE_SECOND 10000000
-
-// Incremental string lenght of ConfigRequest
-//
-#define CONFIG_REQUEST_STRING_INCREMENTAL 1024
-
-//
-// Incremental size of stack for expression
-//
-#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
-
-#define EFI_IFR_SPECIFICATION_VERSION (UINT16) (((EFI_SYSTEM_TABLE_REVISION >> 16) << 8) | (((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) / 10) << 4) | ((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) % 10))
-
-#define SETUP_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'B', 'D', 'V')
-typedef struct {
- UINT32 Signature;
-
- EFI_HANDLE Handle;
-
- //
- // Produced protocol
- //
- EFI_FORM_BROWSER2_PROTOCOL FormBrowser2;
- EDKII_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx;
-
- EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL FormBrowserEx2;
-} SETUP_DRIVER_PRIVATE_DATA;
-
-//
-// IFR relative definition
-//
-#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0
-#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1
-#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2
-#define EFI_HII_EXPRESSION_SUPPRESS_IF 3
-#define EFI_HII_EXPRESSION_DISABLE_IF 4
-#define EFI_HII_EXPRESSION_VALUE 5
-#define EFI_HII_EXPRESSION_RULE 6
-#define EFI_HII_EXPRESSION_READ 7
-#define EFI_HII_EXPRESSION_WRITE 8
-#define EFI_HII_EXPRESSION_WARNING_IF 9
-
-#define EFI_HII_VARSTORE_BUFFER 0
-#define EFI_HII_VARSTORE_NAME_VALUE 1
-#define EFI_HII_VARSTORE_EFI_VARIABLE 2 // EFI Varstore type follow UEFI spec before 2.3.1.
-#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3 // EFI varstore type follow UEFI spec 2.3.1 and later.
-
-#define FORM_INCONSISTENT_VALIDATION 0
-#define FORM_NO_SUBMIT_VALIDATION 1
-
-#define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
- CHAR16 *Name;
- CHAR16 *Value;
- CHAR16 *EditValue;
-} NAME_VALUE_NODE;
-
-#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE)
-
-#define BROWSER_STORAGE_SIGNATURE SIGNATURE_32 ('B', 'S', 'T', 'G')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT8 Type; // Storage type
-
- BOOLEAN Initialized; // Whether this varstore is initialized, efi varstore not used.
-
- EFI_HII_HANDLE HiiHandle; // HiiHandle for this varstore, efi varstore not used.
- EFI_GUID Guid;
-
- CHAR16 *Name; // For EFI_IFR_VARSTORE
- UINT16 Size;
- UINT8 *Buffer;
- UINT8 *EditBuffer; // Edit copy for Buffer Storage
-
- LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE
-
- UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
-
- CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
- // <RequestElement> includes all fields which is used by current form sets.
- UINTN SpareStrLen; // Spare length of ConfigRequest string buffer
-} BROWSER_STORAGE;
-
-#define BROWSER_STORAGE_FROM_LINK(a) CR (a, BROWSER_STORAGE, Link, BROWSER_STORAGE_SIGNATURE)
-
-#define FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'G')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- LIST_ENTRY SaveFailLink;
-
- UINT16 VarStoreId;
-
- BROWSER_STORAGE *BrowserStorage;
-
- CHAR16 *ConfigHdr; // <ConfigHdr>
-
- CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
- CHAR16 *ConfigAltResp; // Alt config response string for this ConfigRequest.
- BOOLEAN HasCallAltCfg; // Flag to show whether browser has call ExtractConfig to get Altcfg string.
- UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest>
- UINTN SpareStrLen; // Spare length of ConfigRequest string buffer
- CHAR16 *RestoreConfigRequest; // When submit formset fail, the element need to be restored
- CHAR16 *SyncConfigRequest; // When submit formset fail, the element need to be synced
-} FORMSET_STORAGE;
-
-#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE)
-#define FORMSET_STORAGE_FROM_SAVE_FAIL_LINK(a) CR (a, FORMSET_STORAGE, SaveFailLink, FORMSET_STORAGE_SIGNATURE)
-
-typedef union {
- EFI_STRING_ID VarName;
- UINT16 VarOffset;
-} VAR_STORE_INFO;
-
-#define EXPRESSION_OPCODE_SIGNATURE SIGNATURE_32 ('E', 'X', 'O', 'P')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT8 Operand;
-
- UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND
- UINT8 Flags; // For EFI_IFR_SPAN
- UINT8 RuleId; // For EFI_IFR_RULE_REF
-
- EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1
-
- EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_VAL_LIST, EFI_IFR_QUESTION_REF1
- EFI_QUESTION_ID QuestionId2;
-
- UINT16 ListLength; // For EFI_IFR_EQ_ID_VAL_LIST
- UINT16 *ValueList;
-
- EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3
- EFI_GUID Guid;
-
- BROWSER_STORAGE *VarStorage; // For EFI_IFR_SET, EFI_IFR_GET
- VAR_STORE_INFO VarStoreInfo; // For EFI_IFR_SET, EFI_IFR_GET
- UINT8 ValueType; // For EFI_IFR_SET, EFI_IFR_GET
- UINT8 ValueWidth; // For EFI_IFR_SET, EFI_IFR_GET
- CHAR16 *ValueName; // For EFI_IFR_SET, EFI_IFR_GET
- LIST_ENTRY MapExpressionList; // nested expressions inside of Map opcode.
-} EXPRESSION_OPCODE;
-
-#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE)
-
-#define FORM_EXPRESSION_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'P')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT8 Type; // Type for this expression
-
- UINT8 RuleId; // For EFI_IFR_RULE only
- EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only
-
- EFI_HII_VALUE Result; // Expression evaluation result
-
- UINT8 TimeOut; // For EFI_IFR_WARNING_IF
- EFI_IFR_OP_HEADER *OpCode; // Save the opcode buffer.
-
- LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE)
-} FORM_EXPRESSION;
-
-#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE)
-
-#define FORM_EXPRESSION_LIST_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'R')
-
-typedef struct {
- UINTN Signature;
- UINTN Count;
- FORM_EXPRESSION *Expression[1]; // Array[Count] of expressions
-} FORM_EXPRESSION_LIST;
-
-#define QUESTION_DEFAULT_SIGNATURE SIGNATURE_32 ('Q', 'D', 'F', 'T')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT16 DefaultId;
- EFI_HII_VALUE Value; // Default value
-
- FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE
-} QUESTION_DEFAULT;
-
-#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE)
-
-#define QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- EFI_IFR_ONE_OF_OPTION *OpCode; // OneOfOption Data
-
- EFI_STRING_ID Text;
- UINT8 Flags;
- EFI_HII_VALUE Value;
- EFI_IMAGE_ID ImageId;
-
- FORM_EXPRESSION_LIST *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf
-} QUESTION_OPTION;
-
-#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE)
-
-typedef enum {
- ExpressFalse = 0,
- ExpressGrayOut,
- ExpressSuppress,
- ExpressDisable
-} EXPRESS_RESULT;
-
-typedef enum {
- ExpressNone = 0,
- ExpressForm,
- ExpressStatement,
- ExpressOption
-} EXPRESS_LEVEL;
-
-typedef struct _FORM_BROWSER_STATEMENT FORM_BROWSER_STATEMENT;
-
-#define FORM_BROWSER_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A')
-
-struct _FORM_BROWSER_STATEMENT {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT8 Operand; // The operand (first byte) of this Statement or Question
- EFI_IFR_OP_HEADER *OpCode;
-
- //
- // Statement Header
- //
- EFI_STRING_ID Prompt;
- EFI_STRING_ID Help;
- EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT
-
- //
- // Fake Question Id, used for statement not has true QuestionId.
- //
- EFI_QUESTION_ID FakeQuestionId;
-
- //
- // Question Header
- //
- EFI_QUESTION_ID QuestionId; // The value of zero is reserved
- EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage
- BROWSER_STORAGE *Storage;
- VAR_STORE_INFO VarStoreInfo;
- UINT16 StorageWidth;
- UINT16 BitStorageWidth;
- UINT16 BitVarOffset;
- UINT8 QuestionFlags;
- BOOLEAN QuestionReferToBitField; // Whether the question is stored in a bit field.
- CHAR16 *VariableName; // Name/Value or EFI Variable name
- CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..."
-
- EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof
- UINT8 *BufferValue; // Edit copy for string, password, orderedlist
- UINT8 ValueType; // Data type for orderedlist value array
-
- //
- // OpCode specific members
- //
- UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF,
- // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER
- UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST
-
- UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number
- EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed
-
- UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value
- UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length
- UINT64 Step;
-
- EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON
- EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID
- BOOLEAN Locked; // Whether this statement is locked.
- BOOLEAN ValueChanged; // Whether this statement's value is changed.
- //
- // Get from IFR parsing
- //
- FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly
- LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values
- LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)
-
- EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE
- UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh
-
- FORM_BROWSER_STATEMENT *ParentStatement;
-
- LIST_ENTRY InconsistentListHead; // nested inconsistent expression list (FORM_EXPRESSION)
- LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION)
- LIST_ENTRY WarningListHead; // nested warning expression list (FORM_EXPRESSION)
- FORM_EXPRESSION_LIST *Expression; // nesting inside of GrayOutIf/DisableIf/SuppressIf
-
- FORM_EXPRESSION *ReadExpression; // nested EFI_IFR_READ, provide this question value by read expression.
- FORM_EXPRESSION *WriteExpression; // nested EFI_IFR_WRITE, evaluate write expression after this question value is set.
-};
-
-#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE)
-
-#define FORM_BROWSER_CONFIG_REQUEST_SIGNATURE SIGNATURE_32 ('F', 'C', 'R', 'S')
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- LIST_ENTRY SaveFailLink;
-
- CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
- CHAR16 *ConfigAltResp; // Alt config response string for this ConfigRequest.
- UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest>
- UINTN SpareStrLen;
- CHAR16 *RestoreConfigRequest; // When submit form fail, the element need to be restored
- CHAR16 *SyncConfigRequest; // When submit form fail, the element need to be synced
-
- BROWSER_STORAGE *Storage;
-} FORM_BROWSER_CONFIG_REQUEST;
-#define FORM_BROWSER_CONFIG_REQUEST_FROM_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, Link, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE)
-#define FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, SaveFailLink, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE)
-
-#define FORM_BROWSER_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M')
-#define STANDARD_MAP_FORM_TYPE 0x01
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT16 FormId; // FormId of normal form or formmap form.
- EFI_STRING_ID FormTitle; // FormTile of normal form, or FormMapMethod title of formmap form.
- UINT16 FormType; // Specific form type for the different form.
-
- EFI_IMAGE_ID ImageId;
-
- BOOLEAN ModalForm; // Whether this is a modal form.
- BOOLEAN Locked; // Whether this form is locked.
- EFI_GUID RefreshGuid; // Form refresh event guid.
-
- LIST_ENTRY FormViewListHead; // List of type FORMID_INFO is Browser View Form History List.
- LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
- LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT)
- LIST_ENTRY ConfigRequestHead; // List of configreques for all storage.
- FORM_EXPRESSION_LIST *SuppressExpression; // nesting inside of SuppressIf
-} FORM_BROWSER_FORM;
-
-#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE)
-
-#define FORMSET_DEFAULTSTORE_SIGNATURE SIGNATURE_32 ('F', 'D', 'F', 'S')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- UINT16 DefaultId;
- EFI_STRING_ID DefaultName;
-} FORMSET_DEFAULTSTORE;
-
-#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE)
-
-#define FORM_BROWSER_FORMSET_SIGNATURE SIGNATURE_32 ('F', 'B', 'F', 'S')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
- LIST_ENTRY SaveFailLink;
-
- EFI_HII_HANDLE HiiHandle; // unique id for formset.
- EFI_HANDLE DriverHandle;
- EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
-
- UINTN IfrBinaryLength;
- UINT8 *IfrBinaryData;
-
- BOOLEAN QuestionInited; // Have finished question initilization?
- EFI_GUID Guid;
- EFI_STRING_ID FormSetTitle;
- EFI_STRING_ID Help;
- UINT8 NumberOfClassGuid;
- EFI_GUID ClassGuid[3]; // Up to three ClassGuid
- UINT16 Class; // Tiano extended Class code
- UINT16 SubClass; // Tiano extended Subclass code
- EFI_IMAGE_ID ImageId;
- EFI_IFR_OP_HEADER *OpCode; // mainly for formset op to get ClassGuid
-
- FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions
- EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode
- FORM_BROWSER_FORM *SaveFailForm; // The form which failed to save.
- FORM_BROWSER_STATEMENT *SaveFailStatement; // The Statement which failed to save.
-
- LIST_ENTRY StatementListOSF; // Statement list out side of the form.
- LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE)
- LIST_ENTRY SaveFailStorageListHead; // Storage list for the save fail storage.
- LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)
- LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM)
- LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
-} FORM_BROWSER_FORMSET;
-#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)
-
-#define FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_FORMSET, SaveFailLink, FORM_BROWSER_FORMSET_SIGNATURE)
-
-typedef struct {
- LIST_ENTRY Link;
- EFI_EVENT RefreshEvent;
-} FORM_BROWSER_REFRESH_EVENT_NODE;
-
-#define FORM_BROWSER_REFRESH_EVENT_FROM_LINK(a) BASE_CR (a, FORM_BROWSER_REFRESH_EVENT_NODE, Link)
-
-typedef struct {
- EFI_HII_HANDLE Handle;
-
- //
- // Target formset/form/Question information
- //
- EFI_GUID FormSetGuid;
- UINT16 FormId;
- UINT16 QuestionId;
- UINTN Sequence; // used for time/date only.
-
- UINTN TopRow;
- UINTN BottomRow;
- UINTN PromptCol;
- UINTN OptionCol;
- UINTN CurrentRow;
-
- //
- // Ation for Browser to taken:
- // UI_ACTION_NONE - navigation inside a form
- // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form
- // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary
- //
- UINTN Action;
-
- //
- // Current selected fomset/form/Question
- //
- FORM_BROWSER_FORMSET *FormSet;
- FORM_BROWSER_FORM *Form;
- FORM_BROWSER_STATEMENT *Statement;
-
- //
- // Whether the Form is editable
- //
- BOOLEAN FormEditable;
-
- FORM_ENTRY_INFO *CurrentMenu;
-} UI_MENU_SELECTION;
-
-#define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- //
- // Globals defined in Setup.c
- //
- BOOLEAN FlagReconnect;
- BOOLEAN CallbackReconnect;
- BOOLEAN ResetRequired;
- BOOLEAN ExitRequired;
- EFI_HII_HANDLE HiiHandle;
- EFI_GUID FormSetGuid;
- EFI_FORM_ID FormId;
- UI_MENU_SELECTION *Selection;
- FORM_BROWSER_FORMSET *SystemLevelFormSet;
- EFI_QUESTION_ID CurFakeQestId;
- BOOLEAN HiiPackageListUpdated;
- BOOLEAN FinishRetrieveCall;
- LIST_ENTRY FormHistoryList;
- LIST_ENTRY FormSetList;
-} BROWSER_CONTEXT;
-
-#define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE)
-
-//
-// Scope for get defaut value. It may be GetDefaultForNoStorage, GetDefaultForStorage or GetDefaultForAll.
-//
-typedef enum {
- GetDefaultForNoStorage, // Get default value for question which not has storage.
- GetDefaultForStorage, // Get default value for question which has storage.
- GetDefaultForAll, // Get default value for all questions.
- GetDefaultForMax // Invalid value.
-} BROWSER_GET_DEFAULT_VALUE;
-
-//
-// Get/set question value from/to.
-//
-typedef enum {
- GetSetValueWithEditBuffer = 0, // Get/Set question value from/to editbuffer in the storage.
- GetSetValueWithBuffer, // Get/Set question value from/to buffer in the storage.
- GetSetValueWithHiiDriver, // Get/Set question value from/to hii driver.
- GetSetValueWithBothBuffer, // Compare the editbuffer with buffer for this question, not use the question value.
- GetSetValueWithMax // Invalid value.
-} GET_SET_QUESTION_VALUE_WITH;
-
-extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
-extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
-extern EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
-extern EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
-
-extern BOOLEAN gCallbackReconnect;
-extern BOOLEAN gFlagReconnect;
-extern BOOLEAN gResetRequiredFormLevel;
-extern BOOLEAN gResetRequiredSystemLevel;
-extern BOOLEAN gExitRequired;
-extern LIST_ENTRY gBrowserFormSetList;
-extern LIST_ENTRY gBrowserHotKeyList;
-extern BROWSER_SETTING_SCOPE gBrowserSettingScope;
-extern EXIT_HANDLER ExitHandlerFunction;
-extern EFI_HII_HANDLE mCurrentHiiHandle;
-extern SETUP_DRIVER_PRIVATE_DATA mPrivateData;
-//
-// Browser Global Strings
-//
-extern CHAR16 *gEmptyString;
-
-extern UI_MENU_SELECTION *gCurrentSelection;
-extern BOOLEAN mHiiPackageListUpdated;
-extern UINT16 mCurFakeQestId;
-extern BOOLEAN mFinishRetrieveCall;
-
-//
-// Global Procedure Defines
-//
-#include "Expression.h"
-
-/**
- Initialize the HII String Token to the correct values.
-
-**/
-VOID
-InitializeBrowserStrings (
- VOID
- );
-
-/**
- Parse opcodes in the formset IFR binary.
-
- @param FormSet Pointer of the FormSet data structure.
-
- @retval EFI_SUCCESS Opcode parse success.
- @retval Other Opcode parse fail.
-
-**/
-EFI_STATUS
-ParseOpCodes (
- IN FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Free resources allocated for a FormSet.
-
- @param FormSet Pointer of the FormSet
-
-**/
-VOID
-DestroyFormSet (
- IN OUT FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Create a new string in HII Package List.
-
- @param String The String to be added
- @param HiiHandle The package list in the HII database to insert the
- specified string.
-
- @return The output string.
-
-**/
-EFI_STRING_ID
-NewString (
- IN CHAR16 *String,
- IN EFI_HII_HANDLE HiiHandle
- );
-
-/**
- Delete a string from HII Package List.
-
- @param StringId Id of the string in HII database.
- @param HiiHandle The HII package list handle.
-
- @retval EFI_SUCCESS The string was deleted successfully.
-
-**/
-EFI_STATUS
-DeleteString (
- IN EFI_STRING_ID StringId,
- IN EFI_HII_HANDLE HiiHandle
- );
-
-/**
- Get the string based on the StringId and HII Package List Handle.
-
- @param Token The String's ID.
- @param HiiHandle The package list in the HII database to search for
- the specified string.
-
- @return The output string.
-
-**/
-CHAR16 *
-GetToken (
- IN EFI_STRING_ID Token,
- IN EFI_HII_HANDLE HiiHandle
- );
-
-/**
- Get Value for given Name from a NameValue Storage.
-
- @param Storage The NameValue Storage.
- @param Name The Name.
- @param Value The retured Value.
- @param GetValueFrom Where to get source value, from EditValue or Value.
-
- @retval EFI_SUCCESS Value found for given Name.
- @retval EFI_NOT_FOUND No such Name found in NameValue storage.
-
-**/
-EFI_STATUS
-GetValueByName (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Name,
- IN OUT CHAR16 **Value,
- IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
- );
-
-/**
- Set Value of given Name in a NameValue Storage.
-
- @param Storage The NameValue Storage.
- @param Name The Name.
- @param Value The Value to set.
- @param SetValueTo Whether update editValue or Value.
- @param ReturnNode The node use the input name.
-
- @retval EFI_SUCCESS Value found for given Name.
- @retval EFI_NOT_FOUND No such Name found in NameValue storage.
-
-**/
-EFI_STATUS
-SetValueByName (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Name,
- IN CHAR16 *Value,
- IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
- OUT NAME_VALUE_NODE **ReturnNode
- );
-
-/**
- Validate whether this question's value has changed.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question Question to be initialized.
- @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
-
- @retval TRUE Question's value has changed.
- @retval FALSE Question's value has not changed
-
-**/
-BOOLEAN
-IsQuestionValueChanged (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
- );
-
-/**
- Validate the FormSet. If the formset is not validate, remove it from the list.
-
- @param FormSet The input FormSet which need to validate.
-
- @retval TRUE The handle is validate.
- @retval FALSE The handle is invalidate.
-
-**/
-BOOLEAN
-ValidateFormSet (
- FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Update the ValueChanged status for questions.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param SettingScope Setting Scope for Default action.
-
-**/
-VOID
-UpdateStatementStatus (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN BROWSER_SETTING_SCOPE SettingScope
- );
-
-/**
- Get Question's current Value.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question Question to be initialized.
- @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-GetQuestionValue (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
- );
-
-/**
- Save Question Value to edit copy(cached) or Storage(uncached).
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question Pointer to the Question.
- @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-SetQuestionValue (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN OUT FORM_BROWSER_STATEMENT *Question,
- IN GET_SET_QUESTION_VALUE_WITH SetValueTo
- );
-
-/**
- Perform inconsistent check for a Form.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question The Question to be validated.
- @param Type Validation type: InConsistent or NoSubmit
-
- @retval EFI_SUCCESS Form validation pass.
- @retval other Form validation failed.
-
-**/
-EFI_STATUS
-ValidateQuestion (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question,
- IN UINTN Type
- );
-
-/**
- Discard data based on the input setting scope (Form, FormSet or System).
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param SettingScope Setting Scope for Discard action.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-DiscardForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN BROWSER_SETTING_SCOPE SettingScope
- );
-
-/**
- Submit data based on the input Setting level (Form, FormSet or System).
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param SettingScope Setting Scope for Submit action.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-SubmitForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN BROWSER_SETTING_SCOPE SettingScope
- );
-
-/**
- Reset Question to its default value.
-
- @param FormSet The form set.
- @param Form The form.
- @param Question The question.
- @param DefaultId The Class of the default.
-
- @retval EFI_SUCCESS Question is reset to default value.
-
-**/
-EFI_STATUS
-GetQuestionDefault (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question,
- IN UINT16 DefaultId
- );
-
-/**
- Get current setting of Questions.
-
- @param FormSet FormSet data structure.
-
-**/
-VOID
-InitializeCurrentSetting (
- IN OUT FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Initialize the internal data structure of a FormSet.
-
- @param Handle PackageList Handle
- @param FormSetGuid GUID of a formset. If not specified (NULL or zero
- GUID), take the first FormSet found in package
- list.
- @param FormSet FormSet data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_NOT_FOUND The specified FormSet could not be found.
-
-**/
-EFI_STATUS
-InitializeFormSet (
- IN EFI_HII_HANDLE Handle,
- IN OUT EFI_GUID *FormSetGuid,
- OUT FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Reset Questions to their initial value or default value in a Form, Formset or System.
-
- GetDefaultValueScope parameter decides which questions will reset
- to its default value.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param DefaultId The Class of the default.
- @param SettingScope Setting Scope for Default action.
- @param GetDefaultValueScope Get default value scope.
- @param Storage Get default value only for this storage.
- @param RetrieveValueFirst Whether call the retrieve call back to
- get the initial value before get default
- value.
- @param SkipGetAltCfg Whether skip the get altcfg string process.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_UNSUPPORTED Unsupport SettingScope.
-
-**/
-EFI_STATUS
-ExtractDefault (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN UINT16 DefaultId,
- IN BROWSER_SETTING_SCOPE SettingScope,
- IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
- IN BROWSER_STORAGE *Storage,
- IN BOOLEAN RetrieveValueFirst,
- IN BOOLEAN SkipGetAltCfg
- );
-
-/**
- Initialize Question's Edit copy from Storage.
-
- @param Selection Selection contains the information about
- the Selection, form and formset to be displayed.
- Selection action may be updated in retrieve callback.
- If Selection is NULL, only initialize Question value.
- @param FormSet FormSet data structure.
- @param Form Form data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-LoadFormConfig (
- IN OUT UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
- );
-
-/**
- Initialize Question's Edit copy from Storage for the whole Formset.
-
- @param Selection Selection contains the information about
- the Selection, form and formset to be displayed.
- Selection action may be updated in retrieve callback.
- If Selection is NULL, only initialize Question value.
- @param FormSet FormSet data structure.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-LoadFormSetConfig (
- IN OUT UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
-
- @param Storage The Storage to be conveted.
- @param ConfigResp The returned <ConfigResp>.
- @param ConfigRequest The ConfigRequest string.
- @param GetEditBuf Get the data from editbuffer or buffer.
-
- @retval EFI_SUCCESS Convert success.
- @retval EFI_INVALID_PARAMETER Incorrect storage type.
-
-**/
-EFI_STATUS
-StorageToConfigResp (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 **ConfigResp,
- IN CHAR16 *ConfigRequest,
- IN BOOLEAN GetEditBuf
- );
-
-/**
- Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
-
- @param Storage The Storage to receive the settings.
- @param ConfigResp The <ConfigResp> to be converted.
-
- @retval EFI_SUCCESS Convert success.
- @retval EFI_INVALID_PARAMETER Incorrect storage type.
-
-**/
-EFI_STATUS
-ConfigRespToStorage (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *ConfigResp
- );
-
-/**
- Fill storage's edit copy with settings requested from Configuration Driver.
-
- @param FormSet FormSet data structure.
- @param Storage Buffer Storage.
-
-**/
-VOID
-LoadStorage (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORMSET_STORAGE *Storage
- );
-
-/**
- Fetch the Ifr binary data of a FormSet.
-
- @param Handle PackageList Handle
- @param FormSetGuid GUID of a formset. If not specified (NULL or zero
- GUID), take the first FormSet found in package
- list.
- @param BinaryLength The length of the FormSet IFR binary.
- @param BinaryData The buffer designed to receive the FormSet.
-
- @retval EFI_SUCCESS Buffer filled with the requested FormSet.
- BufferLength was updated.
- @retval EFI_INVALID_PARAMETER The handle is unknown.
- @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
- be found with the requested FormId.
-
-**/
-EFI_STATUS
-GetIfrBinaryData (
- IN EFI_HII_HANDLE Handle,
- IN OUT EFI_GUID *FormSetGuid,
- OUT UINTN *BinaryLength,
- OUT UINT8 **BinaryData
- );
-
-/**
- Save globals used by previous call to SendForm(). SendForm() may be called from
- HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
- So, save globals of previous call to SendForm() and restore them upon exit.
-
-**/
-VOID
-SaveBrowserContext (
- VOID
- );
-
-/**
- Restore globals used by previous call to SendForm().
-
-**/
-VOID
-RestoreBrowserContext (
- VOID
- );
-
-/**
- This is the routine which an external caller uses to direct the browser
- where to obtain it's information.
-
-
- @param This The Form Browser protocol instanse.
- @param Handles A pointer to an array of Handles. If HandleCount > 1 we
- display a list of the formsets for the handles specified.
- @param HandleCount The number of Handles specified in Handle.
- @param FormSetGuid This field points to the EFI_GUID which must match the Guid
- field in the EFI_IFR_FORM_SET op-code for the specified
- forms-based package. If FormSetGuid is NULL, then this
- function will display the first found forms package.
- @param FormId This field specifies which EFI_IFR_FORM to render as the first
- displayable page. If this field has a value of 0x0000, then
- the forms browser will render the specified forms in their encoded order.
- ScreenDimenions - This allows the browser to be called so that it occupies a
- portion of the physical screen instead of dynamically determining the screen dimensions.
- ActionRequest - Points to the action recommended by the form.
- @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
- characters.
- @param ActionRequest Points to the action recommended by the form.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_NOT_FOUND No valid forms could be found to display.
-
-**/
-EFI_STATUS
-EFIAPI
-SendForm (
- IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
- IN EFI_HII_HANDLE *Handles,
- IN UINTN HandleCount,
- IN EFI_GUID *FormSetGuid OPTIONAL,
- IN UINT16 FormId OPTIONAL,
- IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions OPTIONAL,
- OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL
- );
-
-/**
- This function is called by a callback handler to retrieve uncommitted state
- data from the browser.
-
- @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
- instance.
- @param ResultsDataSize A pointer to the size of the buffer associated
- with ResultsData.
- @param ResultsData A string returned from an IFR browser or
- equivalent. The results string will have no
- routing information in them.
- @param RetrieveData A BOOLEAN field which allows an agent to retrieve
- (if RetrieveData = TRUE) data from the uncommitted
- browser state information or set (if RetrieveData
- = FALSE) data in the uncommitted browser state
- information.
- @param VariableGuid An optional field to indicate the target variable
- GUID name to use.
- @param VariableName An optional field to indicate the target
- human-readable variable name.
-
- @retval EFI_SUCCESS The results have been distributed or are awaiting
- distribution.
- @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
- contain the results data.
-
-**/
-EFI_STATUS
-EFIAPI
-BrowserCallback (
- IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
- IN OUT UINTN *ResultsDataSize,
- IN OUT EFI_STRING ResultsData,
- IN BOOLEAN RetrieveData,
- IN CONST EFI_GUID *VariableGuid OPTIONAL,
- IN CONST CHAR16 *VariableName OPTIONAL
- );
-
-/**
- Find menu which will show next time.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
- @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
- else, we need to exit current formset.
-
- @retval TRUE Exit current form.
- @retval FALSE User press ESC and keep in current form.
-**/
-BOOLEAN
-FindNextMenu (
- IN OUT UI_MENU_SELECTION *Selection,
- IN BROWSER_SETTING_SCOPE SettingLevel
- );
-
-/**
- check whether the form need to update the NV.
-
- @param Form Form data structure.
-
- @retval TRUE Need to update the NV.
- @retval FALSE No need to update the NV.
-**/
-BOOLEAN
-IsNvUpdateRequiredForForm (
- IN FORM_BROWSER_FORM *Form
- );
-
-/**
- check whether the formset need to update the NV.
-
- @param FormSet FormSet data structure.
-
- @retval TRUE Need to update the NV.
- @retval FALSE No need to update the NV.
-**/
-BOOLEAN
-IsNvUpdateRequiredForFormSet (
- IN FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Call the call back function for the question and process the return action.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
- @param FormSet The formset this question belong to.
- @param Form The form this question belong to.
- @param Question The Question which need to call.
- @param Action The action request.
- @param SkipSaveOrDiscard Whether skip save or discard action.
-
- @retval EFI_SUCCESS The call back function executes successfully.
- @return Other value if the call back function failed to execute.
-**/
-EFI_STATUS
-ProcessCallBackFunction (
- IN OUT UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question,
- IN EFI_BROWSER_ACTION Action,
- IN BOOLEAN SkipSaveOrDiscard
- );
-
-/**
- Call the retrieve type call back function for one question to get the initialize data.
-
- This function only used when in the initialize stage, because in this stage, the
- Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
-
- @param ConfigAccess The config access protocol produced by the hii driver.
- @param Statement The Question which need to call.
- @param FormSet The formset this question belong to.
-
- @retval EFI_SUCCESS The call back function executes successfully.
- @return Other value if the call back function failed to execute.
-**/
-EFI_STATUS
-ProcessRetrieveForQuestion (
- IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
- IN FORM_BROWSER_STATEMENT *Statement,
- IN FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Find the matched FormSet context in the backup maintain list based on HiiHandle.
-
- @param Handle The Hii Handle.
-
- @return the found FormSet context. If no found, NULL will return.
-
-**/
-FORM_BROWSER_FORMSET *
-GetFormSetFromHiiHandle (
- EFI_HII_HANDLE Handle
- );
-
-/**
- Check whether the input HII handle is the FormSet that is being used.
-
- @param Handle The Hii Handle.
-
- @retval TRUE HII handle is being used.
- @retval FALSE HII handle is not being used.
-
-**/
-BOOLEAN
-IsHiiHandleInBrowserContext (
- EFI_HII_HANDLE Handle
- );
-
-/**
- Configure what scope the hot key will impact.
- All hot keys have the same scope. The mixed hot keys with the different level are not supported.
- If no scope is set, the default scope will be FormSet level.
- After all registered hot keys are removed, previous Scope can reset to another level.
-
- @param[in] Scope Scope level to be set.
-
- @retval EFI_SUCCESS Scope is set correctly.
- @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
- @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
-
-**/
-EFI_STATUS
-EFIAPI
-SetScope (
- IN BROWSER_SETTING_SCOPE Scope
- );
-
-/**
- Register the hot key with its browser action, or unregistered the hot key.
- Only support hot key that is not printable character (control key, function key, etc.).
- If the action value is zero, the hot key will be unregistered if it has been registered.
- If the same hot key has been registered, the new action and help string will override the previous ones.
-
- @param[in] KeyData A pointer to a buffer that describes the keystroke
- information for the hot key. Its type is EFI_INPUT_KEY to
- be supported by all ConsoleIn devices.
- @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
- @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
- @param[in] HelpString Help string that describes the hot key information.
- Its value may be NULL for the unregistered hot key.
-
- @retval EFI_SUCCESS Hot key is registered or unregistered.
- @retval EFI_INVALID_PARAMETER KeyData is NULL.
- @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
- @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
- @retval EFI_ALREADY_STARTED Key already been registered for one hot key.
-**/
-EFI_STATUS
-EFIAPI
-RegisterHotKey (
- IN EFI_INPUT_KEY *KeyData,
- IN UINT32 Action,
- IN UINT16 DefaultId,
- IN EFI_STRING HelpString OPTIONAL
- );
-
-/**
- Register Exit handler function.
- When more than one handler function is registered, the latter one will override the previous one.
- When NULL handler is specified, the previous Exit handler will be unregistered.
-
- @param[in] Handler Pointer to handler function.
-
-**/
-VOID
-EFIAPI
-RegiserExitHandler (
- IN EXIT_HANDLER Handler
- );
-
-/**
-
- Check whether the browser data has been modified.
-
- @retval TRUE Browser data is changed.
- @retval FALSE No browser data is changed.
-
-**/
-BOOLEAN
-EFIAPI
-IsBrowserDataModified (
- VOID
- );
-
-/**
-
- Execute the action requested by the Action parameter.
-
- @param[in] Action Execute the request action.
- @param[in] DefaultId The default Id info when need to load default value.
-
- @retval EFI_SUCCESS Execute the request action succss.
- @retval EFI_INVALID_PARAMETER The input action value is invalid.
-
-**/
-EFI_STATUS
-EFIAPI
-ExecuteAction (
- IN UINT32 Action,
- IN UINT16 DefaultId
- );
-
-/**
- Create reminder to let user to choose save or discard the changed browser data.
- Caller can use it to actively check the changed browser data.
-
- @retval BROWSER_NO_CHANGES No browser data is changed.
- @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
- @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
- @retval BROWSER_KEEP_CURRENT Browser keep current changes.
-
-**/
-UINT32
-EFIAPI
-SaveReminder (
- VOID
- );
-
-/**
- Check whether the Reset Required for the browser
-
- @retval TRUE Browser required to reset after exit.
- @retval FALSE Browser not need to reset after exit.
-
-**/
-BOOLEAN
-EFIAPI
-IsResetRequired (
- VOID
- );
-
-/**
- Find the registered HotKey based on KeyData.
-
- @param[in] KeyData A pointer to a buffer that describes the keystroke
- information for the hot key.
-
- @return The registered HotKey context. If no found, NULL will return.
-**/
-BROWSER_HOT_KEY *
-GetHotKeyFromRegisterList (
- IN EFI_INPUT_KEY *KeyData
- );
-
-/**
-
- Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
-
- @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
-
- @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
-
-**/
-FORM_BROWSER_STATEMENT *
-GetBrowserStatement (
- IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
- );
-
-/**
- Password may be stored as encrypted by Configuration Driver. When change a
- password, user will be challenged with old password. To validate user input old
- password, we will send the clear text to Configuration Driver via Callback().
- Configuration driver is responsible to check the passed in password and return
- the validation result. If validation pass, state machine in password Callback()
- will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
- After user type in new password twice, Callback() will be invoked to send the
- new password to Configuration Driver.
-
- @param Selection Pointer to UI_MENU_SELECTION.
- @param MenuOption The MenuOption for this password Question.
- @param String The clear text of password.
-
- @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
- @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
- @retval EFI_SUCCESS Password correct, Browser will prompt for new
- password.
- @retval EFI_NOT_READY Password incorrect, Browser will show error
- message.
- @retval Other Browser will do nothing.
- @return In state of BROWSER_STATE_SET_PASSWORD:
- @retval EFI_SUCCESS Set password success.
- @retval Other Set password failed.
-
-**/
-EFI_STATUS
-PasswordCallback (
- IN UI_MENU_SELECTION *Selection,
- IN FORM_BROWSER_STATEMENT *Question,
- IN CHAR16 *String
- );
-
-/**
- Display error message for invalid password.
-
-**/
-VOID
-PasswordInvalid (
- VOID
- );
-
-/**
- The worker function that send the displays to the screen. On output,
- the selection made by user is returned.
-
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
-
- @retval EFI_SUCCESS The page is displayed successfully.
- @return Other value if the page failed to be diplayed.
-
-**/
-EFI_STATUS
-SetupBrowser (
- IN OUT UI_MENU_SELECTION *Selection
- );
-
-/**
- Free up the resource allocated for all strings required
- by Setup Browser.
-
-**/
-VOID
-FreeBrowserStrings (
- VOID
- );
-
-/**
- Create a menu with specified formset GUID and form ID, and add it as a child
- of the given parent menu.
-
- @param HiiHandle Hii handle related to this formset.
- @param FormSetGuid The Formset Guid of menu to be added.
- @param FormId The Form ID of menu to be added.
- @param QuestionId The question id of this menu to be added.
-
- @return A pointer to the newly added menu or NULL if memory is insufficient.
-
-**/
-FORM_ENTRY_INFO *
-UiAddMenuList (
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_GUID *FormSetGuid,
- IN UINT16 FormId,
- IN UINT16 QuestionId
- );
-
-/**
- Search Menu with given FormSetGuid and FormId in all cached menu list.
-
- @param HiiHandle HiiHandle for FormSet.
- @param FormSetGuid The Formset GUID of the menu to search.
- @param FormId The Form ID of menu to search.
-
- @return A pointer to menu found or NULL if not found.
-
-**/
-FORM_ENTRY_INFO *
-UiFindMenuList (
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_GUID *FormSetGuid,
- IN UINT16 FormId
- );
-
-/**
- Free Menu list linked list.
-
- @param MenuListHead One Menu list point in the menu list.
-
-**/
-VOID
-UiFreeMenuList (
- LIST_ENTRY *MenuListHead
- );
-
-/**
- Find parent menu for current menu.
-
- @param CurrentMenu Current Menu
- @param SettingLevel Whether find parent menu in Form Level or Formset level.
- In form level, just find the parent menu;
- In formset level, find the parent menu which has different
- formset guid value.
-
- @retval The parent menu for current menu.
-**/
-FORM_ENTRY_INFO *
-UiFindParentMenu (
- IN FORM_ENTRY_INFO *CurrentMenu,
- IN BROWSER_SETTING_SCOPE SettingLevel
- );
-
-/**
- Validate the HiiHandle.
-
- @param HiiHandle The input HiiHandle which need to validate.
-
- @retval TRUE The handle is validate.
- @retval FALSE The handle is invalidate.
-
-**/
-BOOLEAN
-ValidateHiiHandle (
- EFI_HII_HANDLE HiiHandle
- );
-
-/**
- Copy current Menu list to the new menu list.
-
- @param NewMenuListHead New create Menu list.
- @param CurrentMenuListHead Current Menu list.
-
-**/
-VOID
-UiCopyMenuList (
- OUT LIST_ENTRY *NewMenuListHead,
- IN LIST_ENTRY *CurrentMenuListHead
- );
-
-/**
- Search an Option of a Question by its value.
-
- @param Question The Question
- @param OptionValue Value for Option to be searched.
-
- @retval Pointer Pointer to the found Option.
- @retval NULL Option not found.
-
-**/
-QUESTION_OPTION *
-ValueToOption (
- IN FORM_BROWSER_STATEMENT *Question,
- IN EFI_HII_VALUE *OptionValue
- );
-
-/**
- Return data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
-
- @retval Value The data to be returned
-
-**/
-UINT64
-GetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index
- );
-
-/**
- Set value of a data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
- @param Value The value to be set.
-
-**/
-VOID
-SetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index,
- IN UINT64 Value
- );
-
-/**
- Compare two Hii value.
-
- @param Value1 Expression value to compare on left-hand.
- @param Value2 Expression value to compare on right-hand.
- @param Result Return value after compare.
- retval 0 Two operators equal.
- return Positive value if Value1 is greater than Value2.
- retval Negative value if Value1 is less than Value2.
- @param HiiHandle Only required for string compare.
-
- @retval other Could not perform compare on two values.
- @retval EFI_SUCCESS Compare the value success.
-
-**/
-EFI_STATUS
-CompareHiiValue (
- IN EFI_HII_VALUE *Value1,
- IN EFI_HII_VALUE *Value2,
- OUT INTN *Result,
- IN EFI_HII_HANDLE HiiHandle OPTIONAL
- );
-
-/**
- Perform Password check.
- Passwork may be encrypted by driver that requires the specific check.
-
- @param Form Form where Password Statement is in.
- @param Statement Password statement
- @param PasswordString Password string to be checked. It may be NULL.
- NULL means to restore password.
- "" string can be used to checked whether old password does exist.
-
- @return Status Status of Password check.
-**/
-EFI_STATUS
-EFIAPI
-PasswordCheck (
- IN FORM_DISPLAY_ENGINE_FORM *Form,
- IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
- IN EFI_STRING PasswordString OPTIONAL
- );
-
-/**
-
- Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
-
- @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
-
- @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
-
-**/
-FORM_BROWSER_STATEMENT *
-GetBrowserStatement (
- IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
- );
-
-/**
-
- Initialize the Display form structure data.
-
-**/
-VOID
-InitializeDisplayFormData (
- VOID
- );
-
-/**
- Base on the current formset info, clean the ConfigRequest string in browser storage.
-
- @param FormSet Pointer of the FormSet
-
-**/
-VOID
-CleanBrowserStorage (
- IN OUT FORM_BROWSER_FORMSET *FormSet
- );
-
-/**
- Find HII Handle in the HII database associated with given Device Path.
-
- If DevicePath is NULL, then ASSERT.
-
- @param DevicePath Device Path associated with the HII package list
- handle.
- @param FormsetGuid The formset guid for this formset.
-
- @retval Handle HII package list Handle associated with the Device
- Path.
- @retval NULL Hii Package list handle is not found.
-
-**/
-EFI_HII_HANDLE
-DevicePathToHiiHandle (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- IN EFI_GUID *FormsetGuid
- );
-
-/**
- Adjust the config request info, remove the request elements which already in AllConfigRequest string.
-
- @param Storage Form set Storage.
- @param Request The input request string.
- @param RespString Whether the input is ConfigRequest or ConfigResp format.
-
- @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
- @retval FALSE All elements covered by current used elements.
-
-**/
-BOOLEAN
-ConfigRequestAdjust (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Request,
- IN BOOLEAN RespString
- );
-
-/**
- Perform question check.
-
- If one question has more than one check, process form high priority to low.
-
- @param FormSet FormSet data structure.
- @param Form Form data structure.
- @param Question The Question to be validated.
-
- @retval EFI_SUCCESS Form validation pass.
- @retval other Form validation failed.
-
-**/
-EFI_STATUS
-ValueChangedValidation (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form,
- IN FORM_BROWSER_STATEMENT *Question
- );
-
-/**
- Pop up the error info.
-
- @param BrowserStatus The input browser status.
- @param HiiHandle The HiiHandle for this error opcode.
- @param OpCode The opcode use to get the erro info and timeout value.
- @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF.
-
-**/
-UINT32
-PopupErrorMessage (
- IN UINT32 BrowserStatus,
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_IFR_OP_HEADER *OpCode OPTIONAL,
- IN CHAR16 *ErrorString
- );
-
-/**
- Check whether the result is TRUE or FALSE.
-
- For the EFI_HII_VALUE value type is numeric, return TRUE if the
- value is not 0.
-
- @param Result Input the result data.
-
- @retval TRUE The result is TRUE.
- @retval FALSE The result is FALSE.
-
-**/
-BOOLEAN
-IsTrue (
- IN EFI_HII_VALUE *Result
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-/**
- Reconnect the controller.
-
- @param DriverHandle The controller handle which need to be reconnect.
-
- @retval TRUE do the reconnect behavior success.
- @retval FALSE do the reconnect behavior failed.
-
-**/
-BOOLEAN
-ReconnectController (
- IN EFI_HANDLE DriverHandle
- );
-
-/**
- Converts the unicode character of the string from uppercase to lowercase.
- This is a internal function.
-
- @param ConfigString String to be converted
-
-**/
-VOID
-EFIAPI
-HiiToLower (
- IN EFI_STRING ConfigString
- );
-
-#endif
+/** @file +Private MACRO, structure and function definitions for Setup Browser module. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#ifndef _SETUP_H_ +#define _SETUP_H_ + +#include <PiDxe.h> + +#include <Protocol/SimpleTextOut.h> +#include <Protocol/SimpleTextIn.h> +#include <Protocol/FormBrowser2.h> +#include <Protocol/FormBrowserEx2.h> +#include <Protocol/DisplayProtocol.h> +#include <Protocol/DevicePath.h> +#include <Protocol/UnicodeCollation.h> +#include <Protocol/HiiConfigAccess.h> +#include <Protocol/HiiConfigRouting.h> +#include <Protocol/HiiDatabase.h> +#include <Protocol/HiiString.h> +#include <Protocol/UserManager.h> +#include <Protocol/DevicePathFromText.h> +#include <Protocol/RegularExpressionProtocol.h> + +#include <Guid/MdeModuleHii.h> +#include <Guid/HiiPlatformSetupFormset.h> +#include <Guid/HiiFormMapMethodGuid.h> +#include <Guid/ZeroGuid.h> + +#include <Library/PrintLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HiiLib.h> +#include <Library/PcdLib.h> +#include <Library/DevicePathLib.h> +#include <Library/UefiLib.h> + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// + +#define UI_ACTION_NONE 0 +#define UI_ACTION_REFRESH_FORM 1 +#define UI_ACTION_REFRESH_FORMSET 2 +#define UI_ACTION_EXIT 3 + +// +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// Incremental string lenght of ConfigRequest +// +#define CONFIG_REQUEST_STRING_INCREMENTAL 1024 + +// +// Incremental size of stack for expression +// +#define EXPRESSION_STACK_SIZE_INCREMENT 0x100 + +#define EFI_IFR_SPECIFICATION_VERSION (UINT16) (((EFI_SYSTEM_TABLE_REVISION >> 16) << 8) | (((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) / 10) << 4) | ((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) % 10)) + +#define SETUP_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'B', 'D', 'V') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol + // + EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + EDKII_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx; + + EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL FormBrowserEx2; +} SETUP_DRIVER_PRIVATE_DATA; + +// +// IFR relative definition +// +#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 +#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 +#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 +#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 +#define EFI_HII_EXPRESSION_DISABLE_IF 4 +#define EFI_HII_EXPRESSION_VALUE 5 +#define EFI_HII_EXPRESSION_RULE 6 +#define EFI_HII_EXPRESSION_READ 7 +#define EFI_HII_EXPRESSION_WRITE 8 +#define EFI_HII_EXPRESSION_WARNING_IF 9 + +#define EFI_HII_VARSTORE_BUFFER 0 +#define EFI_HII_VARSTORE_NAME_VALUE 1 +#define EFI_HII_VARSTORE_EFI_VARIABLE 2 // EFI Varstore type follow UEFI spec before 2.3.1. +#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3 // EFI varstore type follow UEFI spec 2.3.1 and later. + +#define FORM_INCONSISTENT_VALIDATION 0 +#define FORM_NO_SUBMIT_VALIDATION 1 + +#define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + CHAR16 *Name; + CHAR16 *Value; + CHAR16 *EditValue; +} NAME_VALUE_NODE; + +#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE) + +#define BROWSER_STORAGE_SIGNATURE SIGNATURE_32 ('B', 'S', 'T', 'G') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Storage type + + BOOLEAN Initialized; // Whether this varstore is initialized, efi varstore not used. + + EFI_HII_HANDLE HiiHandle; // HiiHandle for this varstore, efi varstore not used. + EFI_GUID Guid; + + CHAR16 *Name; // For EFI_IFR_VARSTORE + UINT16 Size; + UINT8 *Buffer; + UINT8 *EditBuffer; // Edit copy for Buffer Storage + + LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE + + UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute + + CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement> + // <RequestElement> includes all fields which is used by current form sets. + UINTN SpareStrLen; // Spare length of ConfigRequest string buffer +} BROWSER_STORAGE; + +#define BROWSER_STORAGE_FROM_LINK(a) CR (a, BROWSER_STORAGE, Link, BROWSER_STORAGE_SIGNATURE) + +#define FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'G') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + LIST_ENTRY SaveFailLink; + + UINT16 VarStoreId; + + BROWSER_STORAGE *BrowserStorage; + + CHAR16 *ConfigHdr; // <ConfigHdr> + + CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement> + CHAR16 *ConfigAltResp; // Alt config response string for this ConfigRequest. + BOOLEAN HasCallAltCfg; // Flag to show whether browser has call ExtractConfig to get Altcfg string. + UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest> + UINTN SpareStrLen; // Spare length of ConfigRequest string buffer + CHAR16 *RestoreConfigRequest; // When submit formset fail, the element need to be restored + CHAR16 *SyncConfigRequest; // When submit formset fail, the element need to be synced +} FORMSET_STORAGE; + +#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE) +#define FORMSET_STORAGE_FROM_SAVE_FAIL_LINK(a) CR (a, FORMSET_STORAGE, SaveFailLink, FORMSET_STORAGE_SIGNATURE) + +typedef union { + EFI_STRING_ID VarName; + UINT16 VarOffset; +} VAR_STORE_INFO; + +#define EXPRESSION_OPCODE_SIGNATURE SIGNATURE_32 ('E', 'X', 'O', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; + + UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND + UINT8 Flags; // For EFI_IFR_SPAN + UINT8 RuleId; // For EFI_IFR_RULE_REF + + EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1 + + EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_VAL_LIST, EFI_IFR_QUESTION_REF1 + EFI_QUESTION_ID QuestionId2; + + UINT16 ListLength; // For EFI_IFR_EQ_ID_VAL_LIST + UINT16 *ValueList; + + EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3 + EFI_GUID Guid; + + BROWSER_STORAGE *VarStorage; // For EFI_IFR_SET, EFI_IFR_GET + VAR_STORE_INFO VarStoreInfo; // For EFI_IFR_SET, EFI_IFR_GET + UINT8 ValueType; // For EFI_IFR_SET, EFI_IFR_GET + UINT8 ValueWidth; // For EFI_IFR_SET, EFI_IFR_GET + CHAR16 *ValueName; // For EFI_IFR_SET, EFI_IFR_GET + LIST_ENTRY MapExpressionList; // nested expressions inside of Map opcode. +} EXPRESSION_OPCODE; + +#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE) + +#define FORM_EXPRESSION_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Type for this expression + + UINT8 RuleId; // For EFI_IFR_RULE only + EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only + + EFI_HII_VALUE Result; // Expression evaluation result + + UINT8 TimeOut; // For EFI_IFR_WARNING_IF + EFI_IFR_OP_HEADER *OpCode; // Save the opcode buffer. + + LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE) +} FORM_EXPRESSION; + +#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE) + +#define FORM_EXPRESSION_LIST_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'R') + +typedef struct { + UINTN Signature; + UINTN Count; + FORM_EXPRESSION *Expression[1]; // Array[Count] of expressions +} FORM_EXPRESSION_LIST; + +#define QUESTION_DEFAULT_SIGNATURE SIGNATURE_32 ('Q', 'D', 'F', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_HII_VALUE Value; // Default value + + FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE +} QUESTION_DEFAULT; + +#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE) + +#define QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_IFR_ONE_OF_OPTION *OpCode; // OneOfOption Data + + EFI_STRING_ID Text; + UINT8 Flags; + EFI_HII_VALUE Value; + EFI_IMAGE_ID ImageId; + + FORM_EXPRESSION_LIST *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf +} QUESTION_OPTION; + +#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE) + +typedef enum { + ExpressFalse = 0, + ExpressGrayOut, + ExpressSuppress, + ExpressDisable +} EXPRESS_RESULT; + +typedef enum { + ExpressNone = 0, + ExpressForm, + ExpressStatement, + ExpressOption +} EXPRESS_LEVEL; + +typedef struct _FORM_BROWSER_STATEMENT FORM_BROWSER_STATEMENT; + +#define FORM_BROWSER_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A') + +struct _FORM_BROWSER_STATEMENT { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; // The operand (first byte) of this Statement or Question + EFI_IFR_OP_HEADER *OpCode; + + // + // Statement Header + // + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; + EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT + + // + // Fake Question Id, used for statement not has true QuestionId. + // + EFI_QUESTION_ID FakeQuestionId; + + // + // Question Header + // + EFI_QUESTION_ID QuestionId; // The value of zero is reserved + EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage + BROWSER_STORAGE *Storage; + VAR_STORE_INFO VarStoreInfo; + UINT16 StorageWidth; + UINT16 BitStorageWidth; + UINT16 BitVarOffset; + UINT8 QuestionFlags; + BOOLEAN QuestionReferToBitField; // Whether the question is stored in a bit field. + CHAR16 *VariableName; // Name/Value or EFI Variable name + CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..." + + EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof + UINT8 *BufferValue; // Edit copy for string, password, orderedlist + UINT8 ValueType; // Data type for orderedlist value array + + // + // OpCode specific members + // + UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF, + // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER + UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST + + UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number + EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed + + UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value + UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length + UINT64 Step; + + EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON + EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID + BOOLEAN Locked; // Whether this statement is locked. + BOOLEAN ValueChanged; // Whether this statement's value is changed. + // + // Get from IFR parsing + // + FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly + LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values + LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION) + + EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE + UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh + + FORM_BROWSER_STATEMENT *ParentStatement; + + LIST_ENTRY InconsistentListHead; // nested inconsistent expression list (FORM_EXPRESSION) + LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION) + LIST_ENTRY WarningListHead; // nested warning expression list (FORM_EXPRESSION) + FORM_EXPRESSION_LIST *Expression; // nesting inside of GrayOutIf/DisableIf/SuppressIf + + FORM_EXPRESSION *ReadExpression; // nested EFI_IFR_READ, provide this question value by read expression. + FORM_EXPRESSION *WriteExpression; // nested EFI_IFR_WRITE, evaluate write expression after this question value is set. +}; + +#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE) + +#define FORM_BROWSER_CONFIG_REQUEST_SIGNATURE SIGNATURE_32 ('F', 'C', 'R', 'S') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + LIST_ENTRY SaveFailLink; + + CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement> + CHAR16 *ConfigAltResp; // Alt config response string for this ConfigRequest. + UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest> + UINTN SpareStrLen; + CHAR16 *RestoreConfigRequest; // When submit form fail, the element need to be restored + CHAR16 *SyncConfigRequest; // When submit form fail, the element need to be synced + + BROWSER_STORAGE *Storage; +} FORM_BROWSER_CONFIG_REQUEST; +#define FORM_BROWSER_CONFIG_REQUEST_FROM_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, Link, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE) +#define FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, SaveFailLink, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE) + +#define FORM_BROWSER_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M') +#define STANDARD_MAP_FORM_TYPE 0x01 + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 FormId; // FormId of normal form or formmap form. + EFI_STRING_ID FormTitle; // FormTile of normal form, or FormMapMethod title of formmap form. + UINT16 FormType; // Specific form type for the different form. + + EFI_IMAGE_ID ImageId; + + BOOLEAN ModalForm; // Whether this is a modal form. + BOOLEAN Locked; // Whether this form is locked. + EFI_GUID RefreshGuid; // Form refresh event guid. + + LIST_ENTRY FormViewListHead; // List of type FORMID_INFO is Browser View Form History List. + LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) + LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) + LIST_ENTRY ConfigRequestHead; // List of configreques for all storage. + FORM_EXPRESSION_LIST *SuppressExpression; // nesting inside of SuppressIf +} FORM_BROWSER_FORM; + +#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE) + +#define FORMSET_DEFAULTSTORE_SIGNATURE SIGNATURE_32 ('F', 'D', 'F', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_STRING_ID DefaultName; +} FORMSET_DEFAULTSTORE; + +#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE) + +#define FORM_BROWSER_FORMSET_SIGNATURE SIGNATURE_32 ('F', 'B', 'F', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + LIST_ENTRY SaveFailLink; + + EFI_HII_HANDLE HiiHandle; // unique id for formset. + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + UINTN IfrBinaryLength; + UINT8 *IfrBinaryData; + + BOOLEAN QuestionInited; // Have finished question initilization? + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; + UINT8 NumberOfClassGuid; + EFI_GUID ClassGuid[3]; // Up to three ClassGuid + UINT16 Class; // Tiano extended Class code + UINT16 SubClass; // Tiano extended Subclass code + EFI_IMAGE_ID ImageId; + EFI_IFR_OP_HEADER *OpCode; // mainly for formset op to get ClassGuid + + FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions + EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode + FORM_BROWSER_FORM *SaveFailForm; // The form which failed to save. + FORM_BROWSER_STATEMENT *SaveFailStatement; // The Statement which failed to save. + + LIST_ENTRY StatementListOSF; // Statement list out side of the form. + LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) + LIST_ENTRY SaveFailStorageListHead; // Storage list for the save fail storage. + LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) + LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) + LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) +} FORM_BROWSER_FORMSET; +#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE) + +#define FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_FORMSET, SaveFailLink, FORM_BROWSER_FORMSET_SIGNATURE) + +typedef struct { + LIST_ENTRY Link; + EFI_EVENT RefreshEvent; +} FORM_BROWSER_REFRESH_EVENT_NODE; + +#define FORM_BROWSER_REFRESH_EVENT_FROM_LINK(a) BASE_CR (a, FORM_BROWSER_REFRESH_EVENT_NODE, Link) + +typedef struct { + EFI_HII_HANDLE Handle; + + // + // Target formset/form/Question information + // + EFI_GUID FormSetGuid; + UINT16 FormId; + UINT16 QuestionId; + UINTN Sequence; // used for time/date only. + + UINTN TopRow; + UINTN BottomRow; + UINTN PromptCol; + UINTN OptionCol; + UINTN CurrentRow; + + // + // Ation for Browser to taken: + // UI_ACTION_NONE - navigation inside a form + // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form + // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary + // + UINTN Action; + + // + // Current selected fomset/form/Question + // + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Statement; + + // + // Whether the Form is editable + // + BOOLEAN FormEditable; + + FORM_ENTRY_INFO *CurrentMenu; +} UI_MENU_SELECTION; + +#define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + // + // Globals defined in Setup.c + // + BOOLEAN FlagReconnect; + BOOLEAN CallbackReconnect; + BOOLEAN ResetRequired; + BOOLEAN ExitRequired; + EFI_HII_HANDLE HiiHandle; + EFI_GUID FormSetGuid; + EFI_FORM_ID FormId; + UI_MENU_SELECTION *Selection; + FORM_BROWSER_FORMSET *SystemLevelFormSet; + EFI_QUESTION_ID CurFakeQestId; + BOOLEAN HiiPackageListUpdated; + BOOLEAN FinishRetrieveCall; + LIST_ENTRY FormHistoryList; + LIST_ENTRY FormSetList; +} BROWSER_CONTEXT; + +#define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE) + +// +// Scope for get defaut value. It may be GetDefaultForNoStorage, GetDefaultForStorage or GetDefaultForAll. +// +typedef enum { + GetDefaultForNoStorage, // Get default value for question which not has storage. + GetDefaultForStorage, // Get default value for question which has storage. + GetDefaultForAll, // Get default value for all questions. + GetDefaultForMax // Invalid value. +} BROWSER_GET_DEFAULT_VALUE; + +// +// Get/set question value from/to. +// +typedef enum { + GetSetValueWithEditBuffer = 0, // Get/Set question value from/to editbuffer in the storage. + GetSetValueWithBuffer, // Get/Set question value from/to buffer in the storage. + GetSetValueWithHiiDriver, // Get/Set question value from/to hii driver. + GetSetValueWithBothBuffer, // Compare the editbuffer with buffer for this question, not use the question value. + GetSetValueWithMax // Invalid value. +} GET_SET_QUESTION_VALUE_WITH; + +extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; +extern EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText; +extern EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay; + +extern BOOLEAN gCallbackReconnect; +extern BOOLEAN gFlagReconnect; +extern BOOLEAN gResetRequiredFormLevel; +extern BOOLEAN gResetRequiredSystemLevel; +extern BOOLEAN gExitRequired; +extern LIST_ENTRY gBrowserFormSetList; +extern LIST_ENTRY gBrowserHotKeyList; +extern BROWSER_SETTING_SCOPE gBrowserSettingScope; +extern EXIT_HANDLER ExitHandlerFunction; +extern EFI_HII_HANDLE mCurrentHiiHandle; +extern SETUP_DRIVER_PRIVATE_DATA mPrivateData; +// +// Browser Global Strings +// +extern CHAR16 *gEmptyString; + +extern UI_MENU_SELECTION *gCurrentSelection; +extern BOOLEAN mHiiPackageListUpdated; +extern UINT16 mCurFakeQestId; +extern BOOLEAN mFinishRetrieveCall; + +// +// Global Procedure Defines +// +#include "Expression.h" + +/** + Initialize the HII String Token to the correct values. + +**/ +VOID +InitializeBrowserStrings ( + VOID + ); + +/** + Parse opcodes in the formset IFR binary. + + @param FormSet Pointer of the FormSet data structure. + + @retval EFI_SUCCESS Opcode parse success. + @retval Other Opcode parse fail. + +**/ +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ); + +/** + Free resources allocated for a FormSet. + + @param FormSet Pointer of the FormSet + +**/ +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ); + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ); + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ); + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ); + +/** + Get Value for given Name from a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The retured Value. + @param GetValueFrom Where to get source value, from EditValue or Value. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +GetValueByName ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Name, + IN OUT CHAR16 **Value, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ); + +/** + Set Value of given Name in a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The Value to set. + @param SetValueTo Whether update editValue or Value. + @param ReturnNode The node use the input name. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +SetValueByName ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value, + IN GET_SET_QUESTION_VALUE_WITH SetValueTo, + OUT NAME_VALUE_NODE **ReturnNode + ); + +/** + Validate whether this question's value has changed. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. + + @retval TRUE Question's value has changed. + @retval FALSE Question's value has not changed + +**/ +BOOLEAN +IsQuestionValueChanged ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ); + +/** + Validate the FormSet. If the formset is not validate, remove it from the list. + + @param FormSet The input FormSet which need to validate. + + @retval TRUE The handle is validate. + @retval FALSE The handle is invalidate. + +**/ +BOOLEAN +ValidateFormSet ( + FORM_BROWSER_FORMSET *FormSet + ); + +/** + Update the ValueChanged status for questions. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param SettingScope Setting Scope for Default action. + +**/ +VOID +UpdateStatementStatus ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN BROWSER_SETTING_SCOPE SettingScope + ); + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH GetValueFrom + ); + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param SetValueTo Update the question value to editbuffer , buffer or hii driver. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN GET_SET_QUESTION_VALUE_WITH SetValueTo + ); + +/** + Perform inconsistent check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: InConsistent or NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ); + +/** + Discard data based on the input setting scope (Form, FormSet or System). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param SettingScope Setting Scope for Discard action. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +DiscardForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN BROWSER_SETTING_SCOPE SettingScope + ); + +/** + Submit data based on the input Setting level (Form, FormSet or System). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param SettingScope Setting Scope for Submit action. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN BROWSER_SETTING_SCOPE SettingScope + ); + +/** + Reset Question to its default value. + + @param FormSet The form set. + @param Form The form. + @param Question The question. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ); + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + +**/ +VOID +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ); + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ); + +/** + Reset Questions to their initial value or default value in a Form, Formset or System. + + GetDefaultValueScope parameter decides which questions will reset + to its default value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param DefaultId The Class of the default. + @param SettingScope Setting Scope for Default action. + @param GetDefaultValueScope Get default value scope. + @param Storage Get default value only for this storage. + @param RetrieveValueFirst Whether call the retrieve call back to + get the initial value before get default + value. + @param SkipGetAltCfg Whether skip the get altcfg string process. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. + +**/ +EFI_STATUS +ExtractDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId, + IN BROWSER_SETTING_SCOPE SettingScope, + IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope, + IN BROWSER_STORAGE *Storage, + IN BOOLEAN RetrieveValueFirst, + IN BOOLEAN SkipGetAltCfg + ); + +/** + Initialize Question's Edit copy from Storage. + + @param Selection Selection contains the information about + the Selection, form and formset to be displayed. + Selection action may be updated in retrieve callback. + If Selection is NULL, only initialize Question value. + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN OUT UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ); + +/** + Initialize Question's Edit copy from Storage for the whole Formset. + + @param Selection Selection contains the information about + the Selection, form and formset to be displayed. + Selection action may be updated in retrieve callback. + If Selection is NULL, only initialize Question value. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormSetConfig ( + IN OUT UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_FORMSET *FormSet + ); + +/** + Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>. + + @param Storage The Storage to be conveted. + @param ConfigResp The returned <ConfigResp>. + @param ConfigRequest The ConfigRequest string. + @param GetEditBuf Get the data from editbuffer or buffer. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 **ConfigResp, + IN CHAR16 *ConfigRequest, + IN BOOLEAN GetEditBuf + ); + +/** + Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The <ConfigResp> to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *ConfigResp + ); + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + +**/ +VOID +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ); + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ); + +/** + Save globals used by previous call to SendForm(). SendForm() may be called from + HiiConfigAccess.Callback(), this will cause SendForm() be reentried. + So, save globals of previous call to SendForm() and restore them upon exit. + +**/ +VOID +SaveBrowserContext ( + VOID + ); + +/** + Restore globals used by previous call to SendForm(). + +**/ +VOID +RestoreBrowserContext ( + VOID + ); + +/** + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + + + @param This The Form Browser protocol instanse. + @param Handles A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + @param HandleCount The number of Handles specified in Handle. + @param FormSetGuid This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + @param FormId This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + ScreenDimenions - This allows the browser to be called so that it occupies a + portion of the physical screen instead of dynamically determining the screen dimensions. + ActionRequest - Points to the action recommended by the form. + @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in + characters. + @param ActionRequest Points to the action recommended by the form. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_NOT_FOUND No valid forms could be found to display. + +**/ +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid OPTIONAL, + IN UINT16 FormId OPTIONAL, + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions OPTIONAL, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ); + +/** + This function is called by a callback handler to retrieve uncommitted state + data from the browser. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid OPTIONAL, + IN CONST CHAR16 *VariableName OPTIONAL + ); + +/** + Find menu which will show next time. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + @param SettingLevel Input Settting level, if it is FormLevel, just exit current form. + else, we need to exit current formset. + + @retval TRUE Exit current form. + @retval FALSE User press ESC and keep in current form. +**/ +BOOLEAN +FindNextMenu ( + IN OUT UI_MENU_SELECTION *Selection, + IN BROWSER_SETTING_SCOPE SettingLevel + ); + +/** + check whether the form need to update the NV. + + @param Form Form data structure. + + @retval TRUE Need to update the NV. + @retval FALSE No need to update the NV. +**/ +BOOLEAN +IsNvUpdateRequiredForForm ( + IN FORM_BROWSER_FORM *Form + ); + +/** + check whether the formset need to update the NV. + + @param FormSet FormSet data structure. + + @retval TRUE Need to update the NV. + @retval FALSE No need to update the NV. +**/ +BOOLEAN +IsNvUpdateRequiredForFormSet ( + IN FORM_BROWSER_FORMSET *FormSet + ); + +/** + Call the call back function for the question and process the return action. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + @param FormSet The formset this question belong to. + @param Form The form this question belong to. + @param Question The Question which need to call. + @param Action The action request. + @param SkipSaveOrDiscard Whether skip save or discard action. + + @retval EFI_SUCCESS The call back function executes successfully. + @return Other value if the call back function failed to execute. +**/ +EFI_STATUS +ProcessCallBackFunction ( + IN OUT UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_BROWSER_ACTION Action, + IN BOOLEAN SkipSaveOrDiscard + ); + +/** + Call the retrieve type call back function for one question to get the initialize data. + + This function only used when in the initialize stage, because in this stage, the + Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead. + + @param ConfigAccess The config access protocol produced by the hii driver. + @param Statement The Question which need to call. + @param FormSet The formset this question belong to. + + @retval EFI_SUCCESS The call back function executes successfully. + @return Other value if the call back function failed to execute. +**/ +EFI_STATUS +ProcessRetrieveForQuestion ( + IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess, + IN FORM_BROWSER_STATEMENT *Statement, + IN FORM_BROWSER_FORMSET *FormSet + ); + +/** + Find the matched FormSet context in the backup maintain list based on HiiHandle. + + @param Handle The Hii Handle. + + @return the found FormSet context. If no found, NULL will return. + +**/ +FORM_BROWSER_FORMSET * +GetFormSetFromHiiHandle ( + EFI_HII_HANDLE Handle + ); + +/** + Check whether the input HII handle is the FormSet that is being used. + + @param Handle The Hii Handle. + + @retval TRUE HII handle is being used. + @retval FALSE HII handle is not being used. + +**/ +BOOLEAN +IsHiiHandleInBrowserContext ( + EFI_HII_HANDLE Handle + ); + +/** + Configure what scope the hot key will impact. + All hot keys have the same scope. The mixed hot keys with the different level are not supported. + If no scope is set, the default scope will be FormSet level. + After all registered hot keys are removed, previous Scope can reset to another level. + + @param[in] Scope Scope level to be set. + + @retval EFI_SUCCESS Scope is set correctly. + @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. + @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. + +**/ +EFI_STATUS +EFIAPI +SetScope ( + IN BROWSER_SETTING_SCOPE Scope + ); + +/** + Register the hot key with its browser action, or unregistered the hot key. + Only support hot key that is not printable character (control key, function key, etc.). + If the action value is zero, the hot key will be unregistered if it has been registered. + If the same hot key has been registered, the new action and help string will override the previous ones. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. Its type is EFI_INPUT_KEY to + be supported by all ConsoleIn devices. + @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. + @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. + @param[in] HelpString Help string that describes the hot key information. + Its value may be NULL for the unregistered hot key. + + @retval EFI_SUCCESS Hot key is registered or unregistered. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + @retval EFI_NOT_FOUND KeyData is not found to be unregistered. + @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. + @retval EFI_ALREADY_STARTED Key already been registered for one hot key. +**/ +EFI_STATUS +EFIAPI +RegisterHotKey ( + IN EFI_INPUT_KEY *KeyData, + IN UINT32 Action, + IN UINT16 DefaultId, + IN EFI_STRING HelpString OPTIONAL + ); + +/** + Register Exit handler function. + When more than one handler function is registered, the latter one will override the previous one. + When NULL handler is specified, the previous Exit handler will be unregistered. + + @param[in] Handler Pointer to handler function. + +**/ +VOID +EFIAPI +RegiserExitHandler ( + IN EXIT_HANDLER Handler + ); + +/** + + Check whether the browser data has been modified. + + @retval TRUE Browser data is changed. + @retval FALSE No browser data is changed. + +**/ +BOOLEAN +EFIAPI +IsBrowserDataModified ( + VOID + ); + +/** + + Execute the action requested by the Action parameter. + + @param[in] Action Execute the request action. + @param[in] DefaultId The default Id info when need to load default value. + + @retval EFI_SUCCESS Execute the request action succss. + @retval EFI_INVALID_PARAMETER The input action value is invalid. + +**/ +EFI_STATUS +EFIAPI +ExecuteAction ( + IN UINT32 Action, + IN UINT16 DefaultId + ); + +/** + Create reminder to let user to choose save or discard the changed browser data. + Caller can use it to actively check the changed browser data. + + @retval BROWSER_NO_CHANGES No browser data is changed. + @retval BROWSER_SAVE_CHANGES The changed browser data is saved. + @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. + @retval BROWSER_KEEP_CURRENT Browser keep current changes. + +**/ +UINT32 +EFIAPI +SaveReminder ( + VOID + ); + +/** + Check whether the Reset Required for the browser + + @retval TRUE Browser required to reset after exit. + @retval FALSE Browser not need to reset after exit. + +**/ +BOOLEAN +EFIAPI +IsResetRequired ( + VOID + ); + +/** + Find the registered HotKey based on KeyData. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. + + @return The registered HotKey context. If no found, NULL will return. +**/ +BROWSER_HOT_KEY * +GetHotKeyFromRegisterList ( + IN EFI_INPUT_KEY *KeyData + ); + +/** + + Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. + + @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. + + @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. + +**/ +FORM_BROWSER_STATEMENT * +GetBrowserStatement ( + IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement + ); + +/** + Password may be stored as encrypted by Configuration Driver. When change a + password, user will be challenged with old password. To validate user input old + password, we will send the clear text to Configuration Driver via Callback(). + Configuration driver is responsible to check the passed in password and return + the validation result. If validation pass, state machine in password Callback() + will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD. + After user type in new password twice, Callback() will be invoked to send the + new password to Configuration Driver. + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this password Question. + @param String The clear text of password. + + @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input. + @return In state of BROWSER_STATE_VALIDATE_PASSWORD: + @retval EFI_SUCCESS Password correct, Browser will prompt for new + password. + @retval EFI_NOT_READY Password incorrect, Browser will show error + message. + @retval Other Browser will do nothing. + @return In state of BROWSER_STATE_SET_PASSWORD: + @retval EFI_SUCCESS Set password success. + @retval Other Set password failed. + +**/ +EFI_STATUS +PasswordCallback ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question, + IN CHAR16 *String + ); + +/** + Display error message for invalid password. + +**/ +VOID +PasswordInvalid ( + VOID + ); + +/** + The worker function that send the displays to the screen. On output, + the selection made by user is returned. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + + @retval EFI_SUCCESS The page is displayed successfully. + @return Other value if the page failed to be diplayed. + +**/ +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ); + +/** + Free up the resource allocated for all strings required + by Setup Browser. + +**/ +VOID +FreeBrowserStrings ( + VOID + ); + +/** + Create a menu with specified formset GUID and form ID, and add it as a child + of the given parent menu. + + @param HiiHandle Hii handle related to this formset. + @param FormSetGuid The Formset Guid of menu to be added. + @param FormId The Form ID of menu to be added. + @param QuestionId The question id of this menu to be added. + + @return A pointer to the newly added menu or NULL if memory is insufficient. + +**/ +FORM_ENTRY_INFO * +UiAddMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId, + IN UINT16 QuestionId + ); + +/** + Search Menu with given FormSetGuid and FormId in all cached menu list. + + @param HiiHandle HiiHandle for FormSet. + @param FormSetGuid The Formset GUID of the menu to search. + @param FormId The Form ID of menu to search. + + @return A pointer to menu found or NULL if not found. + +**/ +FORM_ENTRY_INFO * +UiFindMenuList ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, + IN UINT16 FormId + ); + +/** + Free Menu list linked list. + + @param MenuListHead One Menu list point in the menu list. + +**/ +VOID +UiFreeMenuList ( + LIST_ENTRY *MenuListHead + ); + +/** + Find parent menu for current menu. + + @param CurrentMenu Current Menu + @param SettingLevel Whether find parent menu in Form Level or Formset level. + In form level, just find the parent menu; + In formset level, find the parent menu which has different + formset guid value. + + @retval The parent menu for current menu. +**/ +FORM_ENTRY_INFO * +UiFindParentMenu ( + IN FORM_ENTRY_INFO *CurrentMenu, + IN BROWSER_SETTING_SCOPE SettingLevel + ); + +/** + Validate the HiiHandle. + + @param HiiHandle The input HiiHandle which need to validate. + + @retval TRUE The handle is validate. + @retval FALSE The handle is invalidate. + +**/ +BOOLEAN +ValidateHiiHandle ( + EFI_HII_HANDLE HiiHandle + ); + +/** + Copy current Menu list to the new menu list. + + @param NewMenuListHead New create Menu list. + @param CurrentMenuListHead Current Menu list. + +**/ +VOID +UiCopyMenuList ( + OUT LIST_ENTRY *NewMenuListHead, + IN LIST_ENTRY *CurrentMenuListHead + ); + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ); + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ); + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ); + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ); + +/** + Perform Password check. + Passwork may be encrypted by driver that requires the specific check. + + @param Form Form where Password Statement is in. + @param Statement Password statement + @param PasswordString Password string to be checked. It may be NULL. + NULL means to restore password. + "" string can be used to checked whether old password does exist. + + @return Status Status of Password check. +**/ +EFI_STATUS +EFIAPI +PasswordCheck ( + IN FORM_DISPLAY_ENGINE_FORM *Form, + IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, + IN EFI_STRING PasswordString OPTIONAL + ); + +/** + + Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info. + + @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT. + + @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info. + +**/ +FORM_BROWSER_STATEMENT * +GetBrowserStatement ( + IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement + ); + +/** + + Initialize the Display form structure data. + +**/ +VOID +InitializeDisplayFormData ( + VOID + ); + +/** + Base on the current formset info, clean the ConfigRequest string in browser storage. + + @param FormSet Pointer of the FormSet + +**/ +VOID +CleanBrowserStorage ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ); + +/** + Find HII Handle in the HII database associated with given Device Path. + + If DevicePath is NULL, then ASSERT. + + @param DevicePath Device Path associated with the HII package list + handle. + @param FormsetGuid The formset guid for this formset. + + @retval Handle HII package list Handle associated with the Device + Path. + @retval NULL Hii Package list handle is not found. + +**/ +EFI_HII_HANDLE +DevicePathToHiiHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_GUID *FormsetGuid + ); + +/** + Adjust the config request info, remove the request elements which already in AllConfigRequest string. + + @param Storage Form set Storage. + @param Request The input request string. + @param RespString Whether the input is ConfigRequest or ConfigResp format. + + @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig + @retval FALSE All elements covered by current used elements. + +**/ +BOOLEAN +ConfigRequestAdjust ( + IN BROWSER_STORAGE *Storage, + IN CHAR16 *Request, + IN BOOLEAN RespString + ); + +/** + Perform question check. + + If one question has more than one check, process form high priority to low. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValueChangedValidation ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question + ); + +/** + Pop up the error info. + + @param BrowserStatus The input browser status. + @param HiiHandle The HiiHandle for this error opcode. + @param OpCode The opcode use to get the erro info and timeout value. + @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF. + +**/ +UINT32 +PopupErrorMessage ( + IN UINT32 BrowserStatus, + IN EFI_HII_HANDLE HiiHandle, + IN EFI_IFR_OP_HEADER *OpCode OPTIONAL, + IN CHAR16 *ErrorString + ); + +/** + Check whether the result is TRUE or FALSE. + + For the EFI_HII_VALUE value type is numeric, return TRUE if the + value is not 0. + + @param Result Input the result data. + + @retval TRUE The result is TRUE. + @retval FALSE The result is FALSE. + +**/ +BOOLEAN +IsTrue ( + IN EFI_HII_VALUE *Result + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Reconnect the controller. + + @param DriverHandle The controller handle which need to be reconnect. + + @retval TRUE do the reconnect behavior success. + @retval FALSE do the reconnect behavior failed. + +**/ +BOOLEAN +ReconnectController ( + IN EFI_HANDLE DriverHandle + ); + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +EFIAPI +HiiToLower ( + IN EFI_STRING ConfigString + ); + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni index 49b21252ee..4d50a42db8 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni @@ -1,16 +1,16 @@ -// /** @file
-// The DXE driver produces FORM BROWSER2 protocol defined in UEFI specification.
-//
-// It also produces FormBrowserEx(2) protocol to let user register the different Hot key service.
-//
-// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Produces the FORM BROWSER2 protocol defined in the UEFI Specification"
-
-#string STR_MODULE_DESCRIPTION #language en-US "This driver produces text display service. It can show HII Form package and interact with user. It also produces FormBrowserEx protocol to let user register the different Hot key service."
-
+// /** @file +// The DXE driver produces FORM BROWSER2 protocol defined in UEFI specification. +// +// It also produces FormBrowserEx(2) protocol to let user register the different Hot key service. +// +// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces the FORM BROWSER2 protocol defined in the UEFI Specification" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver produces text display service. It can show HII Form package and interact with user. It also produces FormBrowserEx protocol to let user register the different Hot key service." + diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf index 82db7c1ef1..a896c7e5fa 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf @@ -1,79 +1,79 @@ -## @file
-# The DXE driver produces FORM BROWSER2 protocol defined in UEFI specification.
-#
-# It also produces FormBrowserEx(2) protocol to let user register the different Hot key service.
-#
-# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = SetupBrowser
- MODULE_UNI_FILE = SetupBrowser.uni
- FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 2.0
- ENTRY_POINT = InitializeSetup
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources]
- Setup.c
- Setup.h
- IfrParse.c
- Expression.c
- Presentation.c
- Expression.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- MemoryAllocationLib
- BaseLib
- UefiBootServicesTableLib
- UefiDriverEntryPoint
- UefiRuntimeServicesTableLib
- BaseMemoryLib
- DebugLib
- PrintLib
- HiiLib
- DevicePathLib
- PcdLib
- UefiLib
-
-[Guids]
- gEfiHiiPlatformSetupFormsetGuid ## SOMETIMES_CONSUMES ## GUID
- gEfiHiiStandardFormGuid ## SOMETIMES_CONSUMES ## GUID
- gZeroGuid ## SOMETIMES_CONSUMES ## GUID
- gEdkiiIfrBitVarstoreGuid ## SOMETIMES_CONSUMES ## GUID
-
-[Protocols]
- gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_CONSUMES
- gEfiFormBrowser2ProtocolGuid ## PRODUCES
- gEdkiiFormBrowserEx2ProtocolGuid ## PRODUCES
- gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
- gEfiHiiDatabaseProtocolGuid ## CONSUMES
- gEfiUnicodeCollation2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
- gEfiDevicePathFromTextProtocolGuid ## SOMETIMES_CONSUMES
- ## CONSUMES
- ## NOTIFY
- gEdkiiFormDisplayEngineProtocolGuid
- gEdkiiFormBrowserExProtocolGuid ## PRODUCES
- gEfiRegularExpressionProtocolGuid ## SOMETIMES_CONSUMES
-
-[Depex]
- gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
-
-[UserExtensions.TianoCore."ExtraFiles"]
- SetupBrowserExtra.uni
+## @file +# The DXE driver produces FORM BROWSER2 protocol defined in UEFI specification. +# +# It also produces FormBrowserEx(2) protocol to let user register the different Hot key service. +# +# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SetupBrowser + MODULE_UNI_FILE = SetupBrowser.uni + FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 2.0 + ENTRY_POINT = InitializeSetup + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + Setup.c + Setup.h + IfrParse.c + Expression.c + Presentation.c + Expression.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + HiiLib + DevicePathLib + PcdLib + UefiLib + +[Guids] + gEfiHiiPlatformSetupFormsetGuid ## SOMETIMES_CONSUMES ## GUID + gEfiHiiStandardFormGuid ## SOMETIMES_CONSUMES ## GUID + gZeroGuid ## SOMETIMES_CONSUMES ## GUID + gEdkiiIfrBitVarstoreGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_CONSUMES + gEfiFormBrowser2ProtocolGuid ## PRODUCES + gEdkiiFormBrowserEx2ProtocolGuid ## PRODUCES + gEfiHiiConfigRoutingProtocolGuid ## CONSUMES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiUnicodeCollation2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES + gEfiDevicePathFromTextProtocolGuid ## SOMETIMES_CONSUMES + ## CONSUMES + ## NOTIFY + gEdkiiFormDisplayEngineProtocolGuid + gEdkiiFormBrowserExProtocolGuid ## PRODUCES + gEfiRegularExpressionProtocolGuid ## SOMETIMES_CONSUMES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SetupBrowserExtra.uni diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni index 33d9b8e464..3d2f5e24a9 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// SetupBrowser Localized Strings and Content
-//
-// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"Setup Browser DXE Driver"
-
-
+// /** @file +// SetupBrowser Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Setup Browser DXE Driver" + + |
