]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
Update Browser to provide the customization possibilities.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Presentation.c
index c3854aac249ae89c3900fff5f1cedecfb523ad4e..def18fd9f90b3eaec623fc9107df1d5d4d06da94 100644 (file)
@@ -19,863 +19,1658 @@ UI_MENU_SELECTION  *gCurrentSelection;
 EFI_HII_HANDLE     mCurrentHiiHandle = NULL;\r
 EFI_GUID           mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
 UINT16             mCurrentFormId = 0;\r
+EFI_EVENT          mValueChangedEvent = NULL;\r
+LIST_ENTRY         mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);\r
+UINT32             gBrowserStatus = BROWSER_SUCCESS;\r
+CHAR16             *gErrorInfo;\r
+UINT16             mCurFakeQestId;\r
+FORM_DISPLAY_ENGINE_FORM gDisplayFormData;\r
 \r
 /**\r
-  Clear retangle with specified text attribute.\r
+  Evaluate all expressions in a Form.\r
+\r
+  @param  FormSet        FormSet this Form belongs to.\r
+  @param  Form           The Form.\r
 \r
-  @param  LeftColumn     Left column of retangle.\r
-  @param  RightColumn    Right column of retangle.\r
-  @param  TopRow         Start row of retangle.\r
-  @param  BottomRow      End row of retangle.\r
-  @param  TextAttribute  The character foreground and background.\r
+  @retval EFI_SUCCESS    The expression evaluated successfuly\r
 \r
 **/\r
-VOID\r
-ClearLines (\r
-  IN UINTN               LeftColumn,\r
-  IN UINTN               RightColumn,\r
-  IN UINTN               TopRow,\r
-  IN UINTN               BottomRow,\r
-  IN UINTN               TextAttribute\r
+EFI_STATUS\r
+EvaluateFormExpressions (\r
+  IN FORM_BROWSER_FORMSET  *FormSet,\r
+  IN FORM_BROWSER_FORM     *Form\r
   )\r
 {\r
-  CHAR16  *Buffer;\r
-  UINTN   Row;\r
-\r
-  //\r
-  // For now, allocate an arbitrarily long buffer\r
-  //\r
-  Buffer = AllocateZeroPool (0x10000);\r
-  ASSERT (Buffer != NULL);\r
+  EFI_STATUS       Status;\r
+  LIST_ENTRY       *Link;\r
+  FORM_EXPRESSION  *Expression;\r
 \r
-  //\r
-  // Set foreground and background as defined\r
-  //\r
-  gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);\r
+  Link = GetFirstNode (&Form->ExpressionListHead);\r
+  while (!IsNull (&Form->ExpressionListHead, Link)) {\r
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
+    Link = GetNextNode (&Form->ExpressionListHead, Link);\r
 \r
-  //\r
-  // Much faster to buffer the long string instead of print it a character at a time\r
-  //\r
-  SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');\r
+    if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||\r
+        Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||\r
+        Expression->Type == EFI_HII_EXPRESSION_WRITE ||\r
+        (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {\r
+      //\r
+      // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.\r
+      //\r
+      continue;\r
+    }\r
 \r
-  //\r
-  // Clear the desired area with the appropriate foreground/background\r
-  //\r
-  for (Row = TopRow; Row <= BottomRow; Row++) {\r
-    PrintStringAt (LeftColumn, Row, Buffer);\r
+    Status = EvaluateExpression (FormSet, Form, Expression);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
-  gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);\r
-\r
-  FreePool (Buffer);\r
-  return ;\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Concatenate a narrow string to another string.\r
+  Add empty function for event process function.\r
 \r
-  @param Destination The destination string.\r
-  @param Source      The source string. The string to be concatenated.\r
-                     to the end of Destination.\r
+  @param Event    The Event need to be process\r
+  @param Context  The context of the event.\r
 \r
 **/\r
 VOID\r
-NewStrCat (\r
-  IN OUT CHAR16               *Destination,\r
-  IN     CHAR16               *Source\r
+EFIAPI\r
+SetupBrowserEmptyFunction (\r
+  IN  EFI_EVENT    Event,\r
+  IN  VOID         *Context\r
   )\r
 {\r
-  UINTN Length;\r
-\r
-  for (Length = 0; Destination[Length] != 0; Length++)\r
-    ;\r
-\r
-  //\r
-  // We now have the length of the original string\r
-  // We can safely assume for now that we are concatenating a narrow value to this string.\r
-  // For instance, the string is "XYZ" and cat'ing ">"\r
-  // If this assumption changes, we need to make this routine a bit more complex\r
-  //\r
-  Destination[Length] = NARROW_CHAR;\r
-  Length++;\r
-\r
-  StrCpy (Destination + Length, Source);\r
 }\r
 \r
 /**\r
-  Count the storage space of a Unicode string.\r
-\r
-  This function handles the Unicode string with NARROW_CHAR\r
-  and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR\r
-  does not count in the resultant output. If a WIDE_CHAR is\r
-  hit, then 2 Unicode character will consume an output storage\r
-  space with size of CHAR16 till a NARROW_CHAR is hit.\r
+  Base on the opcode buffer info to get the display statement.\r
 \r
-  If String is NULL, then ASSERT ().\r
-\r
-  @param String          The input string to be counted.\r
-\r
-  @return Storage space for the input string.\r
+  @param OpCode    The input opcode buffer for this statement.\r
+  \r
+  @retval Statement  The statement use this opcode buffer.\r
 \r
 **/\r
-UINTN\r
-GetStringWidth (\r
-  IN CHAR16               *String\r
+FORM_DISPLAY_ENGINE_STATEMENT *\r
+GetDisplayStatement (\r
+  IN EFI_IFR_OP_HEADER     *OpCode\r
   )\r
 {\r
-  UINTN Index;\r
-  UINTN Count;\r
-  UINTN IncrementValue;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;\r
+  LIST_ENTRY                    *Link;\r
+\r
+  Link = GetFirstNode (&gDisplayFormData.StatementListHead);\r
+  while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {\r
+    DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
 \r
-  ASSERT (String != NULL);\r
-  if (String == NULL) {\r
-    return 0;\r
+    if (DisplayStatement->OpCode == OpCode) {\r
+      return DisplayStatement;\r
+    }\r
+    Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);\r
   }\r
 \r
-  Index           = 0;\r
-  Count           = 0;\r
-  IncrementValue  = 1;\r
+  return NULL;\r
+}\r
 \r
-  do {\r
-    //\r
-    // Advance to the null-terminator or to the first width directive\r
-    //\r
-    for (;\r
-         (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);\r
-         Index++, Count = Count + IncrementValue\r
-        )\r
-      ;\r
+/**\r
+  Free the refresh event list.\r
 \r
-    //\r
-    // We hit the null-terminator, we now have a count\r
-    //\r
-    if (String[Index] == 0) {\r
-      break;\r
-    }\r
-    //\r
-    // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed\r
-    // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)\r
-    //\r
-    if (String[Index] == NARROW_CHAR) {\r
-      //\r
-      // Skip to the next character\r
-      //\r
-      Index++;\r
-      IncrementValue = 1;\r
-    } else {\r
-      //\r
-      // Skip to the next character\r
-      //\r
-      Index++;\r
-      IncrementValue = 2;\r
-    }\r
-  } while (String[Index] != 0);\r
+**/\r
+VOID \r
+FreeRefreshEvent (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY   *Link;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
 \r
-  //\r
-  // Increment by one to include the null-terminator in the size\r
-  //\r
-  Count++;\r
+  while (!IsListEmpty (&mRefreshEventList)) {\r
+    Link = GetFirstNode (&mRefreshEventList);\r
+    EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);\r
+    RemoveEntryList (&EventNode->Link);\r
 \r
-  return Count * sizeof (CHAR16);\r
+    gBS->CloseEvent (EventNode->RefreshEvent);\r
+\r
+    FreePool (EventNode);\r
+  }\r
 }\r
 \r
 /**\r
-  This function displays the page frame.\r
+  Check whether this statement value is changed. If yes, update the statement value and return TRUE; \r
+  else return FALSE.\r
+\r
+  @param Statement           The statement need to check.\r
 \r
-  @param  Selection              Selection contains the information about \r
-                                 the Selection, form and formset to be displayed.\r
-                                 Selection action may be updated in retrieve callback.\r
 **/\r
 VOID\r
-DisplayPageFrame (\r
-  IN UI_MENU_SELECTION    *Selection\r
+UpdateStatement (\r
+  IN OUT FORM_BROWSER_STATEMENT        *Statement\r
   )\r
 {\r
-  UINTN                  Index;\r
-  UINT8                  Line;\r
-  UINT8                  Alignment;\r
-  CHAR16                 Character;\r
-  CHAR16                 *Buffer;\r
-  CHAR16                 *StrFrontPageBanner;\r
-  UINTN                  Row;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  UINT8                  RowIdx;\r
-  UINT8                  ColumnIdx;\r
-\r
-  ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-  gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow);\r
-  ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND);\r
-\r
-  if (Selection->Form->ModalForm) {\r
-    return;\r
-  }\r
-\r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+  GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);\r
 \r
   //\r
-  // For now, allocate an arbitrarily long buffer\r
+  // Reset FormPackage update flag\r
   //\r
-  Buffer = AllocateZeroPool (0x10000);\r
-  ASSERT (Buffer != NULL);\r
-\r
-  Character = BOXDRAW_HORIZONTAL;\r
-\r
-  for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) {\r
-    Buffer[Index] = Character;\r
-  }\r
+  mHiiPackageListUpdated = FALSE;\r
 \r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-    //\r
-    //    ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);\r
-    //\r
-    ClearLines (\r
-      LocalScreen.LeftColumn,\r
-      LocalScreen.RightColumn,\r
-      LocalScreen.TopRow,\r
-      FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow,\r
-      BANNER_TEXT | BANNER_BACKGROUND\r
-      );\r
+  //\r
+  // Question value may be changed, need invoke its Callback()\r
+  //\r
+  ProcessCallBackFunction (gCurrentSelection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+  \r
+  if (mHiiPackageListUpdated) {\r
     //\r
-    //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {\r
+    // Package list is updated, force to reparse IFR binary of target Formset\r
     //\r
-    for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) {\r
-      //\r
-      //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {\r
-      //\r
-      for (Alignment = (UINT8) LocalScreen.LeftColumn;\r
-           Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn;\r
-           Alignment++\r
-          ) {\r
-        RowIdx = (UINT8) (Line - (UINT8) LocalScreen.TopRow);\r
-        ColumnIdx = (UINT8) (Alignment - (UINT8) LocalScreen.LeftColumn);\r
-\r
-        ASSERT (RowIdx < BANNER_HEIGHT);\r
-        ASSERT (ColumnIdx < BANNER_COLUMNS);\r
-\r
-        if (gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {\r
-          StrFrontPageBanner = GetToken (\r
-                                gBannerData->Banner[RowIdx][ColumnIdx],\r
-                                gFrontPageHandle\r
-                                );\r
-        } else {\r
-          continue;\r
-        }\r
-\r
-        switch (Alignment - LocalScreen.LeftColumn) {\r
-        case 0:\r
-          //\r
-          // Handle left column\r
-          //\r
-          PrintStringAt (LocalScreen.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);\r
-          break;\r
-\r
-        case 1:\r
-          //\r
-          // Handle center column\r
-          //\r
-          PrintStringAt (\r
-            LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,\r
-            Line,\r
-            StrFrontPageBanner\r
-            );\r
-          break;\r
-\r
-        case 2:\r
-          //\r
-          // Handle right column\r
-          //\r
-          PrintStringAt (\r
-            LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,\r
-            Line,\r
-            StrFrontPageBanner\r
-            );\r
-          break;\r
-        }\r
-\r
-        FreePool (StrFrontPageBanner);\r
-      }\r
-    }\r
+    mHiiPackageListUpdated = FALSE;\r
+    gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;\r
   }\r
+}\r
 \r
-  ClearLines (\r
-    LocalScreen.LeftColumn,\r
-    LocalScreen.RightColumn,\r
-    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,\r
-    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1,\r
-    KEYHELP_TEXT | KEYHELP_BACKGROUND\r
-    );\r
-\r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-    ClearLines (\r
-      LocalScreen.LeftColumn,\r
-      LocalScreen.RightColumn,\r
-      LocalScreen.TopRow,\r
-      LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1,\r
-      TITLE_TEXT | TITLE_BACKGROUND\r
-      );\r
-    //\r
-    // Print Top border line\r
-    // +------------------------------------------------------------------------------+\r
-    // ?                                                                             ?\r
-    // +------------------------------------------------------------------------------+\r
-    //\r
-    Character = BOXDRAW_DOWN_RIGHT;\r
-\r
-    PrintChar (Character);\r
-    PrintString (Buffer);\r
-\r
-    Character = BOXDRAW_DOWN_LEFT;\r
-    PrintChar (Character);\r
-\r
-    Character = BOXDRAW_VERTICAL;\r
-    for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {\r
-      PrintCharAt (LocalScreen.LeftColumn, Row, Character);\r
-      PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);\r
-    }\r
-\r
-    Character = BOXDRAW_UP_RIGHT;\r
-    PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);\r
-    PrintString (Buffer);\r
-\r
-    Character = BOXDRAW_UP_LEFT;\r
-    PrintChar (Character);\r
+/**\r
+  Refresh the question which has refresh guid event attribute.\r
+  \r
+  @param Event    The event which has this function related.     \r
+  @param Context  The input context info related to this event or the status code return to the caller.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshEventNotify(\r
+  IN      EFI_EVENT Event,\r
+  IN      VOID      *Context\r
+  )\r
+{\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
 \r
-    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-      //\r
-      // Print Bottom border line\r
-      // +------------------------------------------------------------------------------+\r
-      // ?                                                                             ?\r
-      // +------------------------------------------------------------------------------+\r
-      //\r
-      Character = BOXDRAW_DOWN_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);\r
-\r
-      PrintString (Buffer);\r
-\r
-      Character = BOXDRAW_DOWN_LEFT;\r
-      PrintChar (Character);\r
-      Character = BOXDRAW_VERTICAL;\r
-      for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;\r
-           Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;\r
-           Row++\r
-          ) {\r
-        PrintCharAt (LocalScreen.LeftColumn, Row, Character);\r
-        PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);\r
-      }\r
+  Statement = (FORM_BROWSER_STATEMENT *)Context;\r
+  UpdateStatement(Statement);\r
+  gBS->SignalEvent (mValueChangedEvent);\r
+}\r
 \r
-      Character = BOXDRAW_UP_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character);\r
 \r
-      PrintString (Buffer);\r
+/**\r
+  Create refresh hook event for statement which has refresh event or interval.\r
 \r
-      Character = BOXDRAW_UP_LEFT;\r
-      PrintChar (Character);\r
-    }\r
-  }\r
+  @param Statement           The statement need to check.\r
 \r
-  FreePool (Buffer);\r
+**/\r
+VOID\r
+CreateRefreshEvent (\r
+  IN     FORM_BROWSER_STATEMENT        *Statement\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_EVENT                       RefreshEvent;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
 \r
+  //\r
+  // If question has refresh guid, create the notify function.\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    RefreshEventNotify,\r
+                    Statement,\r
+                    &Statement->RefreshGuid,\r
+                    &RefreshEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));\r
+  ASSERT (EventNode != NULL);\r
+  EventNode->RefreshEvent = RefreshEvent;\r
+  InsertTailList(&mRefreshEventList, &EventNode->Link);\r
 }\r
 \r
