summaryrefslogtreecommitdiff
path: root/Core/MdeModulePkg/Universal/SetupBrowserDxe
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2017-04-27 11:05:07 +0800
committerGuo Mang <mang.guo@intel.com>2017-04-27 11:05:07 +0800
commitc23f114d3cfbb29b8734b87213d1ec0de404197b (patch)
tree4f3612573be055139a88213559212a40b7862fee /Core/MdeModulePkg/Universal/SetupBrowserDxe
parent001e57a103fce87245bfb7ae9c32ffb499a64135 (diff)
downloadedk2-platforms-c23f114d3cfbb29b8734b87213d1ec0de404197b.tar.xz
MdeModulePkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core/MdeModulePkg/Universal/SetupBrowserDxe')
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c3736
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h265
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c2745
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c2612
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c6570
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h1877
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni22
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf88
-rw-r--r--Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni20
9 files changed, 17935 insertions, 0 deletions
diff --git a/Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
new file mode 100644
index 0000000000..901b35c720
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
@@ -0,0 +1,3736 @@
+/** @file
+Utility functions for expression evaluation.
+
+Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 (
+ )
+{
+ 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;
+ }
+ 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/Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h
new file mode 100644
index 0000000000..5660a997b8
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h
@@ -0,0 +1,265 @@
+/** @file
+Private structure, MACRO and function definitions for User Interface related functionalities.
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/Core/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/Core/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c
new file mode 100644
index 0000000000..6b3e5e098e
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c
@@ -0,0 +1,2745 @@
+/** @file
+Parser for IFR binary encoding.
+
+Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Setup.h"
+
+UINT16 mStatementIndex;
+UINT16 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;
+
+ 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;
+}
+
+/**
+ Convert a numeric value to a Unicode String and insert it to String Package.
+ This string is used as the Unicode Name for the EFI Variable. This is to support
+ the deprecated vareqval opcode.
+
+ @param FormSet The FormSet.
+ @param Statement The numeric question whose VarStoreInfo.VarName is the
+ numeric value which is used to produce the Unicode Name
+ for the EFI Variable.
+
+ If the Statement is NULL, the ASSERT.
+ If the opcode is not Numeric, then ASSERT.
+
+ @retval EFI_SUCCESS The funtion always succeeds.
+**/
+EFI_STATUS
+UpdateCheckBoxStringToken (
+ IN CONST FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ CHAR16 Str[MAXIMUM_VALUE_CHARACTERS];
+ EFI_STRING_ID Id;
+
+ ASSERT (Statement != NULL);
+ ASSERT (Statement->Operand == EFI_IFR_NUMERIC_OP);
+
+ UnicodeValueToStringS (Str, sizeof (Str), 0, Statement->VarStoreInfo.VarName, MAXIMUM_VALUE_CHARACTERS - 1);
+
+ Id = HiiSetString (FormSet->HiiHandle, 0, Str, NULL);
+ if (Id == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Statement->VarStoreInfo.VarName = Id;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the next opcode is the EFI_IFR_EXTEND_OP_VAREQNAME.
+
+ @param OpCodeData The current opcode.
+
+ @retval TRUE Yes.
+ @retval FALSE No.
+**/
+BOOLEAN
+IsNextOpCodeGuidedVarEqName (
+ IN UINT8 *OpCodeData
+ )
+{
+ //
+ // Get next opcode
+ //
+ OpCodeData += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ if (*OpCodeData == EFI_IFR_GUID_OP) {
+ if (CompareGuid (&gEfiIfrFrameworkGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
+ //
+ // Specific GUIDed opcodes to support IFR generated from Framework HII VFR
+ //
+ if ((((EFI_IFR_GUID_VAREQNAME *) OpCodeData)->ExtendOpCode) == EFI_IFR_EXTEND_OP_VAREQNAME) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ 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;
+ EFI_STATUS Status;
+ 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;
+ }
+
+ //
+ // Take a look at next OpCode to see whether it is a GUIDed opcode to support
+ // Framework Compatibility
+ //
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
+ if ((*OpCodeData == EFI_IFR_NUMERIC_OP) && IsNextOpCodeGuidedVarEqName (OpCodeData)) {
+ Status = UpdateCheckBoxStringToken (FormSet, Statement);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+ }
+
+ //
+ // 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;
+ }
+}
+
+/**
+ Check whether exist device path info in the ConfigHdr string.
+
+ @param String UEFI configuration string
+
+ @retval TRUE Device Path exist.
+ @retval FALSE Not exist device path info.
+
+**/
+BOOLEAN
+IsDevicePathExist (
+ IN EFI_STRING String
+ )
+{
+ UINTN Length;
+
+ for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
+ if (*String == 0) {
+ return FALSE;
+ }
+
+ String += StrLen (L"PATH=");
+ if (*String == 0) {
+ return FALSE;
+ }
+
+ for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
+ if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ 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,
+ IN OUT UINT16 *NumberOfStatement,
+ IN OUT UINT16 *NumberOfExpression
+ )
+{
+ UINT16 StatementCount;
+ UINT16 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;
+ UINT16 NumberOfStatement;
+ UINT16 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;
+
+ 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;
+
+ //
+ // 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;
+
+ 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;
+
+ 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);
+ break;
+
+ //
+ // Scope End
+ //
+ case EFI_IFR_END_OP:
+ 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/Core/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
new file mode 100644
index 0000000000..08d46cf554
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
@@ -0,0 +1,2612 @@
+/** @file
+Utility functions for UI presentation.
+
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+
+/**
+ 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) {
+ gResetRequired = 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;
+ }
+
+ 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 + sizeof(CHAR16), 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;
+ gResetRequired = 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;
+
+ 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 + sizeof(CHAR16));
+ } 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) {
+ gResetRequired = 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/Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
new file mode 100644
index 0000000000..83dc2b86c7
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
@@ -0,0 +1,6570 @@
+/** @file
+Entry and initialization module for the browser.
+
+Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 gResetRequired;
+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;
+ gResetRequired = 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;
+
+ if (gFlagReconnect || gCallbackReconnect) {
+ 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 (gResetRequired) {
+ *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;
+}
+
+/**
+ 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;
+
+ 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
+ //
+ 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;
+
+ 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
+ //
+ CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
+ } else {
+ //
+ // Copy from storage Edit buffer
+ //
+ 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
+ //
+ CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
+ } else if (SetValueTo == GetSetValueWithBuffer) {
+ //
+ // Copy to storage edit buffer
+ //
+ 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) {
+ gResetRequired = 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;
+ }
+
+ //
+ // 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 (FormSetGuid) ||
+ 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 = gResetRequired;
+ 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;
+ gResetRequired = 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) {
+ gResetRequired = 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 gResetRequired;
+}
+
diff --git a/Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h
new file mode 100644
index 0000000000..f1accdf841
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h
@@ -0,0 +1,1877 @@
+/** @file
+Private MACRO, structure and function definitions for Setup Browser module.
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#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;
+ UINT8 QuestionFlags;
+ 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 gResetRequired;
+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/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni b/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni
new file mode 100644
index 0000000000..4d158360ef
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni
@@ -0,0 +1,22 @@
+// /** @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 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#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/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
new file mode 100644
index 0000000000..012a39bee5
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
@@ -0,0 +1,88 @@
+## @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 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[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 IPF 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]
+ gEfiIfrFrameworkGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiHiiPlatformSetupFormsetGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiHiiStandardFormGuid ## SOMETIMES_CONSUMES ## GUID
+ gZeroGuid ## 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 ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SetupBrowserExtra.uni
diff --git a/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni b/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni
new file mode 100644
index 0000000000..b456e2a54c
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// SetupBrowser Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Setup Browser DXE Driver"
+
+