]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
Add code check to avoid access violation.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Presentation.c
index a89bb2f50b28029cecd252a1a8c1a70ac7a78a88..28ed0348ed2761b99bd50f6d947c29d80f0662b3 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Utility functions for UI presentation.\r
 \r
-Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -16,7 +16,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 BOOLEAN            mHiiPackageListUpdated;\r
 UI_MENU_SELECTION  *gCurrentSelection;\r
-\r
+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
 \r
 /**\r
   Clear retangle with specified text attribute.\r
@@ -180,10 +182,13 @@ GetStringWidth (
 /**\r
   This function displays the page frame.\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
-  VOID\r
+  IN UI_MENU_SELECTION    *Selection\r
   )\r
 {\r
   UINTN                  Index;\r
@@ -201,6 +206,10 @@ DisplayPageFrame (
   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
 \r
   //\r
@@ -257,7 +266,7 @@ DisplayPageFrame (
           //\r
           // Handle left column\r
           //\r
-          PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner);\r
+          PrintStringAt (LocalScreen.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);\r
           break;\r
 \r
         case 1:\r
@@ -291,7 +300,7 @@ DisplayPageFrame (
   ClearLines (\r
     LocalScreen.LeftColumn,\r
     LocalScreen.RightColumn,\r
-    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT,\r
+    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,\r
     LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1,\r
     KEYHELP_TEXT | KEYHELP_BACKGROUND\r
     );\r
@@ -339,14 +348,14 @@ DisplayPageFrame (
       // +------------------------------------------------------------------------------+\r
       //\r
       Character = BOXDRAW_DOWN_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character);\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 - FOOTER_HEIGHT + 1;\r
+      for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;\r
            Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;\r
            Row++\r
           ) {\r
@@ -459,7 +468,6 @@ DisplayForm (
   CHAR16                 *StringPtr;\r
   UINT16                 MenuItemCount;\r
   EFI_HII_HANDLE         Handle;\r
-  BOOLEAN                Suppress;\r
   EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
   UINT16                 Width;\r
   UINTN                  ArrayEntry;\r
@@ -482,7 +490,11 @@ DisplayForm (
   StringPtr = GetToken (Selection->Form->FormTitle, Handle);\r
 \r
   if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-    gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);\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
     PrintStringAt (\r
       (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,\r
       LocalScreen.TopRow + 1,\r
@@ -508,18 +520,9 @@ DisplayForm (
   while (!IsNull (&Selection->Form->StatementListHead, Link)) {\r
     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
 \r
-    if (Statement->SuppressExpression != NULL) {\r
-      Suppress = Statement->SuppressExpression->Result.Value.b;\r
-    } else {\r
-      Suppress = FALSE;\r
-    }\r
-\r
-    if (Statement->DisableExpression != NULL) {\r
-      Suppress = (BOOLEAN) (Suppress || Statement->DisableExpression->Result.Value.b);\r
-    }\r
-\r
-    if (!Suppress) {\r
+    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) <= ExpressGrayOut) {\r
       StringPtr = GetToken (Statement->Prompt, Handle);\r
+      ASSERT (StringPtr != NULL);\r
 \r
       Width     = GetWidth (Statement, Handle);\r
 \r
@@ -540,7 +543,7 @@ DisplayForm (
       // 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, Statement, NumberOfLines, MenuItemCount);\r
+      MenuOption = UiAddMenuOption (StringPtr, Selection->Handle, Selection->Form, Statement, NumberOfLines, MenuItemCount);\r
       MenuItemCount++;\r
 \r
       if (MenuOption->IsQuestion && !MenuOption->ReadOnly) {\r
@@ -570,13 +573,10 @@ InitializeBrowserStrings (
   VOID\r
   )\r
 {\r
-  gFunctionNineString   = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);\r
-  gFunctionTenString    = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);\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
-  gSaveFailed           = GetToken (STRING_TOKEN (SAVE_FAILED), 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
@@ -613,8 +613,6 @@ FreeBrowserStrings (
   VOID\r
   )\r
 {\r
-  FreePool (gFunctionNineString);\r
-  FreePool (gFunctionTenString);\r
   FreePool (gEnterString);\r
   FreePool (gEnterCommitString);\r
   FreePool (gEnterEscapeString);\r
@@ -645,6 +643,64 @@ FreeBrowserStrings (
   return ;\r
 }\r
 \r
+/**\r
+  Show all registered HotKey help strings on bottom Rows.\r
+\r
+**/\r
+VOID\r
+PrintHotKeyHelpString (\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
+\r
+  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+  ColumnWidth            = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;\r
+  BottomRowOfHotKeyHelp  = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;\r
+\r
+  //\r
+  // Calculate total number of Register HotKeys. \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
+    //\r
+    // Print HotKey help string on bottom Row.\r
+    //\r
+    PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString);\r
+\r
+    //\r
+    // Get Next Hot Key.\r
+    //\r
+    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+    Index ++;\r
+  }\r
+  \r
+  return;\r
+}\r
 \r
 /**\r
   Update key's help imformation.\r
@@ -671,18 +727,22 @@ UpdateKeyHelp (
   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
+\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) * 2 / 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 - 4;\r
-  BottomRowOfHelp   = LocalScreen.BottomRow - 3;\r
-\r
-  gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);\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
@@ -694,11 +754,15 @@ UpdateKeyHelp (
     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
-        if (Selection->FormEditable) {\r
-          PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);\r
-          PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);\r
-        }\r
         PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
       }\r
 \r
@@ -714,14 +778,14 @@ UpdateKeyHelp (
           ARROW_LEFT,\r
           gMoveHighlight\r
           );\r
-        PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber);\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 (SecCol, BottomRowOfHelp, gAdjustNumber);\r
-        } else {\r
-          PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
-        }\r
+          PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);\r
+        } \r
+        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
       }\r
     } else {\r
       PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);\r
@@ -729,7 +793,9 @@ UpdateKeyHelp (
       //\r
       // If it is a selected numeric with manual input, display different message\r
       //\r
-      if ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step == 0)) {\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
@@ -751,11 +817,14 @@ UpdateKeyHelp (
   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
-      if (Selection->FormEditable) {\r
-        PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);\r
-        PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);\r
-      }\r
       PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
     }\r
 \r
@@ -769,19 +838,23 @@ UpdateKeyHelp (
   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 (!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
-        if (Selection->FormEditable) {\r
-          PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);\r
-          PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);\r
-        }\r
         PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
       }\r
 \r
       PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-      if (Statement->Operand != EFI_IFR_TEXT_OP) {\r
+      if (Statement->Operand != EFI_IFR_TEXT_OP && Statement->Operand != EFI_IFR_SUBTITLE_OP) {\r
         PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
       }\r
     } else {\r
@@ -842,6 +915,411 @@ FormUpdateNotify (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  check whether the formset need to update the NV.\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
+  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
+\r
+    if (Form->NvUpdateRequired ) {\r
+      return TRUE;\r
+    }\r
+\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  check whether the formset need to update the NV.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  SetValue               Whether set new value or clear old value.\r
+\r
+**/\r
+VOID\r
+UpdateNvInfoInForm (\r
+  IN FORM_BROWSER_FORMSET  *FormSet,\r
+  IN BOOLEAN               SetValue\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
+\r
+    Form->NvUpdateRequired = SetValue;\r
+\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  }\r
+}\r
+/**\r
+  Find menu which will show next time.\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
+  @param Repaint         Whether need to repaint the menu.\r
+  @param NewLine         Whether need to show at new line.\r
+  \r
+  @retval TRUE           Need return.\r
+  @retval FALSE          No need to return.\r
+**/\r
+BOOLEAN\r
+FindNextMenu (\r
+  IN OUT UI_MENU_SELECTION    *Selection,\r
+  IN     BOOLEAN              *Repaint, \r
+  IN     BOOLEAN              *NewLine  \r
+  )\r
+{\r
+  UI_MENU_LIST            *CurrentMenu;\r
+  CHAR16                  YesResponse;\r
+  CHAR16                  NoResponse;\r
+  EFI_INPUT_KEY           Key;\r
+  BROWSER_SETTING_SCOPE   Scope;\r
+  \r
+  CurrentMenu = Selection->CurrentMenu;\r
+\r
+  if (CurrentMenu != NULL && CurrentMenu->Parent != 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
+        //\r
+        // User hits the ESC key, Ingore. \r
+        //\r
+        if (Repaint != NULL) {\r
+          *Repaint = TRUE;\r
+        }\r
+        if (NewLine != NULL) {\r
+          *NewLine = TRUE;\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
+      } else {\r
+        //\r
+        // If the user hits the NoResponse key\r
+        //\r
+        DiscardForm (Selection->FormSet, Selection->Form, Scope);\r
+      }\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
+  //\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
+      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, FormSetLevel);\r
+    } else {\r
+      //\r
+      // If the user hits the NoResponse key\r
+      //\r
+      DiscardForm (Selection->FormSet, Selection->Form, FormSetLevel);\r
+    }\r
+  }\r
+\r
+  Selection->Statement = NULL;\r
+  if (CurrentMenu != NULL) {\r
+    CurrentMenu->QuestionId = 0;\r
+  }\r
+\r
+  Selection->Action = UI_ACTION_EXIT;\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Call the call back function for the question and process the return action.\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
+  @param Question              The Question which need to call.\r
+  @param Action                The action request.\r
+  @param SkipSaveOrDiscard     Whether skip save or discard action.\r
+\r
+  @retval EFI_SUCCESS          The call back function excutes successfully.\r
+  @return Other value if the call back function failed to excute.  \r
+**/\r
+EFI_STATUS \r
+ProcessCallBackFunction (\r
+  IN OUT UI_MENU_SELECTION               *Selection,\r
+  IN     FORM_BROWSER_STATEMENT          *Question,\r
+  IN     EFI_BROWSER_ACTION              Action,\r
+  IN     BOOLEAN                         SkipSaveOrDiscard\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  EFI_HII_VALUE                   *HiiValue;\r
+  EFI_IFR_TYPE_VALUE              *TypeValue;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+  BOOLEAN                         SubmitFormIsRequired;\r
+  BOOLEAN                         DiscardFormIsRequired;\r
+  BOOLEAN                         NeedExit;\r
+  LIST_ENTRY                      *Link;\r
+  BROWSER_SETTING_SCOPE           SettingLevel;\r
+\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
+  SubmitFormIsRequired  = FALSE;\r
+  SettingLevel          = FormSetLevel;\r
+  DiscardFormIsRequired = FALSE;\r
+  NeedExit              = FALSE;\r
+  Status                = EFI_SUCCESS;\r
+  ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+\r
+  if (ConfigAccess == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Link = GetFirstNode (&Selection->Form->StatementListHead);\r
+  while (!IsNull (&Selection->Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&Selection->Form->StatementListHead, Link);\r
+\r
+    //\r
+    // if Question != NULL, only process the question. Else, process all question in this form.\r
+    //\r
+    if ((Question != NULL) && (Statement != Question)) {\r
+      continue;\r
+    }\r
+    \r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check whether Statement is disabled.\r
+    //\r
+    if (Statement->Expression != NULL) {\r
+      if (EvaluateExpressionList(Statement->Expression, TRUE, Selection->FormSet, Selection->Form) == ExpressDisable) {\r
+        continue;\r
+      }\r
+    }\r
+\r
+    HiiValue = &Statement->HiiValue;\r
+    TypeValue = &HiiValue->Value;\r
+    if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+      //\r
+      // For OrderedList, passing in the value buffer to Callback()\r
+      //\r
+      TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;\r
+    }\r
+      \r
+    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+    Status = ConfigAccess->Callback (\r
+                             ConfigAccess,\r
+                             Action,\r
+                             Statement->QuestionId,\r
+                             HiiValue->Type,\r
+                             TypeValue,\r
+                             &ActionRequest\r
+                             );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.\r
+      //\r
+      if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
+        switch (ActionRequest) {\r
+        case EFI_BROWSER_ACTION_REQUEST_RESET:\r
+          gResetRequired = TRUE;\r
+          Selection->Action = UI_ACTION_EXIT;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
+          SubmitFormIsRequired = TRUE;\r
+          Selection->Action = UI_ACTION_EXIT;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
+          Selection->Action = UI_ACTION_EXIT;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:\r
+          SubmitFormIsRequired  = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:\r
+          DiscardFormIsRequired = TRUE;\r
+          SettingLevel          = FormLevel;      \r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:\r
+          SubmitFormIsRequired  = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:\r
+          DiscardFormIsRequired = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // According the spec, return value from call back of "changing" and \r
+      // "retrieve" should update to the question's temp buffer.\r
+      //\r
+      if (Action == EFI_BROWSER_ACTION_CHANGING || Action == EFI_BROWSER_ACTION_RETRIEVE) {\r
+        SetQuestionValue(Selection->FormSet, Selection->Form, Statement, TRUE);\r
+      }\r
+    } else {\r
+      //\r
+      // According the spec, return fail from call back of "changing" and \r
+      // "retrieve", should restore the question's value.\r
+      //\r
+      if (Action  == EFI_BROWSER_ACTION_CHANGING || Action == EFI_BROWSER_ACTION_RETRIEVE) {\r
+        GetQuestionValue(Selection->FormSet, Selection->Form, Statement, TRUE);\r
+      }\r
+\r
+      if (Status == EFI_UNSUPPORTED) {\r
+        //\r
+        // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.\r
+        //\r
+        Status = EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (SubmitFormIsRequired && !SkipSaveOrDiscard) {\r
+    SubmitForm (Selection->FormSet, Selection->Form, SettingLevel);\r
+  }\r
+\r
+  if (DiscardFormIsRequired && !SkipSaveOrDiscard) {\r
+    DiscardForm (Selection->FormSet, Selection->Form, SettingLevel);\r
+  }\r
+\r
+  if (NeedExit) {\r
+    FindNextMenu (Selection, NULL, NULL);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   The worker function that send the displays to the screen. On output,\r
   the selection made by user is returned.\r
@@ -862,18 +1340,13 @@ SetupBrowser (
 {\r
   EFI_STATUS                      Status;\r
   LIST_ENTRY                      *Link;\r
-  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
   EFI_HANDLE                      NotifyHandle;\r
-  EFI_HII_VALUE                   *HiiValue;\r
-  EFI_IFR_TYPE_VALUE              *TypeValue;\r
   FORM_BROWSER_STATEMENT          *Statement;\r
   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  FORM_BROWSER_FORMSET            *FormSet;\r
   EFI_INPUT_KEY                   Key;\r
 \r
   gMenuRefreshHead = NULL;\r
-  gResetRequired = FALSE;\r
-  FormSet = Selection->FormSet;\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
 \r
   //\r
   // Register notify for Form package update\r
@@ -890,62 +1363,25 @@ SetupBrowser (
     return Status;\r
   }\r
 \r
-  //\r
-  // Before display the formset, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN\r
-  //\r
-  ConfigAccess = Selection->FormSet->ConfigAccess;\r
-  if ((ConfigAccess != NULL) && (Selection->Action != UI_ACTION_REFRESH_FORMSET)) {\r
-    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-    mHiiPackageListUpdated = FALSE;\r
-    Status = ConfigAccess->Callback (\r
-                             ConfigAccess,\r
-                             EFI_BROWSER_ACTION_FORM_OPEN,\r
-                             0,\r
-                             EFI_IFR_TYPE_UNDEFINED,\r
-                             NULL,\r
-                             &ActionRequest\r
-                             );\r
-\r
-    if (!EFI_ERROR (Status)) {\r
-      switch (ActionRequest) {\r
-      case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-        gResetRequired = TRUE;\r
-        break;\r
-\r
-      case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-        //\r
-        // Till now there is no uncommitted data, so ignore this request\r
-        //\r
-        break;\r
-\r
-      case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-        Selection->Action = UI_ACTION_EXIT;\r
-        break;\r
-\r
-      default:\r
-        break;\r
-      }\r
-    }\r
-\r
-    if (mHiiPackageListUpdated) {\r
-      //\r
-      // IFR is updated during callback, force to reparse the IFR binary\r
-      //\r
-      mHiiPackageListUpdated = FALSE;\r
-      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-      goto Done;\r
-    }\r
-  }\r
-\r
   //\r
   // Initialize current settings of Questions in this FormSet\r
   //\r
   Status = InitializeCurrentSetting (Selection->FormSet);\r
   if (EFI_ERROR (Status)) {\r
-    Selection->Action = UI_ACTION_EXIT;\r
     goto Done;\r
   }\r
 \r
+  //\r
+  // Update gOldFormSet on maintain back up FormSet list.\r
+  // And, make gOldFormSet point to current FormSet. \r
+  //\r
+  if (gOldFormSet != NULL) {\r
+    RemoveEntryList (&gOldFormSet->Link);\r
+    DestroyFormSet (gOldFormSet);\r
+  }\r
+  gOldFormSet = Selection->FormSet;\r
+  InsertTailList (&gBrowserFormSetList, &gOldFormSet->Link);\r
+\r
   do {\r
     //\r
     // Initialize Selection->Form\r
@@ -966,19 +1402,15 @@ SetupBrowser (
       //\r
       // No Form to display\r
       //\r
-      return EFI_NOT_FOUND;\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
     }\r
 \r
     //\r
     // Check Form is suppressed.\r
     //\r
     if (Selection->Form->SuppressExpression != NULL) {\r
-      Status = EvaluateExpression (Selection->FormSet, Selection->Form, Selection->Form->SuppressExpression);\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-\r
-      if (Selection->Form->SuppressExpression->Result.Value.b) {\r
+      if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {\r
         //\r
         // Form is suppressed. \r
         //\r
@@ -986,43 +1418,88 @@ SetupBrowser (
           CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
         } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
 \r
-        return EFI_NOT_FOUND;\r
+        Status = EFI_NOT_FOUND;\r
+        goto Done;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Reset FormPackage update flag\r
     //\r
     mHiiPackageListUpdated = FALSE;\r
 \r
+    //\r
+    // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN\r
+    // for each question with callback flag.\r
+    // New form may be the first form, or the different form after another form close.\r
+    //\r
+    if ((ConfigAccess != NULL) &&\r
+        ((Selection->Handle != mCurrentHiiHandle) ||\r
+        (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||\r
+        (Selection->FormId != mCurrentFormId))) {\r
+\r
+      //\r
+      // Keep current form information\r
+      //\r
+      mCurrentHiiHandle   = Selection->Handle;\r
+      CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);\r
+      mCurrentFormId      = Selection->FormId;\r
+\r
+      Status = ProcessCallBackFunction (Selection, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        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
+      if (mHiiPackageListUpdated) {\r
+        Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+        mHiiPackageListUpdated = FALSE;\r
+        break;\r
+      }\r
+    }\r
+\r
     //\r
     // Load Questions' Value for display\r
     //\r
     Status = LoadFormSetConfig (Selection, Selection->FormSet);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      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
     if (mHiiPackageListUpdated) {\r
       Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
       mHiiPackageListUpdated = FALSE;\r
-      goto Done;\r
+      break;\r
     }\r
 \r
     //\r
     // Displays the Header and Footer borders\r
     //\r
-    DisplayPageFrame ();\r
+    DisplayPageFrame (Selection);\r
 \r
     //\r
     // Display form\r
     //\r
     Status = DisplayForm (Selection);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto Done;\r
     }\r
 \r
     //\r
@@ -1039,66 +1516,22 @@ SetupBrowser (
       //\r
       mHiiPackageListUpdated = FALSE;\r
 \r
-      if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {\r
-        ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-\r
-        if (ConfigAccess == NULL) {\r
-          return EFI_UNSUPPORTED;\r
-        }\r
-\r
-        HiiValue = &Statement->HiiValue;\r
-        TypeValue = &HiiValue->Value;\r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
-          //\r
-          // Create String in HII database for Configuration Driver to retrieve\r
-          //\r
-          HiiValue->Value.string = NewString ((CHAR16 *) Statement->BufferValue, Selection->FormSet->HiiHandle);\r
-        } else if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
-          //\r
-          // For OrderedList, passing in the value buffer to Callback()\r
-          //\r
-          TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;\r
-        }\r
-\r
-        Status = ConfigAccess->Callback (\r
-                                 ConfigAccess,\r
-                                 EFI_BROWSER_ACTION_CHANGING,\r
-                                 Statement->QuestionId,\r
-                                 HiiValue->Type,\r
-                                 TypeValue,\r
-                                 &ActionRequest\r
-                                 );\r
-\r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\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
           //\r
-          // Clean the String in HII Database\r
+          // Process dynamic update ref opcode.\r
           //\r
-          DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
-        }\r
-\r
-        if (!EFI_ERROR (Status)) {\r
-          switch (ActionRequest) {\r
-          case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-            gResetRequired = TRUE;\r
-            break;\r
-\r
-          case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-            SubmitForm (Selection->FormSet, Selection->Form);\r
-            break;\r
-\r
-          case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            gNvUpdateRequired = FALSE;\r
-            break;\r
-\r
-          default:\r
-            break;\r
+          if (!EFI_ERROR (Status)) {\r
+            Status = ProcessGotoOpCode(Statement, Selection, NULL, NULL);\r
           }\r
-        } else if (Status != EFI_UNSUPPORTED) {\r
+          \r
           //\r
-          // Callback return error status other than EFI_UNSUPPORTED\r
+          // Callback return error status or status return from process goto opcode.\r
           //\r
-          if (Statement->Operand == EFI_IFR_REF_OP) {\r
+          if (EFI_ERROR (Status)) {\r
             //\r
             // Cross reference will not be taken\r
             //\r
@@ -1106,6 +1539,10 @@ SetupBrowser (
             Selection->QuestionId = 0;\r
           }\r
         }\r
+\r
+        if (!EFI_ERROR (Status) && Statement->Operand != EFI_IFR_REF_OP) {\r
+          ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);\r
+        }\r
       }\r
 \r
       //\r
@@ -1119,57 +1556,40 @@ SetupBrowser (
         Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
       }\r
     }\r
-  } while (Selection->Action == UI_ACTION_REFRESH_FORM);\r
-\r
-  //\r
-  // Before exit the formset, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE\r
-  //\r
-  if ((ConfigAccess != NULL) && (Selection->Action == UI_ACTION_EXIT)) {\r
-    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-    Status = ConfigAccess->Callback (\r
-                             ConfigAccess,\r
-                             EFI_BROWSER_ACTION_FORM_CLOSE,\r
-                             0,\r
-                             EFI_IFR_TYPE_UNDEFINED,\r
-                             NULL,\r
-                             &ActionRequest\r
-                             );\r
-\r
-    if (!EFI_ERROR (Status)) {\r
-      switch (ActionRequest) {\r
-      case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-        gResetRequired = TRUE;\r
-        break;\r
-\r
-      case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-        SubmitForm (Selection->FormSet, Selection->Form);\r
-        break;\r
 \r
-      case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-        gNvUpdateRequired = FALSE;\r
-        break;\r
+    //\r
+    // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE\r
+    // for each question with callback flag.\r
+    //\r
+    if ((ConfigAccess != NULL) && \r
+        ((Selection->Action == UI_ACTION_EXIT) || \r
+         (Selection->Handle != mCurrentHiiHandle) ||\r
+         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||\r
+         (Selection->FormId != mCurrentFormId))) {\r
 \r
-      default:\r
-        break;\r
+      Status = ProcessCallBackFunction (Selection, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
       }\r
     }\r
-  }\r
+  } while (Selection->Action == UI_ACTION_REFRESH_FORM);\r
 \r
+Done:\r
   //\r
-  // Record the old formset\r
+  // Reset current form information to the initial setting when error happens or form exit.\r
   //\r
-  if (gOldFormSet != NULL) {\r
-    DestroyFormSet (gOldFormSet);\r
+  if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {\r
+    mCurrentHiiHandle = NULL;\r
+    CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);\r
+    mCurrentFormId = 0;\r
   }\r
-  gOldFormSet = FormSet;\r
 \r
-Done:\r
   //\r
   // Unregister notify for Form package update\r
   //\r
-  Status = mHiiDatabase->UnregisterPackageNotify (\r
-                           mHiiDatabase,\r
-                           NotifyHandle\r
-                           );\r
+  mHiiDatabase->UnregisterPackageNotify (\r
+                   mHiiDatabase,\r
+                   NotifyHandle\r
+                   );\r
   return Status;\r
 }\r