-\r
 /**\r
-  Evaluate all expressions in a Form.\r
-\r
-  @param  FormSet        FormSet this Form belongs to.\r
-  @param  Form           The Form.\r
-\r
-  @retval EFI_SUCCESS    The expression evaluated successfuly\r
-\r
+  Perform value check for a question.\r
+  \r
+  @param  Question       The question need to do check.\r
+  @param  ErrorInfo      Return info about the error.\r
+  \r
+  @retval  The check result.\r
 **/\r
-EFI_STATUS\r
-EvaluateFormExpressions (\r
-  IN FORM_BROWSER_FORMSET  *FormSet,\r
-  IN FORM_BROWSER_FORM     *Form\r
+UINT32\r
+InConsistentIfCheck (\r
+  IN  FORM_BROWSER_STATEMENT        *Question,\r
+  OUT STATEMENT_ERROR_INFO          *ErrorInfo\r
   )\r
 {\r
-  EFI_STATUS       Status;\r
-  LIST_ENTRY       *Link;\r
-  FORM_EXPRESSION  *Expression;\r
+  EFI_STATUS              Status;\r
+  LIST_ENTRY              *Link;\r
+  FORM_EXPRESSION         *Expression;\r
+  LIST_ENTRY              *ListHead;\r
+  UINT32                  RetVal;\r
 \r
-  Link = GetFirstNode (&Form->ExpressionListHead);\r
-  while (!IsNull (&Form->ExpressionListHead, Link)) {\r
+  RetVal     = STATEMENT_VALID;\r
+  ListHead   = &Question->InconsistentListHead;\r
+\r
+  Link = GetFirstNode (ListHead);\r
+  while (!IsNull (ListHead, Link)) {\r
     Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
-    Link = GetNextNode (&Form->ExpressionListHead, Link);\r
+    Link = GetNextNode (ListHead, Link);\r
 \r
-    if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||\r
-        Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||\r
-        Expression->Type == EFI_HII_EXPRESSION_WRITE ||\r
-        (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {\r
-      //\r
-      // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.\r
-      //\r
+    //\r
+    // Evaluate the expression\r
+    //\r
+    Status = EvaluateExpression (gCurrentSelection->FormSet, gCurrentSelection->Form, Expression);\r
+    if (EFI_ERROR (Status)) {\r
       continue;\r
     }\r
 \r
-    Status = EvaluateExpression (FormSet, Form, Expression);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
+    if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {\r
+      ErrorInfo->StringId = Expression->Error;\r
+      ErrorInfo->TimeOut  = 0;\r
+      RetVal              = INCOSISTENT_IF_TRUE;\r
+      break;\r
     }\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  return RetVal;\r
 }\r
 \r
-/*\r
-+------------------------------------------------------------------------------+\r
-?                                 Setup Page                                  ?\r
-+------------------------------------------------------------------------------+\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
+/**\r
+  Perform value check for a question.\r
+  \r
+  @param  Form       Form where Statement is in.\r
+  @param  Statement  Value will check for it.\r
+  @param  InputValue New value will be checked.\r
+  @param  ErrorInfo  Return the error info for this check.\r
+  \r
+  @retval TRUE   Input Value is valid.\r
+  @retval FALSE  Input Value is invalid.\r
+**/\r
+UINT32\r
+EFIAPI\r
+QuestionCheck (\r
+  IN  FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN  FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN  EFI_HII_VALUE                 *InputValue,\r
+  OUT STATEMENT_ERROR_INFO          *ErrorInfo\r
+  )\r
+{\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  EFI_HII_VALUE           BackUpValue;\r
+  UINT8                   *BackUpBuffer;\r
+  UINT32                  RetVal;\r
 \r
+  BackUpBuffer = NULL;\r
+  RetVal       = STATEMENT_VALID;\r
 \r
+  ASSERT (Form != NULL && Statement != NULL && InputValue != NULL && ErrorInfo != NULL);\r
 \r
+  Question = GetBrowserStatement(Statement);\r
+  ASSERT (Question != NULL);\r
 \r
+  //\r
+  // Back up the quesion value.\r
+  //\r
+  switch (Question->Operand) {\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+    BackUpBuffer = AllocateCopyPool (Question->StorageWidth, Question->BufferValue);\r
+    ASSERT (BackUpBuffer != NULL);\r
+    CopyMem (Question->BufferValue, InputValue->Buffer, Question->StorageWidth);\r
+    break;\r
 \r
+  default:\r
+    CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));\r
+    CopyMem (&Question->HiiValue, InputValue, sizeof (EFI_HII_VALUE));\r
+    break;\r
+  }\r
 \r
+  //\r
+  // Do the inconsistentif check.\r
+  //\r
+  if (!IsListEmpty (&Question->InconsistentListHead)) {\r
+    RetVal = InConsistentIfCheck(Question, ErrorInfo);\r
+  }\r
 \r
+  //\r
+  // Restore the quesion value.\r
+  //\r
+  switch (Question->Operand) {\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+    CopyMem (Question->BufferValue, BackUpBuffer, Question->StorageWidth);\r
+    break;\r
 \r
+  default:\r
+    CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));\r
+    break;\r
+  }\r
 \r
-+------------------------------------------------------------------------------+\r
-?F1=Scroll Help                 F9=Reset to Defaults        F10=Save and Exit ?\r
-| ^"=Move Highlight          <Spacebar> Toggles Checkbox   Esc=Discard Changes |\r
-+------------------------------------------------------------------------------+\r
-*/\r
+  return RetVal;\r
+}\r
 \r
 /**\r
 \r
+  Initialize the Display statement structure data.\r
 \r
-  Display form and wait for user to select one menu option, then return it.\r
-\r
-  @param Selection       On input, Selection tell setup browser the information\r
-                         about the Selection, form and formset to be displayed.\r
-                         On output, Selection return the screen item that is selected\r
-                         by user.\r
-  @retval EFI_SUCESSS            This function always return successfully for now.\r
-\r
+  @param DisplayStatement      Pointer to the display Statement data strucure.\r
+  @param Statement             The statement need to check.\r
+  @param HostDisplayStatement  Pointer to the display Statement data strucure which is an host statement.\r
 **/\r
-EFI_STATUS\r
-DisplayForm (\r
-  IN OUT UI_MENU_SELECTION           *Selection\r
+VOID\r
+InitializeDisplayStatement (\r
+  IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,\r
+  IN     FORM_BROWSER_STATEMENT        *Statement,\r
+  IN     FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement\r
   )\r
 {\r
-  CHAR16                 *StringPtr;\r
-  UINT16                 MenuItemCount;\r
-  EFI_HII_HANDLE         Handle;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  UINT16                 Width;\r
-  UINTN                  ArrayEntry;\r
-  CHAR16                 *OutputString;\r
-  LIST_ENTRY             *Link;\r
-  FORM_BROWSER_STATEMENT *Statement;\r
-  UINT16                 NumberOfLines;\r
-  EFI_STATUS             Status;\r
-  UI_MENU_OPTION         *MenuOption;\r
-  UINT16                 GlyphWidth;\r
+  LIST_ENTRY                 *Link;\r
+  QUESTION_OPTION            *Option;\r
+  DISPLAY_QUESTION_OPTION    *DisplayOption;\r
+\r
+  DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;\r
+  DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;\r
+  DisplayStatement->OpCode    = Statement->OpCode;\r
+  InitializeListHead (&DisplayStatement->NestStatementList);\r
+  InitializeListHead (&DisplayStatement->OptionListHead);\r
+\r
+  if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {\r
+    DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;\r
+  }\r
+  if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
+    DisplayStatement->Attribute |= HII_DISPLAY_READONLY;\r
+  }\r
 \r
-  Handle        = Selection->Handle;\r
-  MenuItemCount = 0;\r
-  ArrayEntry    = 0;\r
-  OutputString  = NULL;\r
+  //\r
+  // Initilize the option list in statement.\r
+  //\r
+  Link = GetFirstNode (&Statement->OptionListHead);\r
+  while (!IsNull (&Statement->OptionListHead, Link)) {\r
+    Option = QUESTION_OPTION_FROM_LINK (Link);\r
+    Link = GetNextNode (&Statement->OptionListHead, Link);\r
+    if ((Option->SuppressExpression != NULL) &&\r
+        ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {\r
+      continue;\r
+    }\r
 \r
-  UiInitMenu ();\r
+    DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));\r
+    ASSERT (DisplayOption != NULL);\r
 \r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+    DisplayOption->ImageId      = Option->ImageId;\r
+    DisplayOption->Signature    = DISPLAY_QUESTION_OPTION_SIGNATURE;\r
+    DisplayOption->OptionOpCode = Option->OpCode;\r
+    InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link);\r
+  }\r
 \r
-  StringPtr = GetToken (Selection->Form->FormTitle, Handle);\r
+  CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));\r
 \r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-    if (Selection->Form->ModalForm) {\r
-      gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | EFI_BACKGROUND_BLACK);\r
-    } else {\r
-      gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);\r
+  //\r
+  // Some special op code need an extra buffer to save the data.\r
+  // Such as string, password, orderedlist...\r
+  //\r
+  if (Statement->BufferValue != NULL) {\r
+    //\r
+    // Ordered list opcode may not initilized, get default value here.\r
+    //\r
+    if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) {\r
+      GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);\r
     }\r
-    PrintStringAt (\r
-      (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,\r
-      LocalScreen.TopRow + 1,\r
-      StringPtr\r
-      );\r
+\r
+    DisplayStatement->CurrentValue.Buffer    = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);\r
+    DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;\r
   }\r
 \r
+  DisplayStatement->SettingChangedFlag = Statement->ValueChanged;\r
+\r
   //\r
-  // Remove Buffer allocated for StringPtr after it has been used.\r
+  // Get the highlight statement for current form.\r
   //\r
-  FreePool (StringPtr);\r
+  if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||\r
+      ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) {\r
+    gDisplayFormData.HighLightedStatement = DisplayStatement;\r
+  }\r
 \r
   //\r
-  // Evaluate all the Expressions in this Form\r
+  // Create the refresh event process function.\r
   //\r
-  Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
+    CreateRefreshEvent (Statement);\r
   }\r
 \r
-  Selection->FormEditable = FALSE;\r
-  Link = GetFirstNode (&Selection->Form->StatementListHead);\r
-  while (!IsNull (&Selection->Form->StatementListHead, Link)) {\r
-    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+  //\r
+  // For RTC type of date/time, set default refresh interval to be 1 second.\r
+  //\r
+  if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {\r
+    Statement->RefreshInterval = 1;\r
+  }\r
 \r
-    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) <= ExpressGrayOut) {\r
-      StringPtr = GetToken (Statement->Prompt, Handle);\r
-      ASSERT (StringPtr != NULL);\r
+  //\r
+  // Create the refresh guid hook event.\r
+  // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.\r
+  //\r
+  if ((!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) || (Statement->RefreshInterval != 0)) {\r
+    gDisplayFormData.FormRefreshEvent = mValueChangedEvent;\r
+  }\r
 \r
-      Width     = GetWidth (Statement, Handle);\r
+  //\r
+  // Save the password check function for later use.\r
+  //\r
+  if (Statement->Operand == EFI_IFR_PASSWORD_OP) {\r
+    DisplayStatement->PasswordCheck = PasswordCheck;\r
+  }\r
 \r
-      NumberOfLines = 1;\r
-      ArrayEntry = 0;\r
-      GlyphWidth = 1;\r
-      for (; GetLineByWidth (StringPtr, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {\r
-        //\r
-        // If there is more string to process print on the next row and increment the Skip value\r
-        //\r
-        if (StrLen (&StringPtr[ArrayEntry]) != 0) {\r
-          NumberOfLines++;\r
-        }\r
+  //\r
+  // Save the validate check question for later use.\r
+  //\r
+  if (!IsListEmpty (&Statement->InconsistentListHead)) {\r
+    DisplayStatement->ValidateQuestion = QuestionCheck;\r
+  }\r
 \r
-        FreePool (OutputString);\r
-      }\r
+  //\r
+  // If this statement is nest in the subtitle, insert to the host statement.\r
+  // else insert to the form it belongs to.\r
+  //\r
+  if (Statement->InSubtitle) {\r
+    InsertTailList(&HostDisplayStatement->NestStatementList, &DisplayStatement->DisplayLink);\r
+  } else {\r
+    InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);\r
+  }\r
+}\r
 \r
-      //\r
-      // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do\r
-      // it in UiFreeMenu.\r
-      //\r
-      MenuOption = UiAddMenuOption (StringPtr, Selection->Handle, Selection->Form, Statement, NumberOfLines, MenuItemCount);\r
-      MenuItemCount++;\r
+/**\r
+  Process for the refresh interval statement.\r
 \r
-      if (MenuOption->IsQuestion && !MenuOption->ReadOnly) {\r
-        //\r
-        // At least one item is not readonly, this Form is considered as editable\r
-        //\r
-        Selection->FormEditable = TRUE;\r
+  @param Event    The Event need to be process\r
+  @param Context  The context of the event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshIntervalProcess (\r
+  IN  EFI_EVENT    Event,\r
+  IN  VOID         *Context\r
+  )\r
+{\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+  LIST_ENTRY                    *Link;\r
+\r
+  Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+  while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
+\r
+    if (Statement->RefreshInterval == 0) {\r
+      continue;\r
+    }\r
+\r
+    UpdateStatement(Statement);\r
+  }\r
+\r
+  gBS->SignalEvent (mValueChangedEvent);\r
+}\r
+\r
+/**\r
+\r
+  Make a copy of the global hotkey info.\r
+\r
+**/\r
+VOID\r
+UpdateHotkeyList (\r
+  VOID\r
+  )\r
+{\r
+  BROWSER_HOT_KEY  *HotKey;\r
+  BROWSER_HOT_KEY  *CopyKey;\r
+  LIST_ENTRY       *Link;\r
+\r
+  Link = GetFirstNode (&gBrowserHotKeyList);\r
+  while (!IsNull (&gBrowserHotKeyList, Link)) {\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+\r
+    CopyKey             = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);\r
+    CopyKey->KeyData    = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);\r
+    CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);\r
+\r
+    InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);\r
+\r
+    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Enum all statement in current form, find all the statement can be display and\r
+  add to the display form.\r
+\r
+**/\r
+VOID\r
+AddStatementToDisplayForm (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  LIST_ENTRY                    *Link;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement;\r
+  UINT8                         MinRefreshInterval;\r
+  EFI_EVENT                     RefreshIntervalEvent;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
+  BOOLEAN                       FormEditable;\r
+\r
+  HostDisplayStatement = NULL;\r
+  MinRefreshInterval   = 0;\r
+  FormEditable         = FALSE;\r
+\r
+  //\r
+  // Process the statement outside the form, these statements are not recognized\r
+  // by browser core.\r
+  //\r
+  Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);\r
+  while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);\r
+\r
+    DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));\r
+    ASSERT (DisplayStatement != NULL);\r
+    DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;\r
+    DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;\r
+    DisplayStatement->OpCode = Statement->OpCode;\r
+\r
+    InitializeListHead (&DisplayStatement->NestStatementList);\r
+    InitializeListHead (&DisplayStatement->OptionListHead);\r
+\r
+    InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);\r
+  }\r
+\r
+  //\r
+  // Process the statement in this form.\r
+  //\r
+  Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+  while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
+\r
+    //\r
+    // This statement can't be show, skip it.\r
+    //\r
+    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {\r
+      continue;\r
+    }\r
+\r
+    DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));\r
+    ASSERT (DisplayStatement != NULL);\r
+\r
+    //\r
+    // Initialize this statement and add it to the display form.\r
+    //\r
+    InitializeDisplayStatement(DisplayStatement, Statement, HostDisplayStatement);\r
+\r
+    //\r
+    // Save the Host statement info.\r
+    // Host statement may has nest statement follow it.\r
+    //\r
+    if (!Statement->InSubtitle) {\r
+      HostDisplayStatement = DisplayStatement;\r
+    }\r
+\r
+    if (Statement->Storage != NULL) {\r
+      FormEditable = TRUE;\r
+    }\r
+\r
+    //\r
+    // Get the minimal refresh interval value for later use.\r
+    //\r
+    if ((Statement->RefreshInterval != 0) && \r
+      (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {\r
+      MinRefreshInterval = Statement->RefreshInterval;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create the periodic timer for refresh interval statement.\r
+  //\r
+  if (MinRefreshInterval != 0) {\r
+    Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);\r
+    ASSERT_EFI_ERROR (Status);\r
+    Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));\r
+    ASSERT (EventNode != NULL);\r
+    EventNode->RefreshEvent = RefreshIntervalEvent;\r
+    InsertTailList(&mRefreshEventList, &EventNode->Link);\r
+  }\r
+\r
+  //\r
+  // Update hotkey list field.\r
+  //\r
+  if (gBrowserSettingScope == SystemLevel || FormEditable) {\r
+    UpdateHotkeyList();\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Initialize the SettingChangedFlag variable in the display form.\r
+\r
+**/\r
+VOID\r
+UpdateDataChangedFlag (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY           *Link;\r
+  FORM_BROWSER_FORMSET *LocalFormSet;\r
+\r
+  gDisplayFormData.SettingChangedFlag   = FALSE;\r
+\r
+  if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {\r
+    gDisplayFormData.SettingChangedFlag = TRUE;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Base on the system level to check whether need to show the NV flag.\r
+  // \r
+  switch (gBrowserSettingScope) {\r
+  case SystemLevel:\r
+    //\r
+    // Check the maintain list to see whether there is any change.\r
+    //\r
+    Link = GetFirstNode (&gBrowserFormSetList);\r
+    while (!IsNull (&gBrowserFormSetList, Link)) {\r
+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+      if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {\r
+        gDisplayFormData.SettingChangedFlag = TRUE;\r
+        return;\r
       }\r
+      Link = GetNextNode (&gBrowserFormSetList, Link);\r
     }\r
+    break;\r
 \r
-    Link = GetNextNode (&Selection->Form->StatementListHead, Link);\r
+  case FormSetLevel:\r
+    if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {\r
+      gDisplayFormData.SettingChangedFlag = TRUE;\r
+      return;\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
   }\r
+}\r
 \r
-  Status = UiDisplayMenu (Selection);\r
+/**\r
 \r
-  UiFreeMenu ();\r
+  Initialize the Display form structure data.\r
 \r
-  return Status;\r
+**/\r
+VOID\r
+InitializeDisplayFormData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  gDisplayFormData.Signature   = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;\r
+  gDisplayFormData.Version     = FORM_DISPLAY_ENGINE_VERSION_1;\r
+  gDisplayFormData.ImageId     = 0;\r
+  gDisplayFormData.AnimationId = 0;\r
+\r
+  InitializeListHead (&gDisplayFormData.StatementListHead);\r
+  InitializeListHead (&gDisplayFormData.StatementListOSF);\r
+  InitializeListHead (&gDisplayFormData.HotKeyListHead);\r
+\r
+  Status = gBS->CreateEvent (\r
+        EVT_NOTIFY_WAIT, \r
+        TPL_CALLBACK,\r
+        SetupBrowserEmptyFunction,\r
+        NULL,\r
+        &mValueChangedEvent\r
+        );\r
+  ASSERT_EFI_ERROR (Status); \r
+}\r
+\r
+/**\r
+\r
+  Free the kotkey info saved in form data.\r
+\r
+**/\r
+VOID\r
+FreeHotkeyList (\r
+  VOID\r
+  )\r
+{\r
+  BROWSER_HOT_KEY  *HotKey;\r
+  LIST_ENTRY       *Link;\r
+\r
+  while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {\r
+    Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+\r
+    RemoveEntryList (&HotKey->Link);\r
+\r
+    FreePool (HotKey->KeyData);\r
+    FreePool (HotKey->HelpString);\r
+    FreePool (HotKey);\r
+  }\r
 }\r
 \r
 /**\r
-  Initialize the HII String Token to the correct values.\r
+\r
+  Update the Display form structure data.\r
 \r
 **/\r
 VOID\r
-InitializeBrowserStrings (\r
+UpdateDisplayFormData (\r
   VOID\r
   )\r
 {\r
-  gEnterString          = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle);\r
-  gEnterCommitString    = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle);\r
-  gEnterEscapeString    = GetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), gHiiHandle);\r
-  gEscapeString         = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle);\r
-  gMoveHighlight        = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle);\r
-  gMakeSelection        = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle);\r
-  gDecNumericInput      = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle);\r
-  gHexNumericInput      = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle);\r
-  gToggleCheckBox       = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle);\r
-  gPromptForData        = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);\r
-  gPromptForPassword    = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);\r
-  gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);\r
-  gConfirmPassword      = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);\r
-  gConfirmError         = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);\r
-  gPassowordInvalid     = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle);\r
-  gPressEnter           = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);\r
-  gEmptyString          = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
-  gAreYouSure           = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle);\r
-  gYesResponse          = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);\r
-  gNoResponse           = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);\r
-  gMiniString           = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);\r
-  gPlusString           = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle);\r
-  gMinusString          = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle);\r
-  gAdjustNumber         = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle);\r
-  gSaveChanges          = GetToken (STRING_TOKEN (SAVE_CHANGES), gHiiHandle);\r
-  gOptionMismatch       = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);\r
-  gFormSuppress         = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);\r
-  gProtocolNotFound     = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);\r
-  return ;\r
+  gDisplayFormData.FormTitle        = gCurrentSelection->Form->FormTitle;\r
+  gDisplayFormData.FormId           = gCurrentSelection->FormId;\r
+  gDisplayFormData.HiiHandle        = gCurrentSelection->Handle;\r
+  CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);\r
+\r
+  gDisplayFormData.Attribute        = 0;\r
+  gDisplayFormData.Attribute       |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;\r
+  gDisplayFormData.Attribute       |= gCurrentSelection->Form->Locked    ? HII_DISPLAY_LOCK  : 0;\r
+\r
+  gDisplayFormData.FormRefreshEvent     = NULL;\r
+  gDisplayFormData.HighLightedStatement = NULL;\r
+\r
+  gDisplayFormData.BrowserStatus = gBrowserStatus;\r
+  gDisplayFormData.ErrorString   = gErrorInfo;\r
+\r
+  gBrowserStatus = BROWSER_SUCCESS;\r
+  gErrorInfo     = NULL;\r
+\r
+  UpdateDataChangedFlag ();\r
+\r
+  AddStatementToDisplayForm ();\r
+}\r
+\r
+/**\r
+\r
+  Free the Display Statement structure data.\r
+\r
+  @param   StatementList         Point to the statement list which need to be free.\r
+\r
+**/\r
+VOID\r
+FreeStatementData (\r
+  LIST_ENTRY           *StatementList\r
+  )\r
+{\r
+  LIST_ENTRY                    *Link;\r
+  LIST_ENTRY                    *OptionLink;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+  DISPLAY_QUESTION_OPTION       *Option;\r
+\r
+  //\r
+  // Free Statements/Questions\r
+  //\r
+  while (!IsListEmpty (StatementList)) {\r
+    Link = GetFirstNode (StatementList);\r
+    Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
+\r
+    //\r
+    // Free Options List\r
+    //\r
+    while (!IsListEmpty (&Statement->OptionListHead)) {\r
+      OptionLink = GetFirstNode (&Statement->OptionListHead);\r
+      Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);\r
+      RemoveEntryList (&Option->Link);\r
+      FreePool (Option);\r
+    }\r
+\r
+    //\r
+    // Free nest statement List\r
+    //\r
+    if (!IsListEmpty (&Statement->NestStatementList)) {\r
+      FreeStatementData(&Statement->NestStatementList);\r
+    }\r
+\r
+    RemoveEntryList (&Statement->DisplayLink);\r
+    FreePool (Statement);\r
+  }\r
 }\r
 \r
 /**\r
-  Free up the resource allocated for all strings required\r
-  by Setup Browser.\r
+\r
+  Free the Display form structure data.\r
 \r
 **/\r
 VOID\r
-FreeBrowserStrings (\r
+FreeDisplayFormData (\r
   VOID\r
   )\r
 {\r
-  FreePool (gEnterString);\r
-  FreePool (gEnterCommitString);\r
-  FreePool (gEnterEscapeString);\r
-  FreePool (gEscapeString);\r
-  FreePool (gMoveHighlight);\r
-  FreePool (gMakeSelection);\r
-  FreePool (gDecNumericInput);\r
-  FreePool (gHexNumericInput);\r
-  FreePool (gToggleCheckBox);\r
-  FreePool (gPromptForData);\r
-  FreePool (gPromptForPassword);\r
-  FreePool (gPromptForNewPassword);\r
-  FreePool (gConfirmPassword);\r
-  FreePool (gPassowordInvalid);\r
-  FreePool (gConfirmError);\r
-  FreePool (gPressEnter);\r
-  FreePool (gEmptyString);\r
-  FreePool (gAreYouSure);\r
-  FreePool (gYesResponse);\r
-  FreePool (gNoResponse);\r
-  FreePool (gMiniString);\r
-  FreePool (gPlusString);\r
-  FreePool (gMinusString);\r
-  FreePool (gAdjustNumber);\r
-  FreePool (gSaveChanges);\r
-  FreePool (gOptionMismatch);\r
-  FreePool (gFormSuppress);\r
-  FreePool (gProtocolNotFound);\r
-  return ;\r
+  FreeStatementData (&gDisplayFormData.StatementListHead);\r
+  FreeStatementData (&gDisplayFormData.StatementListOSF);\r
+\r
+  FreeRefreshEvent();\r
+\r
+  FreeHotkeyList();\r
+}\r
+\r
+/**\r
+\r
+  Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.\r
+\r
+  @param DisplayStatement        The input FORM_DISPLAY_ENGINE_STATEMENT.\r
+\r
+  @retval FORM_BROWSER_STATEMENT  The return FORM_BROWSER_STATEMENT info.\r
+\r
+**/\r
+FORM_BROWSER_STATEMENT *\r
+GetBrowserStatement (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement\r
+  )\r
+{\r
+  FORM_BROWSER_STATEMENT *Statement;\r
+  LIST_ENTRY             *Link;\r
+\r
+  Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+  while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+    if (Statement->OpCode == DisplayStatement->OpCode) {\r
+      return Statement;\r
+    }\r
+\r
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+\r
+  Process the action request in user input.\r
+\r
+  @param Action                  The user input action request info.\r
+  @param DefaultId               The user input default Id info.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS \r
+ProcessAction (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  //\r
+  // This is caused by use press ESC, and it should not combine with other action type.\r
+  //\r
+  if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {\r
+    FindNextMenu (gCurrentSelection, FormLevel);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Below is normal hotkey trigged action, these action maybe combine with each other.\r
+  //\r
+  if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
+    DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
+    ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+    Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (EFI_ERROR (Status)) {\r
+      gBrowserStatus = BROWSER_SUBMIT_FAIL;\r
+    }\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+    gResetRequired = TRUE;\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
+    //\r
+    // Form Exit without saving, Similar to ESC Key.\r
+    // FormSet Exit without saving, Exit SendForm.\r
+    // System Exit without saving, CallExitHandler and Exit SendForm.\r
+    //\r
+    DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {\r
+      FindNextMenu (gCurrentSelection, gBrowserSettingScope);\r
+    } else if (gBrowserSettingScope == SystemLevel) {\r
+      if (ExitHandlerFunction != NULL) {\r
+        ExitHandlerFunction ();\r
+      }\r
+      gCurrentSelection->Action = UI_ACTION_EXIT;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find HII Handle in the HII database associated with given Device Path.\r
+\r
+  If DevicePath is NULL, then ASSERT.\r
+\r
+  @param  DevicePath             Device Path associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+EFIAPI\r
+DevicePathToHiiHandle (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;\r
+  UINTN                       BufferSize;\r
+  UINTN                       HandleCount;\r
+  UINTN                       Index;\r
+  EFI_HANDLE                  Handle;\r
+  EFI_HANDLE                  DriverHandle;\r
+  EFI_HII_HANDLE              *HiiHandles;\r
+  EFI_HII_HANDLE              HiiHandle;\r
+\r
+  ASSERT (DevicePath != NULL);\r
+\r
+  TmpDevicePath = DevicePath;\r
+  //\r
+  // Locate Device Path Protocol handle buffer\r
+  //\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &TmpDevicePath,\r
+                  &DriverHandle\r
+                  );\r
+  if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Retrieve all HII Handles from HII database\r
+  //\r
+  BufferSize = 0x1000;\r
+  HiiHandles = AllocatePool (BufferSize);\r
+  ASSERT (HiiHandles != NULL);\r
+  Status = mHiiDatabase->ListPackageLists (\r
+                           mHiiDatabase,\r
+                           EFI_HII_PACKAGE_TYPE_ALL,\r
+                           NULL,\r
+                           &BufferSize,\r
+                           HiiHandles\r
+                           );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FreePool (HiiHandles);\r
+    HiiHandles = AllocatePool (BufferSize);\r
+    ASSERT (HiiHandles != NULL);\r
+\r
+    Status = mHiiDatabase->ListPackageLists (\r
+                             mHiiDatabase,\r
+                             EFI_HII_PACKAGE_TYPE_ALL,\r
+                             NULL,\r
+                             &BufferSize,\r
+                             HiiHandles\r
+                             );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (HiiHandles);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Search Hii Handle by Driver Handle\r
+  //\r
+  HiiHandle = NULL;\r
+  HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = mHiiDatabase->GetPackageListHandle (\r
+                             mHiiDatabase,\r
+                             HiiHandles[Index],\r
+                             &Handle\r
+                             );\r
+    if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+      HiiHandle = HiiHandles[Index];\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+  return HiiHandle;\r
+}\r
+\r
+/**\r
+  Find HII Handle in the HII database associated with given form set guid.\r
+\r
+  If FormSetGuid is NULL, then ASSERT.\r
+\r
+  @param  ComparingGuid          FormSet Guid associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+  EFI_GUID     *ComparingGuid\r
+  )\r
+{\r
+  EFI_HII_HANDLE               *HiiHandles;\r
+  UINTN                        Index;\r
+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
+  UINTN                        BufferSize;\r
+  UINT32                       Offset;\r
+  UINT32                       Offset2;\r
+  UINT32                       PackageListLength;\r
+  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
+  UINT8                        *Package;\r
+  UINT8                        *OpCodeData;\r
+  EFI_STATUS                   Status;\r
+  EFI_HII_HANDLE               HiiHandle;\r
+\r
+  ASSERT (ComparingGuid != NULL);\r
+\r
+  HiiHandle  = NULL;\r
+  //\r
+  // Get all the Hii handles\r
+  //\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
+  //\r
+  // Search for formset of each class type\r
+  //\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    BufferSize = 0;\r
+    HiiPackageList = NULL;\r
+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      HiiPackageList = AllocatePool (BufferSize);\r
+      ASSERT (HiiPackageList != NULL);\r
+\r
+      Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    }\r
+    if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+      return NULL;\r
+    }\r
+\r
+    //\r
+    // Get Form package from this HII package List\r
+    //\r
+    Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+    Offset2 = 0;\r
+    CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+    while (Offset < PackageListLength) {\r
+      Package = ((UINT8 *) HiiPackageList) + Offset;\r
+      CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+      if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+        //\r
+        // Search FormSet in this Form Package\r
+        //\r
+        Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+        while (Offset2 < PackageHeader.Length) {\r
+          OpCodeData = Package + Offset2;\r
+\r
+          if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+            //\r
+            // Try to compare against formset GUID\r
+            //\r
+            if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+              HiiHandle = HiiHandles[Index];\r
+              break;\r
+            }\r
+          }\r
+\r
+          Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+        }\r
+      }\r
+      if (HiiHandle != NULL) {\r
+        break;\r
+      }\r
+      Offset += PackageHeader.Length;\r
+    }\r
+    \r
+    FreePool (HiiPackageList);\r
+       if (HiiHandle != NULL) {\r
+               break;\r
+       }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+\r
+  return HiiHandle;\r
+}\r
+\r
+/**\r
+  check how to process the changed data in current form or form set.\r
+\r
+  @param Selection       On input, Selection tell setup browser the information\r
+                         about the Selection, form and formset to be displayed.\r
+                         On output, Selection return the screen item that is selected\r
+                         by user.\r
+\r
+  @param Scope           Data save or discard scope, form or formset.\r
+\r
+  @retval                TRUE   Success process the changed data, will return to the parent form.\r
+  @retval                FALSE  Reject to process the changed data, will stay at  current form.\r
+**/\r
+BOOLEAN\r
+ProcessChangedData (\r
+  IN OUT UI_MENU_SELECTION       *Selection,\r
+  IN     BROWSER_SETTING_SCOPE   Scope\r
+  )\r
+{\r
+  BOOLEAN  RetValue;\r
+\r
+  RetValue = TRUE;\r
+  switch (mFormDisplay->ConfirmDataChange()) {\r
+    case BROWSER_ACTION_DISCARD:\r
+      DiscardForm (Selection->FormSet, Selection->Form, Scope);\r
+      break;\r
+  \r
+    case BROWSER_ACTION_SUBMIT:\r
+      SubmitForm (Selection->FormSet, Selection->Form, Scope);\r
+      break;\r
+\r
+    case BROWSER_ACTION_NONE:\r
+      RetValue = FALSE;\r
+      break;\r
+\r
+    default:\r
+      //\r
+      // if Invalid value return, process same as BROWSER_ACTION_NONE.\r
+      //\r
+      RetValue = FALSE;\r
+      break;\r
+  }\r
+\r
+  return RetValue;\r
+}\r
+\r
+/**\r
+  Find parent formset menu(the first menu which has different formset) for current menu.\r
+  If not find, just return to the first menu.\r
+\r
+  @param Selection    The selection info.\r
+\r
+**/\r
+VOID\r
+FindParentFormSet (\r
+  IN OUT   UI_MENU_SELECTION           *Selection\r
+  )\r
+{\r
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+  FORM_ENTRY_INFO            *ParentMenu;\r
+\r
+  CurrentMenu = Selection->CurrentMenu;\r
+  ParentMenu  = UiFindParentMenu(CurrentMenu);\r
+\r
+  //\r
+  // Find a menu which has different formset guid with current.\r
+  //\r
+  while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+    CurrentMenu = ParentMenu;\r
+    ParentMenu  = UiFindParentMenu(CurrentMenu);\r
+  }\r
+\r
+  if (ParentMenu != NULL) {\r
+    CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->Handle = ParentMenu->HiiHandle;\r
+    Selection->FormId     = ParentMenu->FormId;\r
+    Selection->QuestionId = ParentMenu->QuestionId;\r
+  } else {\r
+    Selection->FormId     = CurrentMenu->FormId;\r
+    Selection->QuestionId = CurrentMenu->QuestionId;\r
+  }\r
+\r
+  Selection->Statement  = NULL;\r
+}\r
+\r
+/**\r
+  Process the goto op code, update the info in the selection structure.\r
+\r
+  @param Statement    The statement belong to goto op code.\r
+  @param Selection    The selection info.\r
+\r
+  @retval EFI_SUCCESS    The menu process successfully.\r
+  @return Other value if the process failed.\r
+**/\r
+EFI_STATUS\r
+ProcessGotoOpCode (\r
+  IN OUT   FORM_BROWSER_STATEMENT      *Statement,\r
+  IN OUT   UI_MENU_SELECTION           *Selection\r
+  )\r
+{\r
+  CHAR16                          *StringPtr;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  FORM_BROWSER_FORM               *RefForm;\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+  \r
+  Status    = EFI_SUCCESS;\r
+  StringPtr = NULL;\r
+  HiiHandle = NULL;\r
+\r
+  //\r
+  // Prepare the device path check, get the device path info first.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+  }\r
+\r
+  //\r
+  // Check whether the device path string is a valid string.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Goto another Hii Package list\r
+    //\r
+    if (mPathFromText != NULL) {\r
+      DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+      if (DevicePath != NULL) {\r
+        HiiHandle = DevicePathToHiiHandle (DevicePath);\r
+        FreePool (DevicePath);\r
+      }\r
+      FreePool (StringPtr);\r
+    } else {\r
+      //\r
+      // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+      //\r
+      gBrowserStatus = BROWSER_PROTOCOL_NOT_FOUND;\r
+      FreePool (StringPtr);\r
+      return Status;\r
+    }\r
+\r
+    if (HiiHandle != Selection->Handle) {\r
+      //\r
+      // Goto another Formset, check for uncommitted data\r
+      //\r
+      if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+          IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+        if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    Selection->Handle = HiiHandle;\r
+    if (Selection->Handle == NULL) {\r
+      //\r
+      // If target Hii Handle not found, exit current formset.\r
+      //\r
+      FindParentFormSet(Selection);\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+    if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {\r
+      //\r
+      // Goto another Formset, check for uncommitted data\r
+      //\r
+      if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+         IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+        if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
+    if (Selection->Handle == NULL) {\r
+      //\r
+      // If target Hii Handle not found, exit current formset.\r
+      //\r
+      FindParentFormSet(Selection);\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
+    //\r
+    // Goto another Form, check for uncommitted data\r
+    //\r
+    if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {\r
+      if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {\r
+        if (!ProcessChangedData (Selection, FormLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+\r
+    RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+    if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+      if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
+        //\r
+        // Form is suppressed. \r
+        //\r
+        gBrowserStatus = BROWSER_FORM_SUPPRESS;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process Question Config.\r
+\r
+  @param  Selection              The UI menu selection.\r
+  @param  Question               The Question to be peocessed.\r
+\r
+  @retval EFI_SUCCESS            Question Config process success.\r
+  @retval Other                  Question Config process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessQuestionConfig (\r
+  IN  UI_MENU_SELECTION       *Selection,\r
+  IN  FORM_BROWSER_STATEMENT  *Question\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          *ConfigResp;\r
+  CHAR16                          *Progress;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+\r
+  if (Question->QuestionConfig == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get <ConfigResp>\r
+  //\r
+  ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);\r
+  if (ConfigResp == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Send config to Configuration Driver\r
+  //\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
+  if (ConfigAccess == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  Status = ConfigAccess->RouteConfig (\r
+                           ConfigAccess,\r
+                           ConfigResp,\r
+                           &Progress\r
+                           );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Process the user input data.\r
+\r
+  @param UserInput               The user input data.\r
+  @param ChangeHighlight         Whether need to change the highlight statement.  \r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessUserInput (\r
+  IN USER_INPUT               *UserInput,\r
+  IN BOOLEAN                  ChangeHighlight\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // When Exit from FormDisplay function, one of the below two cases must be true.\r
+  //\r
+  ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);\r
+\r
+  //\r
+  // Remove the last highligh question id, this id will update when show next form.\r
+  //\r
+  gCurrentSelection->QuestionId = 0;\r
+\r
+  //\r
+  // First process the Action field in USER_INPUT.\r
+  //\r
+  if (UserInput->Action != 0) {\r
+    Status = ProcessAction (UserInput->Action, UserInput->DefaultId);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Clear the highlight info.\r
+    //\r
+    gCurrentSelection->Statement = NULL;\r
+\r
+    if (UserInput->SelectedStatement != NULL) {\r
+      Statement = GetBrowserStatement(UserInput->SelectedStatement);\r
+      ASSERT (Statement != NULL);\r
+      //\r
+      // Save the current highlight menu in the menu history data.\r
+      // which will be used when later browse back to this form.\r
+      //\r
+      gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;\r
+      //\r
+      // For statement like text, actio, it not has question id.\r
+      // So use FakeQuestionId to save the question.\r
+      //\r
+      if (gCurrentSelection->CurrentMenu->QuestionId == 0) {\r
+        mCurFakeQestId = Statement->FakeQuestionId;\r
+      } else {\r
+        mCurFakeQestId = 0;\r
+      }\r
+    }\r
+  } else {\r
+    Statement = GetBrowserStatement(UserInput->SelectedStatement);\r
+    ASSERT (Statement != NULL);\r
+\r
+    gCurrentSelection->Statement = Statement;\r
+\r
+    if (ChangeHighlight) {\r
+      //\r
+      // This question is the current user select one,record it and later\r
+      // show it as the highlight question.\r
+      //\r
+      gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;\r
+      //\r
+      // For statement like text, actio, it not has question id.\r
+      // So use FakeQuestionId to save the question.\r
+      //\r
+      if (gCurrentSelection->CurrentMenu->QuestionId == 0) {\r
+        mCurFakeQestId = Statement->FakeQuestionId;\r
+      } else {\r
+        mCurFakeQestId = 0;\r
+      }\r
+    }\r
+\r
+    switch (Statement->Operand) {\r
+    case EFI_IFR_REF_OP:\r
+      Status = ProcessGotoOpCode(Statement, gCurrentSelection);\r
+      break;\r
+    \r
+    case EFI_IFR_ACTION_OP:\r
+      //\r
+      // Process the Config string <ConfigResp>\r
+      //\r
+      Status = ProcessQuestionConfig (gCurrentSelection, Statement);\r
+      break;\r
+    \r
+    case EFI_IFR_RESET_BUTTON_OP:\r
+      //\r
+      // Reset Question to default value specified by DefaultId\r
+      //\r
+      Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);\r
+      break;\r
+\r
+    default:\r
+      switch (Statement->Operand) {\r
+      case EFI_IFR_STRING_OP:\r
+        DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);\r
+        Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;\r
+        CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+        FreePool (UserInput->InputValue.Buffer);\r
+        break;\r
+\r
+      case EFI_IFR_PASSWORD_OP:\r
+        if (UserInput->InputValue.Buffer == NULL) {\r
+          //\r
+          // User not input new password, just return.\r
+          //\r
+          break;\r
+        }\r
+\r
+        DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);\r
+        Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;\r
+        CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+        FreePool (UserInput->InputValue.Buffer);\r
+        //\r
+        // Two password match, send it to Configuration Driver\r
+        //\r
+        if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);\r
+          //\r
+          // Clean the value after saved it.\r
+          //\r
+          ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);\r
+          HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);\r
+        } else {\r
+          SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);\r
+        }\r
+        break;\r
+\r
+      case EFI_IFR_ORDERED_LIST_OP:\r
+        CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);\r
+        break;\r
+\r
+      default:\r
+        CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));\r
+        break;\r
+      }\r
+      if (Statement->Operand != EFI_IFR_PASSWORD_OP) {\r
+        SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
-  Show all registered HotKey help strings on bottom Rows.\r
+\r
+  Display form and wait for user to select one menu option, then return it.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
 \r
 **/\r
-VOID\r
-PrintHotKeyHelpString (\r
+EFI_STATUS\r
+DisplayForm (\r
   VOID\r
   )\r
 {\r
-  UINTN                  CurrentCol;\r
-  UINTN                  CurrentRow;\r
-  UINTN                  BottomRowOfHotKeyHelp;\r
-  UINTN                  ColumnWidth;\r
-  UINTN                  Index;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  LIST_ENTRY             *Link;\r
-  BROWSER_HOT_KEY        *HotKey;\r
+  EFI_STATUS               Status;\r
+  USER_INPUT               UserInput;\r
+  FORM_ENTRY_INFO          *CurrentMenu;\r
+  BOOLEAN                  ChangeHighlight;\r
 \r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-  ColumnWidth            = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;\r
-  BottomRowOfHotKeyHelp  = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;\r
+  ZeroMem (&UserInput, sizeof (USER_INPUT));\r
 \r
   //\r
-  // Calculate total number of Register HotKeys. \r
+  // Update the menu history data.\r
   //\r
-  Index = 0;\r
-  Link  = GetFirstNode (&gBrowserHotKeyList);\r
-  while (!IsNull (&gBrowserHotKeyList, Link)) {\r
-    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
-    //\r
-    // Help string can't exceed ColumnWidth. One Row will show three Help information. \r
-    //\r
-    if (StrLen (HotKey->HelpString) > ColumnWidth) {\r
-      HotKey->HelpString[ColumnWidth] = L'\0';\r
-    }\r
-    //\r
-    // Calculate help information Column and Row.\r
-    //\r
-    if ((Index % 3) != 2) {\r
-      CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth;\r
-    } else {\r
-      CurrentCol = LocalScreen.LeftColumn + 2;\r
-    }\r
-    CurrentRow = BottomRowOfHotKeyHelp - Index / 3;\r
+  CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);\r
+  if (CurrentMenu == NULL) {\r
     //\r
-    // Print HotKey help string on bottom Row.\r
+    // Current menu not found, add it to the menu tree\r
     //\r
-    PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString);\r
+    CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,\r
+                                 gCurrentSelection->FormId, gCurrentSelection->QuestionId);\r
+    ASSERT (CurrentMenu != NULL);\r
+  }\r
+  gCurrentSelection->CurrentMenu = CurrentMenu;\r
 \r
+  //\r
+  // Find currrent highlight statement.\r
+  //\r
+  if (gCurrentSelection->QuestionId == 0) {\r
     //\r
-    // Get Next Hot Key.\r
+    // Highlight not specified, fetch it from cached menu\r
     //\r
-    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
-    Index ++;\r
+    gCurrentSelection->QuestionId = CurrentMenu->QuestionId;\r
   }\r
-  \r
-  return;\r
-}\r
-\r
-/**\r
-  Update key's help imformation.\r
-\r
-  @param Selection       Tell setup browser the information about the Selection\r
-  @param  MenuOption     The Menu option\r
-  @param  Selected       Whether or not a tag be selected\r
-\r
-**/\r
-VOID\r
-UpdateKeyHelp (\r
-  IN  UI_MENU_SELECTION           *Selection,\r
-  IN  UI_MENU_OPTION              *MenuOption,\r
-  IN  BOOLEAN                     Selected\r
-  )\r
-{\r
-  UINTN                  SecCol;\r
-  UINTN                  ThdCol;\r
-  UINTN                  LeftColumnOfHelp;\r
-  UINTN                  RightColumnOfHelp;\r
-  UINTN                  TopRowOfHelp;\r
-  UINTN                  BottomRowOfHelp;\r
-  UINTN                  StartColumnOfHelp;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  FORM_BROWSER_STATEMENT *Statement;\r
 \r
-  gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-  if (Selection->Form->ModalForm) {\r
-    return;\r
+  //\r
+  // Evaluate all the Expressions in this Form\r
+  //\r
+  Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-\r
-  SecCol            = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;\r
-  ThdCol            = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3 * 2;\r
-\r
-  StartColumnOfHelp = LocalScreen.LeftColumn + 2;\r
-  LeftColumnOfHelp  = LocalScreen.LeftColumn + 1;\r
-  RightColumnOfHelp = LocalScreen.RightColumn - 2;\r
-  TopRowOfHelp      = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;\r
-  BottomRowOfHelp   = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;\r
-\r
-  Statement = MenuOption->ThisTag;\r
-  switch (Statement->Operand) {\r
-  case EFI_IFR_ORDERED_LIST_OP:\r
-  case EFI_IFR_ONE_OF_OP:\r
-  case EFI_IFR_NUMERIC_OP:\r
-  case EFI_IFR_TIME_OP:\r
-  case EFI_IFR_DATE_OP:\r
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-    if (!Selected) {\r
-      //\r
-      // On system setting, HotKey will show on every form.\r
-      //\r
-      if (gBrowserSettingScope == SystemLevel ||\r
-          (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
-        PrintHotKeyHelpString ();\r
-      }\r
-\r
-      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-      }\r
-\r
-      if ((Statement->Operand == EFI_IFR_DATE_OP) ||\r
-          (Statement->Operand == EFI_IFR_TIME_OP)) {\r
-        PrintAt (\r
-          StartColumnOfHelp,\r
-          BottomRowOfHelp,\r
-          L"%c%c%c%c%s",\r
-          ARROW_UP,\r
-          ARROW_DOWN,\r
-          ARROW_RIGHT,\r
-          ARROW_LEFT,\r
-          gMoveHighlight\r
-          );\r
-        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
-        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);\r
-      } else {\r
-        PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-        if (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0) {\r
-          PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);\r
-        } \r
-        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
-      }\r
-    } else {\r
-      PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);\r
-\r
-      //\r
-      // If it is a selected numeric with manual input, display different message\r
-      //\r
-      if ((Statement->Operand == EFI_IFR_NUMERIC_OP) || \r
-          (Statement->Operand == EFI_IFR_DATE_OP) ||\r
-          (Statement->Operand == EFI_IFR_TIME_OP)) {\r
-        PrintStringAt (\r
-          SecCol,\r
-          TopRowOfHelp,\r
-          ((Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput\r
-          );\r
-      } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) {\r
-        PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-      }\r
-\r
-      if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
-        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);\r
-        PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);\r
-      }\r
-\r
-      PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);\r
-    }\r
-    break;\r
-\r
-  case EFI_IFR_CHECKBOX_OP:\r
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-    //\r
-    // On system setting, HotKey will show on every form.\r
-    //\r
-    if (gBrowserSettingScope == SystemLevel ||\r
-        (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
-      PrintHotKeyHelpString ();\r
-    }\r
-    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-      PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-    }\r
+  UpdateDisplayFormData ();\r
 \r
-    PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-    PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);\r
-    break;\r
+  //\r
+  // Three possible status maybe return.\r
+  //\r
+  // EFI_INVALID_PARAMETER: The input dimension info is not valid.\r
+  // EFI_NOT_FOUND:         The input value for oneof/orderedlist opcode is not valid\r
+  //                        and an valid value has return.\r
+  // EFI_SUCCESS:           Success shows form and get user input in UserInput paramenter.\r
+  //\r
+  Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);\r
+  if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {\r
+    FreeDisplayFormData();\r
+    return Status;\r
+  }\r
 \r
-  case EFI_IFR_REF_OP:\r
-  case EFI_IFR_PASSWORD_OP:\r
-  case EFI_IFR_STRING_OP:\r
-  case EFI_IFR_TEXT_OP:\r
-  case EFI_IFR_ACTION_OP:\r
-  case EFI_IFR_RESET_BUTTON_OP:\r
-  case EFI_IFR_SUBTITLE_OP:\r
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
+  //\r
+  // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return.\r
+  //                           in this case, browser need to change the highlight menu.\r
+  // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist \r
+  //                          opcode and new valid value has return, browser core need to adjust\r
+  //                          value for this opcode and shows this form again.\r
+  //\r
+  ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE);\r
 \r
-    if (!Selected) {\r
-      //\r
-      // On system setting, HotKey will show on every form.\r
-      //\r
-      if (gBrowserSettingScope == SystemLevel ||\r
-          (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
-        PrintHotKeyHelpString ();\r
-      }\r
-      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-      }\r
+  Status = ProcessUserInput (&UserInput, ChangeHighlight);\r
 \r
-      PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-      if (Statement->Operand != EFI_IFR_TEXT_OP && Statement->Operand != EFI_IFR_SUBTITLE_OP) {\r
-        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
-      }\r
-    } else {\r
-      if (Statement->Operand != EFI_IFR_REF_OP) {\r
-        PrintStringAt (\r
-          (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2,\r
-          BottomRowOfHelp,\r
-          gEnterCommitString\r
-          );\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);\r
-      }\r
-    }\r
-    break;\r
+  FreeDisplayFormData();\r
 \r
-  default:\r
-    break;\r
-  }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -920,60 +1715,136 @@ FormUpdateNotify (
 }\r
 \r
 /**\r
-  check whether the formset need to update the NV.\r
+  Update the NV flag info for this form set.\r
 \r
   @param  FormSet                FormSet data structure.\r
 \r
-  @retval TRUE                   Need to update the NV.\r
-  @retval FALSE                  No need to update the NV.\r
 **/\r
-BOOLEAN \r
-IsNvUpdateRequired (\r
+BOOLEAN\r
+IsNvUpdateRequiredForFormSet (\r
   IN FORM_BROWSER_FORMSET  *FormSet\r
   )\r
 {\r
   LIST_ENTRY              *Link;\r
   FORM_BROWSER_FORM       *Form;\r
+  BOOLEAN                 RetVal;\r
+\r
+  //\r
+  // Not finished question initialization, return FALSE.\r
+  //\r
+  if (!FormSet->QuestionInited) {\r
+    return FALSE;\r
+  }\r
+\r
+  RetVal = FALSE;\r
 \r
   Link = GetFirstNode (&FormSet->FormListHead);\r
   while (!IsNull (&FormSet->FormListHead, Link)) {\r
     Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
 \r
-    if (Form->NvUpdateRequired ) {\r
-      return TRUE;\r
+    RetVal = IsNvUpdateRequiredForForm(Form);\r
+    if (RetVal) {\r
+      break;\r
     }\r
 \r
     Link = GetNextNode (&FormSet->FormListHead, Link);\r
   }\r
 \r
+  return RetVal;\r
+}\r
+\r
+/**\r
+  Update the NvUpdateRequired flag for a form.\r
+\r
+  @param  Form                Form data structure.\r
+\r
+**/\r
+BOOLEAN\r
+IsNvUpdateRequiredForForm (\r
+  IN FORM_BROWSER_FORM    *Form\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_STATEMENT  *Statement;\r
+\r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+    if (Statement->ValueChanged) {\r
+      return TRUE;\r
+    }\r
+\r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+  }\r
+\r
   return FALSE;\r
 }\r
 \r
 /**\r
-  check whether the formset need to update the NV.\r
+  Check whether the storage data for current form set is changed.\r
 \r
-  @param  FormSet                FormSet data structure.\r
-  @param  SetValue               Whether set new value or clear old value.\r
+  @param  FormSet           FormSet data structure.\r
 \r
+  @retval TRUE              Data is changed.\r
+  @retval FALSE             Data is not changed.\r
 **/\r
-VOID\r
-UpdateNvInfoInForm (\r
-  IN FORM_BROWSER_FORMSET  *FormSet,\r
-  IN BOOLEAN               SetValue\r
+BOOLEAN \r
+IsStorageDataChangedForFormSet (\r
+  IN FORM_BROWSER_FORMSET             *FormSet\r
   )\r
 {\r
   LIST_ENTRY              *Link;\r
-  FORM_BROWSER_FORM       *Form;\r
-  \r
-  Link = GetFirstNode (&FormSet->FormListHead);\r
-  while (!IsNull (&FormSet->FormListHead, Link)) {\r
-    Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+  FORMSET_STORAGE         *Storage;\r
+  BROWSER_STORAGE         *BrowserStorage;\r
+  CHAR16                  *ConfigRespNew;\r
+  CHAR16                  *ConfigRespOld;\r
+  BOOLEAN                 RetVal;\r
 \r
-    Form->NvUpdateRequired = SetValue;\r
+  RetVal        = FALSE;\r
+  ConfigRespNew = NULL;\r
+  ConfigRespOld = NULL;\r
 \r
-    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  //\r
+  // Request current settings from Configuration Driver\r
+  //\r
+  Link = GetFirstNode (&FormSet->StorageListHead);\r
+  while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+    Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+\r
+    BrowserStorage = Storage->BrowserStorage;\r
+\r
+    if (BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+      continue;\r
+    }\r
+\r
+    if (Storage->ElementCount == 0) {\r
+      continue;\r
+    }\r
+\r
+    StorageToConfigResp (BrowserStorage, &ConfigRespNew, Storage->ConfigRequest, TRUE);\r
+    StorageToConfigResp (BrowserStorage, &ConfigRespOld, Storage->ConfigRequest, FALSE);\r
+    ASSERT (ConfigRespNew != NULL && ConfigRespOld != NULL);\r
+\r
+    if (StrCmp (ConfigRespNew, ConfigRespOld) != 0) {\r
+      RetVal = TRUE;\r
+    }\r
+\r
+    FreePool (ConfigRespNew);\r
+    ConfigRespNew = NULL;\r
+\r
+    FreePool (ConfigRespOld);\r
+    ConfigRespOld = NULL;\r
+\r
+    if (RetVal) {\r
+      break;\r
+    }\r
   }\r
+\r
+  return RetVal;\r
 }\r
+\r
 /**\r
   Find menu which will show next time.\r
 \r
@@ -981,170 +1852,92 @@ UpdateNvInfoInForm (
                          about the Selection, form and formset to be displayed.\r
                          On output, Selection return the screen item that is selected\r
                          by user.\r
-  @param Repaint         Whether need to repaint the menu.\r
-  @param NewLine         Whether need to show at new line.\r
+  @param SettingLevel    Input Settting level, if it is FormLevel, just exit current form. \r
+                         else, we need to exit current formset.\r
   \r
-  @retval TRUE           Need return.\r
-  @retval FALSE          No need to return.\r
+  @retval TRUE           Exit current form.\r
+  @retval FALSE          User press ESC and keep in current form.\r
 **/\r
 BOOLEAN\r
 FindNextMenu (\r
-  IN OUT UI_MENU_SELECTION    *Selection,\r
-  IN     BOOLEAN              *Repaint, \r
-  IN     BOOLEAN              *NewLine  \r
+  IN OUT UI_MENU_SELECTION        *Selection,\r
+  IN       BROWSER_SETTING_SCOPE  SettingLevel\r
   )\r
 {\r
-  UI_MENU_LIST            *CurrentMenu;\r
-  CHAR16                  YesResponse;\r
-  CHAR16                  NoResponse;\r
-  EFI_INPUT_KEY           Key;\r
-  BROWSER_SETTING_SCOPE   Scope;\r
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+  FORM_ENTRY_INFO            *ParentMenu;\r
+  BROWSER_SETTING_SCOPE      Scope;\r
   \r
   CurrentMenu = Selection->CurrentMenu;\r
+  ParentMenu  = NULL;\r
+  Scope       = FormSetLevel;\r
 \r
-  if (CurrentMenu != NULL && CurrentMenu->Parent != NULL) {\r
+  if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) {\r
     //\r
     // we have a parent, so go to the parent menu\r
     //\r
-    if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
-      //\r
-      // The parent menu and current menu are in the same formset\r
-      //\r
-      Selection->Action = UI_ACTION_REFRESH_FORM;\r
-      Scope             = FormLevel;\r
-    } else {\r
-      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-      CopyMem (&Selection->FormSetGuid, &CurrentMenu->Parent->FormSetGuid, sizeof (EFI_GUID));\r
-      Selection->Handle = CurrentMenu->Parent->HiiHandle;\r
-      Scope             = FormSetLevel;\r
-    }\r
-\r
-    //\r
-    // Form Level Check whether the data is changed.\r
-    //\r
-    if ((gBrowserSettingScope == FormLevel && Selection->Form->NvUpdateRequired) ||\r
-        (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequired(Selection->FormSet) && Scope == FormSetLevel)) {\r
-      gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-  \r
-      YesResponse = gYesResponse[0];\r
-      NoResponse  = gNoResponse[0];\r
-  \r
-      //\r
-      // If NV flag is up, prompt user\r
-      //\r
-      do {\r
-        CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
-      } while\r
-      (\r
-        (Key.ScanCode != SCAN_ESC) &&\r
-        ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-        ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-      );\r
-  \r
-      if (Key.ScanCode == SCAN_ESC) {\r
+    if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+      if (SettingLevel == FormSetLevel) {\r
         //\r
-        // User hits the ESC key, Ingore. \r
+        // Find a menu which has different formset guid with current.\r
         //\r
-        if (Repaint != NULL) {\r
-          *Repaint = TRUE;\r
-        }\r
-        if (NewLine != NULL) {\r
-          *NewLine = TRUE;\r
+        while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+          CurrentMenu = ParentMenu;\r
+          if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) {\r
+            break;\r
+          }\r
         }\r
 \r
-        Selection->Action = UI_ACTION_NONE;\r
-        return FALSE;\r
-      }\r
-  \r
-      if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-        //\r
-        // If the user hits the YesResponse key\r
-        //\r
-        SubmitForm (Selection->FormSet, Selection->Form, Scope);\r
+        if (ParentMenu != NULL) {\r
+          Scope = FormSetLevel;\r
+        }\r
       } else {\r
-        //\r
-        // If the user hits the NoResponse key\r
-        //\r
-        DiscardForm (Selection->FormSet, Selection->Form, Scope);\r
+        Scope = FormLevel;\r
       }\r
+    } else {\r
+      Scope = FormSetLevel;\r
     }\r
-\r
-    Selection->Statement = NULL;\r
-\r
-    Selection->FormId = CurrentMenu->Parent->FormId;\r
-    Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
-\r
-    //\r
-    // Clear highlight record for this menu\r
-    //\r
-    CurrentMenu->QuestionId = 0;\r
-    return FALSE;\r
-  }\r
-\r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-    //\r
-    // We never exit FrontPage, so skip the ESC\r
-    //\r
-    Selection->Action = UI_ACTION_NONE;\r
-    return FALSE;\r
   }\r
 \r
   //\r
-  // We are going to leave current FormSet, so check uncommited data in this FormSet\r
+  // Form Level Check whether the data is changed.\r
   //\r
-  if (gBrowserSettingScope != SystemLevel && IsNvUpdateRequired(Selection->FormSet)) {\r
-    gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
-    YesResponse = gYesResponse[0];\r
-    NoResponse  = gNoResponse[0];\r
-\r
-    //\r
-    // If NV flag is up, prompt user\r
-    //\r
-    do {\r
-      CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
-    } while\r
-    (\r
-      (Key.ScanCode != SCAN_ESC) &&\r
-      ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-      ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-    );\r
-\r
-    if (Key.ScanCode == SCAN_ESC) {\r
-      //\r
-      // User hits the ESC key\r
-      //\r
-      if (Repaint != NULL) {\r
-        *Repaint = TRUE;\r
-      }\r
-\r
-      if (NewLine != NULL) {\r
-        *NewLine = TRUE;\r
-      }\r
-\r
-      Selection->Action = UI_ACTION_NONE;\r
+  if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||\r
+      (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {\r
+    if (!ProcessChangedData(Selection, Scope)) {\r
       return FALSE;\r
     }\r
+  }\r
 \r
-    if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-      //\r
-      // If the user hits the YesResponse key\r
-      //\r
-      SubmitForm (Selection->FormSet, Selection->Form, FormSetLevel);\r
+  if (ParentMenu != NULL) {\r
+    //\r
+    // ParentMenu is found. Then, go to it.\r
+    //\r
+    if (Scope == FormLevel) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
     } else {\r
-      //\r
-      // If the user hits the NoResponse key\r
-      //\r
-      DiscardForm (Selection->FormSet, Selection->Form, FormSetLevel);\r
+      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+      CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+      Selection->Handle = ParentMenu->HiiHandle;\r
     }\r
-  }\r
 \r
-  Selection->Statement = NULL;\r
-  if (CurrentMenu != NULL) {\r
+    Selection->Statement = NULL;\r
+\r
+    Selection->FormId = ParentMenu->FormId;\r
+    Selection->QuestionId = ParentMenu->QuestionId;\r
+\r
+    //\r
+    // Clear highlight record for this menu\r
+    //\r
     CurrentMenu->QuestionId = 0;\r
+    return FALSE;\r
   }\r
 \r
+  //\r
+  // Current in root page, exit the SendForm\r
+  //\r
   Selection->Action = UI_ACTION_EXIT;\r
+\r
   return TRUE;\r
 }\r
 \r
@@ -1244,18 +2037,19 @@ ProcessCallBackFunction (
       if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
         switch (ActionRequest) {\r
         case EFI_BROWSER_ACTION_REQUEST_RESET:\r
+          DiscardFormIsRequired = TRUE;\r
           gResetRequired = TRUE;\r
-          Selection->Action = UI_ACTION_EXIT;\r
+          NeedExit              = TRUE;\r
           break;\r
 \r
         case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
           SubmitFormIsRequired = TRUE;\r
-          Selection->Action = UI_ACTION_EXIT;\r
+          NeedExit              = TRUE;\r
           break;\r
 \r
         case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
           DiscardFormIsRequired = TRUE;\r
-          Selection->Action = UI_ACTION_EXIT;\r
+          NeedExit              = TRUE;\r
           break;\r
 \r
         case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:\r
@@ -1266,7 +2060,7 @@ ProcessCallBackFunction (
 \r
         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:\r
           DiscardFormIsRequired = TRUE;\r
-          SettingLevel          = FormLevel;      \r
+          SettingLevel          = FormLevel;\r
           NeedExit              = TRUE;\r
           break;\r
 \r
@@ -1319,7 +2113,7 @@ ProcessCallBackFunction (
   }\r
 \r
   if (NeedExit) {\r
-    FindNextMenu (Selection, NULL, NULL);\r
+    FindNextMenu (Selection, SettingLevel);\r
   }\r
 \r
   return Status;\r
@@ -1399,9 +2193,7 @@ SetupBrowser (
   EFI_HANDLE                      NotifyHandle;\r
   FORM_BROWSER_STATEMENT          *Statement;\r
   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  EFI_INPUT_KEY                   Key;\r
 \r
-  gMenuRefreshHead = NULL;\r
   ConfigAccess = Selection->FormSet->ConfigAccess;\r
 \r
   //\r
@@ -1422,21 +2214,17 @@ SetupBrowser (
   //\r
   // Initialize current settings of Questions in this FormSet\r
   //\r
-  Status = InitializeCurrentSetting (Selection->FormSet);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Done;\r
-  }\r
+  InitializeCurrentSetting (Selection->FormSet);\r
 \r
   //\r
-  // Update gOldFormSet on maintain back up FormSet list.\r
-  // And, make gOldFormSet point to current FormSet. \r
+  // Initilize Action field.\r
   //\r
-  if (gOldFormSet != NULL) {\r
-    RemoveEntryList (&gOldFormSet->Link);\r
-    DestroyFormSet (gOldFormSet);\r
-  }\r
-  gOldFormSet = Selection->FormSet;\r
-  InsertTailList (&gBrowserFormSetList, &gOldFormSet->Link);\r
+  Selection->Action = UI_ACTION_REFRESH_FORM;\r
+\r
+  //\r
+  // Clean the mCurFakeQestId value is formset refreshed.\r
+  //\r
+  mCurFakeQestId = 0;\r
 \r
   do {\r
     //\r
@@ -1479,10 +2267,7 @@ SetupBrowser (
         //\r
         // Form is suppressed. \r
         //\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
-\r
+        gBrowserStatus = BROWSER_FORM_SUPPRESS;\r
         Status = EFI_NOT_FOUND;\r
         goto Done;\r
       }\r
@@ -1497,7 +2282,6 @@ SetupBrowser (
         ((Selection->Handle != mCurrentHiiHandle) ||\r
         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||\r
         (Selection->FormId != mCurrentFormId))) {\r
-\r
       //\r
       // Keep current form information\r
       //\r
@@ -1510,12 +2294,6 @@ SetupBrowser (
         goto Done;\r
       }\r
 \r
-      //\r
-      // EXIT requests to close form.\r
-      //\r
-      if (Selection->Action == UI_ACTION_EXIT) {\r
-        goto Done;\r
-      }\r
       //\r
       // IFR is updated during callback of open form, force to reparse the IFR binary\r
       //\r
@@ -1534,12 +2312,6 @@ SetupBrowser (
       goto Done;\r
     }\r
 \r
-    //\r
-    // EXIT requests to close form.\r
-    //\r
-    if (Selection->Action == UI_ACTION_EXIT) {\r
-      goto Done;\r
-    }\r
     //\r
     // IFR is updated during callback of read value, force to reparse the IFR binary\r
     //\r
@@ -1549,15 +2321,10 @@ SetupBrowser (
       break;\r
     }\r
 \r
-    //\r
-    // Displays the Header and Footer borders\r
-    //\r
-    DisplayPageFrame (Selection);\r
-\r
     //\r
     // Display form\r
     //\r
-    Status = DisplayForm (Selection);\r
+    Status = DisplayForm ();\r
     if (EFI_ERROR (Status)) {\r
       goto Done;\r
     }\r
@@ -1567,20 +2334,16 @@ SetupBrowser (
     //\r
     Statement = Selection->Statement;\r
     if (Statement != NULL) {\r
-      if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) {\r
-        gResetRequired = TRUE;\r
-      }\r
-\r
       if ((ConfigAccess != NULL) && \r
           ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && \r
           (Statement->Operand != EFI_IFR_PASSWORD_OP)) {\r
-        Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);         \r
-        if (Statement->Operand == EFI_IFR_REF_OP && Selection->Action != UI_ACTION_EXIT) {\r
+        Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+        if (Statement->Operand == EFI_IFR_REF_OP) {\r
           //\r
           // Process dynamic update ref opcode.\r
           //\r
           if (!EFI_ERROR (Status)) {\r
-            Status = ProcessGotoOpCode(Statement, Selection, NULL, NULL);\r
+            Status = ProcessGotoOpCode(Statement, Selection);\r
           }\r
           \r
           //\r
@@ -1601,6 +2364,27 @@ SetupBrowser (
       }\r
     }\r
 \r
+    //\r
+    // Check whether Exit flag is TRUE.\r
+    //\r
+    if (gExitRequired) {\r
+      switch (gBrowserSettingScope) {\r
+      case SystemLevel:\r
+        Selection->Action = UI_ACTION_EXIT;\r
+        break;\r
+\r
+      case FormSetLevel:\r
+      case FormLevel:\r
+        FindNextMenu (Selection, gBrowserSettingScope);\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      gExitRequired = FALSE;\r
+    }\r
+\r
     //\r
     // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE\r
     // for each question with callback flag.\r