]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
Update Browser to provide the customization possibilities.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Setup.c
index 5b99e7c5dd93c4f3de5d6d0b86f6241fb641aa0d..c4dd18a04fd664e4320d71ffabad670625763088 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
 Entry and initialization module for the browser.\r
 \r
-Copyright (c) 2007 - 2009, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2007 - 2013, 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
 http://opensource.org/licenses/bsd-license.php\r
@@ -20,159 +20,289 @@ SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {
   {\r
     SendForm,\r
     BrowserCallback\r
+  },\r
+  {\r
+    SetScope,\r
+    RegisterHotKey,\r
+    RegiserExitHandler,\r
+    SaveReminder\r
+  },\r
+  {\r
+    BROWSER_EXTENSION2_VERSION_1,\r
+    SetScope,\r
+    RegisterHotKey,\r
+    RegiserExitHandler,\r
+    IsBrowserDataModified,\r
+    ExecuteAction,\r
   }\r
 };\r
 \r
 EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;\r
-EFI_HII_STRING_PROTOCOL           *mHiiString;\r
 EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;\r
+EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;\r
+EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;\r
 \r
 UINTN           gBrowserContextCount = 0;\r
 LIST_ENTRY      gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);\r
+LIST_ENTRY      gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);\r
+LIST_ENTRY      gBrowserHotKeyList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);\r
+LIST_ENTRY      gBrowserStorageList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);\r
 \r
-BANNER_DATA           *gBannerData;\r
-EFI_HII_HANDLE        gFrontPageHandle;\r
-UINTN                 gClassOfVfr;\r
-UINTN                 gFunctionKeySetting;\r
 BOOLEAN               gResetRequired;\r
-BOOLEAN               gNvUpdateRequired;\r
-EFI_HII_HANDLE        gHiiHandle;\r
-UINT16                gDirection;\r
-EFI_SCREEN_DESCRIPTOR gScreenDimensions;\r
+BOOLEAN               gExitRequired;\r
+BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;\r
+BOOLEAN               mBrowserScopeFirstSet = TRUE;\r
+EXIT_HANDLER          ExitHandlerFunction = NULL;\r
 \r
 //\r
 // Browser Global Strings\r
 //\r
-CHAR16            *gFunctionNineString;\r
-CHAR16            *gFunctionTenString;\r
-CHAR16            *gEnterString;\r
-CHAR16            *gEnterCommitString;\r
-CHAR16            *gEnterEscapeString;\r
-CHAR16            *gEscapeString;\r
-CHAR16            *gSaveFailed;\r
-CHAR16            *gMoveHighlight;\r
-CHAR16            *gMakeSelection;\r
-CHAR16            *gDecNumericInput;\r
-CHAR16            *gHexNumericInput;\r
-CHAR16            *gToggleCheckBox;\r
-CHAR16            *gPromptForData;\r
-CHAR16            *gPromptForPassword;\r
-CHAR16            *gPromptForNewPassword;\r
-CHAR16            *gConfirmPassword;\r
-CHAR16            *gConfirmError;\r
-CHAR16            *gPassowordInvalid;\r
-CHAR16            *gPressEnter;\r
 CHAR16            *gEmptyString;\r
-CHAR16            *gAreYouSure;\r
-CHAR16            *gYesResponse;\r
-CHAR16            *gNoResponse;\r
-CHAR16            *gMiniString;\r
-CHAR16            *gPlusString;\r
-CHAR16            *gMinusString;\r
-CHAR16            *gAdjustNumber;\r
-CHAR16            *gSaveChanges;\r
-CHAR16            *gOptionMismatch;\r
-CHAR16            *gFormSuppress;\r
 \r
 CHAR16            *mUnknownString = L"!";\r
 \r
-CHAR16            gPromptBlockWidth;\r
-CHAR16            gOptionBlockWidth;\r
-CHAR16            gHelpBlockWidth;\r
-\r
 EFI_GUID  gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
 EFI_GUID  gSetupBrowserGuid = {\r
   0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}\r
 };\r
 \r
-FORM_BROWSER_FORMSET  *gOldFormSet;\r
+FORM_BROWSER_FORMSET  *gOldFormSet = NULL;\r
+extern UINT32   gBrowserStatus;\r
+extern CHAR16   *gErrorInfo;\r
+extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;\r
+\r
+/**\r
+  Create a menu with specified formset GUID and form ID, and add it as a child\r
+  of the given parent menu.\r
+\r
+  @param  HiiHandle              Hii handle related to this formset.\r
+  @param  FormSetGuid            The Formset Guid of menu to be added.\r
+  @param  FormId                 The Form ID of menu to be added.\r
+  @param  QuestionId             The question id of this menu to be added.\r
+\r
+  @return A pointer to the newly added menu or NULL if memory is insufficient.\r
+\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiAddMenuList (\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId,\r
+  IN UINT16               QuestionId\r
+  )\r
+{\r
+  FORM_ENTRY_INFO  *MenuList;\r
+\r
+  MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));\r
+  if (MenuList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;\r
+\r
+  MenuList->HiiHandle  = HiiHandle;\r
+  CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
+  MenuList->FormId     = FormId;\r
+  MenuList->QuestionId = QuestionId;\r
 \r
-FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {\r
   //\r
-  // Boot Manager\r
+  // If parent is not specified, it is the root Form of a Formset\r
   //\r
-  {\r
-    {\r
-      0x847bc3fe,\r
-      0xb974,\r
-      0x446d,\r
-      {\r
-        0x94,\r
-        0x49,\r
-        0x5a,\r
-        0xd5,\r
-        0x41,\r
-        0x2e,\r
-        0x99,\r
-        0x3b\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
+  InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
+\r
+  return MenuList;\r
+}\r
+\r
+/**\r
+  Return the form id for the input hiihandle and formset.\r
+\r
+  @param  HiiHandle              HiiHandle for FormSet.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.\r
+\r
+  @return First form's id for this form set.\r
+\r
+**/\r
+EFI_FORM_ID\r
+GetFirstFormId (\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid\r
+  )\r
+{\r
+  LIST_ENTRY         *Link;\r
+  FORM_BROWSER_FORM  *Form;\r
+\r
+  Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);\r
+  Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+  return Form->FormId;\r
+}\r
+\r
+/**\r
+  Search Menu with given FormSetGuid and FormId in all cached menu list.\r
+\r
+  @param  HiiHandle              HiiHandle for FormSet.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.\r
+  @param  FormId                 The Form ID of menu to search.\r
+\r
+  @return A pointer to menu found or NULL if not found.\r
+\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiFindMenuList (\r
+  IN EFI_HII_HANDLE       HiiHandle, \r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
+  )\r
+{\r
+  LIST_ENTRY         *Link;\r
+  FORM_ENTRY_INFO    *MenuList;\r
+  FORM_ENTRY_INFO    *RetMenu;\r
+  EFI_FORM_ID        FirstFormId;\r
+\r
+  RetMenu = NULL;\r
+\r
+  Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);\r
+  while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);\r
+    Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);\r
+    \r
+    //\r
+    // If already find the menu, free the menus behind it.\r
+    //\r
+    if (RetMenu != NULL) {\r
+      RemoveEntryList (&MenuList->Link);\r
+      FreePool (MenuList);\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Find the same FromSet.\r
+    //\r
+    if (MenuList->HiiHandle == HiiHandle) {\r
+      if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) {\r
+        //\r
+        // FormSetGuid is not specified.\r
+        //\r
+        RetMenu = MenuList;\r
+      } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {\r
+        if (MenuList->FormId == FormId) {\r
+          RetMenu = MenuList;\r
+        } else if (FormId == 0 || MenuList->FormId == 0 ) {\r
+          FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);\r
+          if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {\r
+            RetMenu = MenuList;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return RetMenu;\r
+}\r
+\r
+/**\r
+  Find parent menu for current menu.\r
+\r
+  @param  CurrentMenu    Current Menu\r
+\r
+  @retval   The parent menu for current menu.\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiFindParentMenu (\r
+  IN FORM_ENTRY_INFO  *CurrentMenu\r
+  )\r
+{\r
+  FORM_ENTRY_INFO    *ParentMenu;\r
+\r
+  ParentMenu = NULL;\r
+  if (CurrentMenu->Link.BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {\r
+    ParentMenu = FORM_ENTRY_INFO_FROM_LINK (CurrentMenu->Link.BackLink);\r
+  }\r
+\r
+  return ParentMenu;\r
+}\r
+\r
+/**\r
+  Free Menu list linked list.\r
+\r
+  @param  MenuListHead    One Menu list point in the menu list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenuList (\r
+  LIST_ENTRY   *MenuListHead\r
+  )\r
+{\r
+  FORM_ENTRY_INFO    *MenuList;\r
+\r
+  while (!IsListEmpty (MenuListHead)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+\r
+    FreePool (MenuList);\r
+  }\r
+}\r
+\r
+/**\r
+  Load all hii formset to the browser.\r
+\r
+**/\r
+VOID\r
+LoadAllHiiFormset (\r
+  VOID\r
+  )\r
+{\r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+  EFI_HII_HANDLE          *HiiHandles;\r
+  UINTN                   Index;\r
+  EFI_GUID                ZeroGuid;\r
+  EFI_STATUS              Status;\r
+\r
   //\r
-  // Device Manager\r
+  // Get all the Hii handles\r
   //\r
-  {\r
-    {\r
-      0x3ebfa8e6,\r
-      0x511d,\r
-      0x4b5b,\r
-      {\r
-        0xa9,\r
-        0x5f,\r
-        0xfb,\r
-        0x38,\r
-        0x26,\r
-        0xf,\r
-        0x1c,\r
-        0x27\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
   //\r
-  // BMM FormSet.\r
+  // Search for formset of each class type\r
   //\r
-  {\r
-    {\r
-      0x642237c7,\r
-      0x35d4,\r
-      0x472d,\r
-      {\r
-        0x83,\r
-        0x65,\r
-        0x12,\r
-        0xe0,\r
-        0xcc,\r
-        0xf2,\r
-        0x7a,\r
-        0x22\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    //\r
+    // Check HiiHandles[Index] does exist in global maintain list.\r
+    //\r
+    if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Initilize FormSet Setting\r
+    //\r
+    LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
+    ASSERT (LocalFormSet != NULL);\r
+    ZeroMem (&ZeroGuid, sizeof (ZeroGuid));\r
+    Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);\r
+    if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {\r
+      DestroyFormSet (LocalFormSet);\r
+      continue;\r
+    }\r
+    InitializeCurrentSetting (LocalFormSet);\r
+\r
+    //\r
+    // Initilize Questions' Value\r
+    //\r
+    Status = LoadFormSetConfig (NULL, LocalFormSet);\r
+    if (EFI_ERROR (Status)) {\r
+      DestroyFormSet (LocalFormSet);\r
+      continue;\r
+    }\r
+  }\r
+\r
   //\r
-  // BMM File Explorer FormSet.\r
+  // Free resources, and restore gOldFormSet and gClassOfVfr\r
   //\r
-  {\r
-    {\r
-      0x1f2d63e1,\r
-      0xfebd,\r
-      0x4dc7,\r
-      {\r
-        0x9c,\r
-        0xc5,\r
-        0xba,\r
-        0x2b,\r
-        0x1c,\r
-        0xef,\r
-        0x9c,\r
-        0x5b\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
-};\r
+  FreePool (HiiHandles);\r
+}\r
 \r
 /**\r
   This is the routine which an external caller uses to direct the browser\r
@@ -215,74 +345,25 @@ SendForm (
   UI_MENU_SELECTION             *Selection;\r
   UINTN                         Index;\r
   FORM_BROWSER_FORMSET          *FormSet;\r
+  FORM_ENTRY_INFO               *MenuList;\r
 \r
   //\r
-  // Save globals used by SendForm()\r
-  //\r
-  SaveBrowserContext ();\r
-\r
-  Status = EFI_SUCCESS;\r
-  ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-\r
-  //\r
-  // Seed the dimensions in the global\r
+  // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.\r
   //\r
-  gST->ConOut->QueryMode (\r
-                 gST->ConOut,\r
-                 gST->ConOut->Mode->Mode,\r
-                 &gScreenDimensions.RightColumn,\r
-                 &gScreenDimensions.BottomRow\r
-                 );\r
-\r
-  if (ScreenDimensions != NULL) {\r
-    //\r
-    // Check local dimension vs. global dimension.\r
-    //\r
-    if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||\r
-        (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)\r
-        ) {\r
-      Status = EFI_INVALID_PARAMETER;\r
-      goto Done;\r
-    } else {\r
-      //\r
-      // Local dimension validation.\r
-      //\r
-      if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&\r
-          (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&\r
-          ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&\r
-          (\r
-            (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +\r
-            SCROLL_ARROW_HEIGHT *\r
-            2 +\r
-            FRONT_PAGE_HEADER_HEIGHT +\r
-            FOOTER_HEIGHT +\r
-            1\r
-          )\r
-        ) {\r
-        CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-      } else {\r
-        Status = EFI_INVALID_PARAMETER;\r
-        goto Done;\r
-      }\r
-    }\r
+  if (mFormDisplay == NULL) {\r
+    return EFI_UNSUPPORTED;\r
   }\r
 \r
-  gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);\r
-  gHelpBlockWidth   = gOptionBlockWidth;\r
-  gPromptBlockWidth = gOptionBlockWidth;\r
-\r
   //\r
-  // Initialize the strings for the browser, upon exit of the browser, the strings will be freed\r
+  // Save globals used by SendForm()\r
   //\r
-  InitializeBrowserStrings ();\r
-\r
-  gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING;\r
-  gClassOfVfr         = FORMSET_CLASS_PLATFORM_SETUP;\r
+  SaveBrowserContext ();\r
 \r
-  //\r
-  // Ensure we are in Text mode\r
-  //\r
-  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+  gResetRequired = FALSE;\r
+  gExitRequired  = FALSE;\r
+  Status         = EFI_SUCCESS;\r
+  gEmptyString   = L"";\r
+  gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;\r
 \r
   for (Index = 0; Index < HandleCount; Index++) {\r
     Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));\r
@@ -292,11 +373,10 @@ SendForm (
     if (FormSetGuid != NULL) {\r
       CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
       Selection->FormId = FormId;\r
+    } else {\r
+      CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));\r
     }\r
 \r
-    gOldFormSet = NULL;\r
-    gNvUpdateRequired = FALSE;\r
-\r
     do {\r
       FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
       ASSERT (FormSet != NULL);\r
@@ -320,20 +400,36 @@ SendForm (
 \r
       gCurrentSelection = NULL;\r
 \r
+      //\r
+      // If no data is changed, don't need to save current FormSet into the maintain list.\r
+      //\r
+      if (!IsNvUpdateRequiredForFormSet (FormSet) && !IsStorageDataChangedForFormSet(FormSet)) {\r
+        CleanBrowserStorage(FormSet);\r
+        RemoveEntryList (&FormSet->Link);\r
+        DestroyFormSet (FormSet);\r
+      }\r
+\r
       if (EFI_ERROR (Status)) {\r
         break;\r
       }\r
-\r
     } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);\r
 \r
-    if (gOldFormSet != NULL) {\r
-      DestroyFormSet (gOldFormSet);\r
-      gOldFormSet = NULL;\r
-    }\r
-\r
     FreePool (Selection);\r
   }\r
 \r
+  //\r
+  // Still has error info, pop up a message.\r
+  //\r
+  if (gBrowserStatus != BROWSER_SUCCESS) {\r
+    gDisplayFormData.BrowserStatus = gBrowserStatus;\r
+    gDisplayFormData.ErrorString   = gErrorInfo;\r
+\r
+    gBrowserStatus = BROWSER_SUCCESS;\r
+    gErrorInfo     = NULL;\r
+\r
+    mFormDisplay->FormDisplay (&gDisplayFormData, NULL);\r
+  }\r
+\r
   if (ActionRequest != NULL) {\r
     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
     if (gResetRequired) {\r
@@ -341,12 +437,17 @@ SendForm (
     }\r
   }\r
 \r
-  FreeBrowserStrings ();\r
+  mFormDisplay->ExitDisplay();\r
 \r
-  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
-  gST->ConOut->ClearScreen (gST->ConOut);\r
+  //\r
+  // Clear the menu history data.\r
+  //\r
+  while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+    FreePool (MenuList);\r
+  }\r
 \r
-Done:\r
   //\r
   // Restore globals used by SendForm()\r
   //\r
@@ -355,15 +456,10 @@ Done:
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  This function is called by a callback handler to retrieve uncommitted state\r
-  data from the browser.\r
+  Get or set data to the storage.\r
 \r
-  @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL\r
-                                 instance.\r
-  @param  ResultsDataSize        A pointer to the size of the buffer associated\r
-                                 with ResultsData.\r
+  @param  ResultsDataSize        The size of the buffer associatedwith ResultsData.\r
   @param  ResultsData            A string returned from an IFR browser or\r
                                  equivalent. The results string will have no\r
                                  routing information in them.\r
@@ -372,145 +468,70 @@ Done:
                                  browser state information or set (if RetrieveData\r
                                  = FALSE) data in the uncommitted browser state\r
                                  information.\r
-  @param  VariableGuid           An optional field to indicate the target variable\r
-                                 GUID name to use.\r
-  @param  VariableName           An optional field to indicate the target\r
-                                 human-readable variable name.\r
+  @param  Storage                The pointer to the storage.\r
 \r
   @retval EFI_SUCCESS            The results have been distributed or are awaiting\r
                                  distribution.\r
-  @retval EFI_BUFFER_TOO_SMALL   The ResultsDataSize specified was too small to\r
-                                 contain the results data.\r
 \r
 **/\r
-EFI_STATUS\r
-EFIAPI\r
-BrowserCallback (\r
-  IN CONST EFI_FORM_BROWSER2_PROTOCOL  *This,\r
+EFI_STATUS \r
+ProcessStorage (\r
   IN OUT UINTN                         *ResultsDataSize,\r
-  IN OUT EFI_STRING                    ResultsData,\r
+  IN OUT EFI_STRING                    *ResultsData,\r
   IN BOOLEAN                           RetrieveData,\r
-  IN CONST EFI_GUID                    *VariableGuid, OPTIONAL\r
-  IN CONST CHAR16                      *VariableName  OPTIONAL\r
+  IN BROWSER_STORAGE                   *Storage\r
   )\r
 {\r
-  EFI_STATUS            Status;\r
-  LIST_ENTRY            *Link;\r
-  FORMSET_STORAGE       *Storage;\r
-  FORM_BROWSER_FORMSET  *FormSet;\r
-  BOOLEAN               Found;\r
   CHAR16                *ConfigResp;\r
+  EFI_STATUS            Status;\r
   CHAR16                *StrPtr;\r
   UINTN                 BufferSize;\r
   UINTN                 TmpSize;\r
 \r
-  if (ResultsDataSize == NULL || ResultsData == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (gCurrentSelection == NULL) {\r
-    return EFI_NOT_READY;\r
-  }\r
-\r
-  Storage = NULL;\r
-  ConfigResp = NULL;\r
-  FormSet = gCurrentSelection->FormSet;\r
-\r
-  //\r
-  // Find target storage\r
-  //\r
-  Link = GetFirstNode (&FormSet->StorageListHead);\r
-  if (IsNull (&FormSet->StorageListHead, Link)) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  if (VariableGuid != NULL) {\r
-    //\r
-    // Try to find target storage\r
-    //\r
-    Found = FALSE;\r
-    while (!IsNull (&FormSet->StorageListHead, Link)) {\r
-      Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
-      Link = GetNextNode (&FormSet->StorageListHead, Link);\r
-\r
-      if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {\r
-        if (Storage->Type == EFI_HII_VARSTORE_BUFFER) {\r
-          //\r
-          // Buffer storage require both GUID and Name\r
-          //\r
-          if (VariableName == NULL) {\r
-            return EFI_NOT_FOUND;\r
-          }\r
-\r
-          if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {\r
-            continue;\r
-          }\r
-        }\r
-        Found = TRUE;\r
-        break;\r
-      }\r
-    }\r
-\r
-    if (!Found) {\r
-      return EFI_NOT_FOUND;\r
-    }\r
-  } else {\r
-    //\r
-    // GUID/Name is not specified, take the first storage in FormSet\r
-    //\r
-    Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
-  }\r
-\r
   if (RetrieveData) {\r
-    //\r
-    // Skip if there is no RequestElement\r
-    //\r
-    if (Storage->ElementCount == 0) {\r
-      return EFI_SUCCESS;\r
-    }\r
-\r
     //\r
     // Generate <ConfigResp>\r
     //\r
-    Status = StorageToConfigResp (Storage, &ConfigResp);\r
+    Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
 \r
     //\r
-    // Skip <ConfigHdr> and '&' to point to <ConfigBody>\r
+    // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.\r
+    // Also need to consider add "\0" at first time.\r
     //\r
-    StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;\r
-\r
+    StrPtr     = ConfigResp + StrLen (Storage->ConfigHdr) + 1;\r
     BufferSize = StrSize (StrPtr);\r
-    if (*ResultsDataSize < BufferSize) {\r
-      *ResultsDataSize = BufferSize;\r
 \r
-      FreePool (ConfigResp);\r
-      return EFI_BUFFER_TOO_SMALL;\r
+\r
+    //\r
+    // Copy the data if the input buffer is bigger enough.\r
+    //\r
+    if (*ResultsDataSize >= BufferSize) {\r
+      StrCpy (*ResultsData, StrPtr);\r
     }\r
 \r
     *ResultsDataSize = BufferSize;\r
-    CopyMem (ResultsData, StrPtr, BufferSize);\r
-\r
     FreePool (ConfigResp);\r
   } else {\r
     //\r
     // Prepare <ConfigResp>\r
     //\r
-    TmpSize = StrLen (ResultsData);\r
+    TmpSize = StrLen (*ResultsData);\r
     BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);\r
     ConfigResp = AllocateZeroPool (BufferSize);\r
     ASSERT (ConfigResp != NULL);\r
 \r
     StrCpy (ConfigResp, Storage->ConfigHdr);\r
     StrCat (ConfigResp, L"&");\r
-    StrCat (ConfigResp, ResultsData);\r
+    StrCat (ConfigResp, *ResultsData);\r
 \r
     //\r
     // Update Browser uncommited data\r
     //\r
     Status = ConfigRespToStorage (Storage, ConfigResp);\r
+    FreePool (ConfigResp);\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
@@ -519,40 +540,203 @@ BrowserCallback (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
-  Initialize Setup Browser driver.\r
-\r
-  @param ImageHandle     The image handle.\r
-  @param SystemTable     The system table.\r
+  This routine called this service in the browser to retrieve or set certain uncommitted \r
+  state information that resides in the open formsets. \r
 \r
-  @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..\r
-  @return Other value if failed to initialize the Setup Browser module.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeSetup (\r
-  IN EFI_HANDLE           ImageHandle,\r
-  IN EFI_SYSTEM_TABLE     *SystemTable\r
-  )\r
-{\r
-  EFI_STATUS                  Status;\r
+  @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL\r
+                                 instance.\r
+  @param  ResultsDataSize        A pointer to the size of the buffer associated\r
+                                 with ResultsData.\r
+  @param  ResultsData            A string returned from an IFR browser or\r
+                                 equivalent. The results string will have no\r
+                                 routing information in them.\r
+  @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve\r
+                                 (if RetrieveData = TRUE) data from the uncommitted\r
+                                 browser state information or set (if RetrieveData\r
+                                 = FALSE) data in the uncommitted browser state\r
+                                 information.\r
+  @param  VariableGuid           An optional field to indicate the target variable\r
+                                 GUID name to use.\r
+  @param  VariableName           An optional field to indicate the target\r
+                                 human-readable variable name.\r
+\r
+  @retval EFI_SUCCESS            The results have been distributed or are awaiting\r
+                                 distribution.\r
+  @retval EFI_BUFFER_TOO_SMALL   The ResultsDataSize specified was too small to\r
+                                 contain the results data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BrowserCallback (\r
+  IN CONST EFI_FORM_BROWSER2_PROTOCOL  *This,\r
+  IN OUT UINTN                         *ResultsDataSize,\r
+  IN OUT EFI_STRING                    ResultsData,\r
+  IN BOOLEAN                           RetrieveData,\r
+  IN CONST EFI_GUID                    *VariableGuid, OPTIONAL\r
+  IN CONST CHAR16                      *VariableName  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  LIST_ENTRY            *Link;\r
+  BROWSER_STORAGE       *Storage;\r
+  FORMSET_STORAGE       *FormsetStorage;\r
+  FORM_BROWSER_FORMSET  *FormSet;\r
+  UINTN                 TotalSize;\r
+  BOOLEAN               Found;\r
+\r
+  if (ResultsDataSize == NULL || ResultsData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TotalSize = *ResultsDataSize;\r
+  Storage   = NULL;\r
+  Found     = FALSE;\r
+  Status    = EFI_SUCCESS;\r
 \r
   //\r
-  // Locate required Hii relative protocols\r
+  // If set browser data, pre load all hii formset to avoid set the varstore which is not \r
+  // saved in browser.\r
   //\r
+  if (!RetrieveData && (gBrowserSettingScope == SystemLevel)) {\r
+    LoadAllHiiFormset();\r
+  }\r
+\r
+  if (VariableGuid != NULL) {\r
+    //\r
+    // Try to find target storage in the current formset.\r
+    //\r
+    Link = GetFirstNode (&gBrowserStorageList);\r
+    while (!IsNull (&gBrowserStorageList, Link)) {\r
+      Storage = BROWSER_STORAGE_FROM_LINK (Link);\r
+      Link = GetNextNode (&gBrowserStorageList, Link);\r
+      //\r
+      // Check the current storage.\r
+      //\r
+      if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {\r
+        continue;\r
+      }\r
+\r
+      if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||\r
+          Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+        //\r
+        // Buffer storage require both GUID and Name\r
+        //\r
+        if (VariableName == NULL) {\r
+          return EFI_NOT_FOUND;\r
+        }\r
+\r
+        if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {\r
+          continue;\r
+        }\r
+      }\r
+\r
+      Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Different formsets may have same varstore, so here just set the flag\r
+      // not exit the circle.\r
+      // \r
+      Found = TRUE;\r
+      break;\r
+    }\r
+\r
+    if (!Found) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  } else {\r
+    //\r
+    // GUID/Name is not specified, take the first storage in FormSet\r
+    //\r
+    if (gCurrentSelection == NULL) {\r
+      return EFI_NOT_READY;\r
+    }\r
+\r
+    //\r
+    // Generate <ConfigResp>\r
+    //\r
+    FormSet = gCurrentSelection->FormSet;\r
+    Link = GetFirstNode (&FormSet->StorageListHead);\r
+    if (IsNull (&FormSet->StorageListHead, Link)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);\r
+    \r
+    Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  if (RetrieveData) {\r
+    Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
+    *ResultsDataSize = TotalSize;\r
+  }\r
+   \r
+  return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Callback function for SimpleTextInEx protocol install events\r
+\r
+  @param Event           the event that is signaled.\r
+  @param Context         not used here.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FormDisplayCallback (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+\r
+  if (mFormDisplay != NULL) {\r
+    return;\r
+  }\r
+\r
   Status = gBS->LocateProtocol (\r
-                  &gEfiHiiDatabaseProtocolGuid,\r
+                  &gEdkiiFormDisplayEngineProtocolGuid,\r
                   NULL,\r
-                  (VOID **) &mHiiDatabase\r
+                  (VOID **) &mFormDisplay\r
                   );\r
-  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Initialize Setup Browser driver.\r
+\r
+  @param ImageHandle     The image handle.\r
+  @param SystemTable     The system table.\r
+\r
+  @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..\r
+  @return Other value if failed to initialize the Setup Browser module.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSetup (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  VOID                        *Registration;\r
 \r
+  //\r
+  // Locate required Hii relative protocols\r
+  //\r
   Status = gBS->LocateProtocol (\r
-                  &gEfiHiiStringProtocolGuid,\r
+                  &gEfiHiiDatabaseProtocolGuid,\r
                   NULL,\r
-                  (VOID **) &mHiiString\r
+                  (VOID **) &mHiiDatabase\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -563,22 +747,11 @@ InitializeSetup (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  //\r
-  // Publish our HII data\r
-  //\r
-  gHiiHandle = HiiAddPackages (\r
-                 &gSetupBrowserGuid,\r
-                 ImageHandle,\r
-                 SetupBrowserStrings,\r
-                 NULL\r
-                 );\r
-  ASSERT (gHiiHandle != NULL);\r
-\r
-  //\r
-  // Initialize Driver private data\r
-  //\r
-  gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));\r
-  ASSERT (gBannerData != NULL);\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDevicePathFromTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mPathFromText\r
+                  );\r
 \r
   //\r
   // Install FormBrowser2 protocol\r
@@ -592,7 +765,46 @@ InitializeSetup (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  return Status;\r
+  //\r
+  // Install FormBrowserEx2 protocol\r
+  //\r
+  InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);  \r
+  mPrivateData.Handle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mPrivateData.Handle,\r
+                  &gEdkiiFormBrowserEx2ProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mPrivateData.FormBrowserEx2\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mPrivateData.Handle,\r
+                  &gEfiFormBrowserExProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mPrivateData.FormBrowserEx\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  InitializeDisplayFormData ();\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEdkiiFormDisplayEngineProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mFormDisplay\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EfiCreateProtocolNotifyEvent (\r
+      &gEdkiiFormDisplayEngineProtocolGuid,\r
+      TPL_CALLBACK,\r
+      FormDisplayCallback,\r
+      NULL,\r
+      &Registration\r
+      );\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
@@ -662,9 +874,13 @@ GetToken (
 {\r
   EFI_STRING  String;\r
 \r
+  if (HiiHandle == NULL) {\r
+    return NULL;\r
+  }\r
+\r
   String = HiiGetString (HiiHandle, Token, NULL);\r
   if (String == NULL) {\r
-    String = AllocateCopyPool (sizeof (mUnknownString), mUnknownString);\r
+    String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);\r
     ASSERT (String != NULL);\r
   }\r
   return (CHAR16 *) String;\r
@@ -724,50 +940,13 @@ NewStringCat (
   *Dest = NewString;\r
 }\r
 \r
-\r
-/**\r
-  Synchronize Storage's Edit copy to Shadow copy.\r
-\r
-  @param  Storage                The Storage to be synchronized.\r
-\r
-**/\r
-VOID\r
-SynchronizeStorage (\r
-  IN FORMSET_STORAGE         *Storage\r
-  )\r
-{\r
-  LIST_ENTRY              *Link;\r
-  NAME_VALUE_NODE         *Node;\r
-\r
-  switch (Storage->Type) {\r
-  case EFI_HII_VARSTORE_BUFFER:\r
-    CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);\r
-    break;\r
-\r
-  case EFI_HII_VARSTORE_NAME_VALUE:\r
-    Link = GetFirstNode (&Storage->NameValueListHead);\r
-    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
-      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
-\r
-      NewStringCpy (&Node->Value, Node->EditValue);\r
-\r
-      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
-    }\r
-    break;\r
-\r
-  case EFI_HII_VARSTORE_EFI_VARIABLE:\r
-  default:\r
-    break;\r
-  }\r
-}\r
-\r
-\r
 /**\r
   Get Value for given Name from a NameValue Storage.\r
 \r
   @param  Storage                The NameValue Storage.\r
   @param  Name                   The Name.\r
   @param  Value                  The retured Value.\r
+  @param  GetValueFrom           Where to get source value, from EditValue or Value.\r
 \r
   @retval EFI_SUCCESS            Value found for given Name.\r
   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.\r
@@ -775,14 +954,19 @@ SynchronizeStorage (
 **/\r
 EFI_STATUS\r
 GetValueByName (\r
-  IN FORMSET_STORAGE         *Storage,\r
-  IN CHAR16                  *Name,\r
-  IN OUT CHAR16              **Value\r
+  IN BROWSER_STORAGE             *Storage,\r
+  IN CHAR16                      *Name,\r
+  IN OUT CHAR16                  **Value,\r
+  IN GET_SET_QUESTION_VALUE_WITH GetValueFrom\r
   )\r
 {\r
   LIST_ENTRY              *Link;\r
   NAME_VALUE_NODE         *Node;\r
 \r
+  if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   *Value = NULL;\r
 \r
   Link = GetFirstNode (&Storage->NameValueListHead);\r
@@ -790,7 +974,11 @@ GetValueByName (
     Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
 \r
     if (StrCmp (Name, Node->Name) == 0) {\r
-      NewStringCpy (Value, Node->EditValue);\r
+      if (GetValueFrom == GetSetValueWithEditBuffer) {\r
+        NewStringCpy (Value, Node->EditValue);\r
+      } else {\r
+        NewStringCpy (Value, Node->Value);\r
+      }\r
       return EFI_SUCCESS;\r
     }\r
 \r
@@ -807,6 +995,8 @@ GetValueByName (
   @param  Storage                The NameValue Storage.\r
   @param  Name                   The Name.\r
   @param  Value                  The Value to set.\r
+  @param  SetValueTo             Whether update editValue or Value.\r
+  @param  ReturnNode             The node use the input name.\r
 \r
   @retval EFI_SUCCESS            Value found for given Name.\r
   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.\r
@@ -814,24 +1004,46 @@ GetValueByName (
 **/\r
 EFI_STATUS\r
 SetValueByName (\r
-  IN FORMSET_STORAGE         *Storage,\r
-  IN CHAR16                  *Name,\r
-  IN CHAR16                  *Value\r
+  IN  BROWSER_STORAGE             *Storage,\r
+  IN  CHAR16                      *Name,\r
+  IN  CHAR16                      *Value,\r
+  IN  GET_SET_QUESTION_VALUE_WITH SetValueTo,\r
+  OUT NAME_VALUE_NODE             **ReturnNode\r
   )\r
 {\r
   LIST_ENTRY              *Link;\r
   NAME_VALUE_NODE         *Node;\r
+  CHAR16                  *Buffer;\r
+\r
+  if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   Link = GetFirstNode (&Storage->NameValueListHead);\r
   while (!IsNull (&Storage->NameValueListHead, Link)) {\r
     Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
 \r
     if (StrCmp (Name, Node->Name) == 0) {\r
-      if (Node->EditValue != NULL) {\r
-        FreePool (Node->EditValue);\r
+      if (SetValueTo == GetSetValueWithEditBuffer) {\r
+        Buffer = Node->EditValue;\r
+      } else {\r
+        Buffer = Node->Value;\r
       }\r
-      Node->EditValue = AllocateCopyPool (StrSize (Value), Value);\r
-      ASSERT (Node->EditValue != NULL);\r
+      if (Buffer != NULL) {\r
+        FreePool (Buffer);\r
+      }\r
+      Buffer = AllocateCopyPool (StrSize (Value), Value);\r
+      ASSERT (Buffer != NULL);\r
+      if (SetValueTo == GetSetValueWithEditBuffer) {\r
+        Node->EditValue = Buffer;\r
+      } else {\r
+        Node->Value = Buffer;\r
+      }\r
+\r
+      if (ReturnNode != NULL) {\r
+        *ReturnNode = Node;\r
+      }\r
+\r
       return EFI_SUCCESS;\r
     }\r
 \r
@@ -847,6 +1059,8 @@ SetValueByName (
 \r
   @param  Storage                The Storage to be conveted.\r
   @param  ConfigResp             The returned <ConfigResp>.\r
+  @param  ConfigRequest          The ConfigRequest string.\r
+  @param  GetEditBuf             Get the data from editbuffer or buffer.\r
 \r
   @retval EFI_SUCCESS            Convert success.\r
   @retval EFI_INVALID_PARAMETER  Incorrect storage type.\r
@@ -854,23 +1068,28 @@ SetValueByName (
 **/\r
 EFI_STATUS\r
 StorageToConfigResp (\r
-  IN FORMSET_STORAGE         *Storage,\r
-  IN CHAR16                  **ConfigResp\r
+  IN BROWSER_STORAGE         *Storage,\r
+  IN CHAR16                  **ConfigResp,\r
+  IN CHAR16                  *ConfigRequest,\r
+  IN BOOLEAN                 GetEditBuf\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  EFI_STRING  Progress;\r
+  EFI_STATUS              Status;\r
+  EFI_STRING              Progress;\r
   LIST_ENTRY              *Link;\r
   NAME_VALUE_NODE         *Node;\r
+  UINT8                   *SourceBuf;\r
 \r
   Status = EFI_SUCCESS;\r
 \r
   switch (Storage->Type) {\r
   case EFI_HII_VARSTORE_BUFFER:\r
+  case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+    SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;\r
     Status = mHiiConfigRouting->BlockToConfig (\r
                                   mHiiConfigRouting,\r
-                                  Storage->ConfigRequest,\r
-                                  Storage->EditBuffer,\r
+                                  ConfigRequest,\r
+                                  SourceBuf,\r
                                   Storage->Size,\r
                                   ConfigResp,\r
                                   &Progress\r
@@ -885,11 +1104,16 @@ StorageToConfigResp (
     while (!IsNull (&Storage->NameValueListHead, Link)) {\r
       Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
 \r
-      NewStringCat (ConfigResp, L"&");\r
-      NewStringCat (ConfigResp, Node->Name);\r
-      NewStringCat (ConfigResp, L"=");\r
-      NewStringCat (ConfigResp, Node->EditValue);\r
-\r
+      if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
+        NewStringCat (ConfigResp, L"&");\r
+        NewStringCat (ConfigResp, Node->Name);\r
+        NewStringCat (ConfigResp, L"=");\r
+        if (GetEditBuf) {\r
+          NewStringCat (ConfigResp, Node->EditValue);\r
+        } else {\r
+          NewStringCat (ConfigResp, Node->Value);\r
+        }\r
+      }\r
       Link = GetNextNode (&Storage->NameValueListHead, Link);\r
     }\r
     break;\r
@@ -916,7 +1140,7 @@ StorageToConfigResp (
 **/\r
 EFI_STATUS\r
 ConfigRespToStorage (\r
-  IN FORMSET_STORAGE         *Storage,\r
+  IN BROWSER_STORAGE         *Storage,\r
   IN CHAR16                  *ConfigResp\r
   )\r
 {\r
@@ -931,6 +1155,7 @@ ConfigRespToStorage (
 \r
   switch (Storage->Type) {\r
   case EFI_HII_VARSTORE_BUFFER:\r
+  case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
     BufferSize = Storage->Size;\r
     Status = mHiiConfigRouting->ConfigToBlock (\r
                                   mHiiConfigRouting,\r
@@ -942,6 +1167,10 @@ ConfigRespToStorage (
     break;\r
 \r
   case EFI_HII_VARSTORE_NAME_VALUE:\r
+    StrPtr = StrStr (ConfigResp, L"PATH");\r
+    if (StrPtr == NULL) {\r
+      break;\r
+    }\r
     StrPtr = StrStr (ConfigResp, L"&");\r
     while (StrPtr != NULL) {\r
       //\r
@@ -964,7 +1193,7 @@ ConfigRespToStorage (
       if (StrPtr != NULL) {\r
         *StrPtr = 0;\r
       }\r
-      SetValueByName (Storage, Name, Value);\r
+      SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);\r
     }\r
     break;\r
 \r
@@ -984,8 +1213,7 @@ ConfigRespToStorage (
   @param  FormSet                FormSet data structure.\r
   @param  Form                   Form data structure.\r
   @param  Question               Question to be initialized.\r
-  @param  Cached                 TRUE:  get from Edit copy FALSE: get from original\r
-                                 Storage\r
+  @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.\r
 \r
   @retval EFI_SUCCESS            The function completed successfully.\r
 \r
@@ -995,7 +1223,7 @@ GetQuestionValue (
   IN FORM_BROWSER_FORMSET             *FormSet,\r
   IN FORM_BROWSER_FORM                *Form,\r
   IN OUT FORM_BROWSER_STATEMENT       *Question,\r
-  IN BOOLEAN                          Cached\r
+  IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -1004,7 +1232,7 @@ GetQuestionValue (
   UINT8               *Dst;\r
   UINTN               StorageWidth;\r
   EFI_TIME            EfiTime;\r
-  FORMSET_STORAGE     *Storage;\r
+  BROWSER_STORAGE     *Storage;\r
   EFI_IFR_TYPE_VALUE  *QuestionValue;\r
   CHAR16              *ConfigRequest;\r
   CHAR16              *Progress;\r
@@ -1018,8 +1246,15 @@ GetQuestionValue (
   BOOLEAN             IsString;\r
   CHAR16              TemStr[5];\r
   UINT8               DigitUint8;\r
+  UINT8               *TemBuffer;\r
 \r
   Status = EFI_SUCCESS;\r
+  Value  = NULL;\r
+  Result = NULL;\r
+\r
+  if (GetValueFrom >= GetSetValueWithMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   //\r
   // Statement don't have storage, skip them\r
@@ -1034,10 +1269,49 @@ GetQuestionValue (
   if (Question->ValueExpression != NULL) {\r
     Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);\r
     if (!EFI_ERROR (Status)) {\r
-      CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE));\r
+      if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
+        ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);\r
+        if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {\r
+          CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);\r
+          Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;\r
+        } else {\r
+          CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);\r
+          Question->HiiValue.BufferLen = Question->StorageWidth;\r
+        }\r
+        FreePool (Question->ValueExpression->Result.Buffer);\r
+      }\r
+      Question->HiiValue.Type = Question->ValueExpression->Result.Type;\r
+      CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));      \r
     }\r
     return Status;\r
   }\r
+  \r
+  //\r
+  // Get question value by read expression.\r
+  //\r
+  if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {\r
+    Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);\r
+    if (!EFI_ERROR (Status) && \r
+      ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {\r
+      //\r
+      // Only update question value to the valid result.\r
+      //\r
+      if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
+        ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);\r
+        if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {\r
+          CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);\r
+          Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;\r
+        } else {\r
+          CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);\r
+          Question->HiiValue.BufferLen = Question->StorageWidth;\r
+        }\r
+        FreePool (Question->ReadExpression->Result.Buffer);\r
+      }\r
+      Question->HiiValue.Type = Question->ReadExpression->Result.Type;\r
+      CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));       \r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
 \r
   //\r
   // Question value is provided by RTC\r
@@ -1126,20 +1400,34 @@ GetQuestionValue (
     Dst = (UINT8 *) &Question->HiiValue.Value;\r
   }\r
 \r
-  IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+    IsBufferStorage = TRUE;\r
+  } else {\r
+    IsBufferStorage = FALSE;\r
+  }\r
   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);\r
-  if (Cached) {\r
+  if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {\r
     if (IsBufferStorage) {\r
-      //\r
-      // Copy from storage Edit buffer\r
-      //\r
-      CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
-    } else {\r
-      Status = GetValueByName (Storage, Question->VariableName, &Value);\r
+      if (GetValueFrom == GetSetValueWithEditBuffer) {\r
+        //\r
+        // Copy from storage Edit buffer\r
+        //\r
+        CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
+      } else {\r
+        //\r
+        // Copy from storage Edit buffer\r
+        //\r
+        CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
+      }\r
+    } else {\r
+      Value = NULL;\r
+      Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
       }\r
 \r
+      ASSERT (Value != NULL);\r
       LengthStr = StrLen (Value);\r
       Status    = EFI_SUCCESS;\r
       if (IsString) {\r
@@ -1182,115 +1470,147 @@ GetQuestionValue (
       FreePool (Value);\r
     }\r
   } else {\r
-    //\r
-    // Request current settings from Configuration Driver\r
-    //\r
-    if (FormSet->ConfigAccess == NULL) {\r
-      return EFI_NOT_FOUND;\r
-    }\r
-\r
-    //\r
-    // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
-    //                   <ConfigHdr> + "&" + <VariableName>\r
-    //\r
-    if (IsBufferStorage) {\r
-      Length = StrLen (Storage->ConfigHdr);\r
-      Length += StrLen (Question->BlockName);\r
-    } else {\r
-      Length = StrLen (Storage->ConfigHdr);\r
-      Length += StrLen (Question->VariableName) + 1;\r
-    }\r
-    ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
-    ASSERT (ConfigRequest != NULL);\r
-\r
-    StrCpy (ConfigRequest, Storage->ConfigHdr);\r
-    if (IsBufferStorage) {\r
-      StrCat (ConfigRequest, Question->BlockName);\r
-    } else {\r
-      StrCat (ConfigRequest, L"&");\r
-      StrCat (ConfigRequest, Question->VariableName);\r
-    }\r
-\r
-    Status = FormSet->ConfigAccess->ExtractConfig (\r
-                                      FormSet->ConfigAccess,\r
-                                      ConfigRequest,\r
-                                      &Progress,\r
-                                      &Result\r
-                                      );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+    if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+      //\r
+      // Request current settings from Configuration Driver\r
+      //\r
+      if (FormSet->ConfigAccess == NULL) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
 \r
-    //\r
-    // Skip <ConfigRequest>\r
-    //\r
-    Value = Result + Length;\r
-    if (IsBufferStorage) {\r
       //\r
-      // Skip "&VALUE"\r
+      // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
+      //                   <ConfigHdr> + "&" + <VariableName>\r
       //\r
-      Value = Value + 6;\r
-    }\r
-    if (*Value != '=') {\r
-      FreePool (Result);\r
-      return EFI_NOT_FOUND;\r
-    }\r
-    //\r
-    // Skip '=', point to value\r
-    //\r
-    Value = Value + 1;\r
+      if (IsBufferStorage) {\r
+        Length = StrLen (Storage->ConfigHdr);\r
+        Length += StrLen (Question->BlockName);\r
+      } else {\r
+        Length = StrLen (Storage->ConfigHdr);\r
+        Length += StrLen (Question->VariableName) + 1;\r
+      }\r
+      ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
+      ASSERT (ConfigRequest != NULL);\r
 \r
-    //\r
-    // Suppress <AltResp> if any\r
-    //\r
-    StringPtr = Value;\r
-    while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
-      StringPtr++;\r
-    }\r
-    *StringPtr = L'\0';\r
+      StrCpy (ConfigRequest, Storage->ConfigHdr);\r
+      if (IsBufferStorage) {\r
+        StrCat (ConfigRequest, Question->BlockName);\r
+      } else {\r
+        StrCat (ConfigRequest, L"&");\r
+        StrCat (ConfigRequest, Question->VariableName);\r
+      }\r
+\r
+      Status = FormSet->ConfigAccess->ExtractConfig (\r
+                                        FormSet->ConfigAccess,\r
+                                        ConfigRequest,\r
+                                        &Progress,\r
+                                        &Result\r
+                                        );\r
+      FreePool (ConfigRequest);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
 \r
-    LengthStr = StrLen (Value);\r
-    Status    = EFI_SUCCESS;\r
-    if (!IsBufferStorage && IsString) {\r
       //\r
-      // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"\r
-      // Add string tail char L'\0' into Length\r
+      // Skip <ConfigRequest>\r
       //\r
-      Length    = StorageWidth + sizeof (CHAR16);\r
-      if (Length < ((LengthStr / 4 + 1) * 2)) {\r
-        Status = EFI_BUFFER_TOO_SMALL;\r
-      } else {\r
-        StringPtr = (CHAR16 *) Dst;\r
-        ZeroMem (TemStr, sizeof (TemStr));\r
-        for (Index = 0; Index < LengthStr; Index += 4) {\r
-          StrnCpy (TemStr, Value + Index, 4);\r
-          StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
+      if (IsBufferStorage) {\r
+        Value = StrStr (Result, L"&VALUE");\r
+        if (Value == NULL) {\r
+          FreePool (Result);\r
+          return EFI_NOT_FOUND;\r
         }\r
         //\r
-        // Add tailing L'\0' character\r
+        // Skip "&VALUE"\r
         //\r
-        StringPtr[Index/4] = L'\0';\r
+        Value = Value + 6;\r
+      } else {\r
+        Value = Result + Length;\r
       }\r
-    } else {\r
-      if (StorageWidth < ((LengthStr + 1) / 2)) {\r
-        Status = EFI_BUFFER_TOO_SMALL;\r
+      if (*Value != '=') {\r
+        FreePool (Result);\r
+        return EFI_NOT_FOUND;\r
+      }\r
+      //\r
+      // Skip '=', point to value\r
+      //\r
+      Value = Value + 1;\r
+\r
+      //\r
+      // Suppress <AltResp> if any\r
+      //\r
+      StringPtr = Value;\r
+      while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
+        StringPtr++;\r
+      }\r
+      *StringPtr = L'\0';\r
+\r
+      LengthStr = StrLen (Value);\r
+      Status    = EFI_SUCCESS;\r
+      if (!IsBufferStorage && IsString) {\r
+        //\r
+        // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"\r
+        // Add string tail char L'\0' into Length\r
+        //\r
+        Length    = StorageWidth + sizeof (CHAR16);\r
+        if (Length < ((LengthStr / 4 + 1) * 2)) {\r
+          Status = EFI_BUFFER_TOO_SMALL;\r
+        } else {\r
+          StringPtr = (CHAR16 *) Dst;\r
+          ZeroMem (TemStr, sizeof (TemStr));\r
+          for (Index = 0; Index < LengthStr; Index += 4) {\r
+            StrnCpy (TemStr, Value + Index, 4);\r
+            StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
+          }\r
+          //\r
+          // Add tailing L'\0' character\r
+          //\r
+          StringPtr[Index/4] = L'\0';\r
+        }\r
       } else {\r
-        ZeroMem (TemStr, sizeof (TemStr));\r
-        for (Index = 0; Index < LengthStr; Index ++) {\r
-          TemStr[0] = Value[LengthStr - Index - 1];\r
-          DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
-          if ((Index & 1) == 0) {\r
-            Dst [Index/2] = DigitUint8;\r
-          } else {\r
-            Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
+        if (StorageWidth < ((LengthStr + 1) / 2)) {\r
+          Status = EFI_BUFFER_TOO_SMALL;\r
+        } else {\r
+          ZeroMem (TemStr, sizeof (TemStr));\r
+          for (Index = 0; Index < LengthStr; Index ++) {\r
+            TemStr[0] = Value[LengthStr - Index - 1];\r
+            DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+            if ((Index & 1) == 0) {\r
+              Dst [Index/2] = DigitUint8;\r
+            } else {\r
+              Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
+            }\r
           }\r
         }\r
       }\r
-    }\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      FreePool (Result);\r
-      return Status;\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (Result);\r
+        return Status;\r
+      }\r
+    } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+      TemBuffer = NULL;\r
+      TemBuffer = AllocateZeroPool (Storage->Size);\r
+      if (TemBuffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
+      }\r
+      Length = Storage->Size;\r
+      Status = gRT->GetVariable (\r
+                       Storage->Name,\r
+                       &Storage->Guid,\r
+                       NULL,\r
+                       &Length,\r
+                       TemBuffer\r
+                       );\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (TemBuffer);\r
+        return Status;\r
+      }\r
+\r
+      CopyMem (Dst, TemBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);\r
+\r
+      FreePool (TemBuffer);\r
     }\r
 \r
     //\r
@@ -1299,10 +1619,12 @@ GetQuestionValue (
     if (IsBufferStorage) {\r
       CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);\r
     } else {\r
-      SetValueByName (Storage, Question->VariableName, Value);\r
+      SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);\r
     }\r
 \r
-    FreePool (Result);\r
+    if (Result != NULL) {\r
+      FreePool (Result);\r
+    }\r
   }\r
 \r
   return Status;\r
@@ -1315,8 +1637,7 @@ GetQuestionValue (
   @param  FormSet                FormSet data structure.\r
   @param  Form                   Form data structure.\r
   @param  Question               Pointer to the Question.\r
-  @param  Cached                 TRUE:  set to Edit copy FALSE: set to original\r
-                                 Storage\r
+  @param  SetValueTo             Update the question value to editbuffer , buffer or hii driver.\r
 \r
   @retval EFI_SUCCESS            The function completed successfully.\r
 \r
@@ -1326,7 +1647,7 @@ SetQuestionValue (
   IN FORM_BROWSER_FORMSET             *FormSet,\r
   IN FORM_BROWSER_FORM                *Form,\r
   IN OUT FORM_BROWSER_STATEMENT       *Question,\r
-  IN BOOLEAN                          Cached\r
+  IN GET_SET_QUESTION_VALUE_WITH      SetValueTo\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -1336,7 +1657,7 @@ SetQuestionValue (
   EFI_TIME            EfiTime;\r
   UINTN               BufferLen;\r
   UINTN               StorageWidth;\r
-  FORMSET_STORAGE     *Storage;\r
+  BROWSER_STORAGE     *Storage;\r
   EFI_IFR_TYPE_VALUE  *QuestionValue;\r
   CHAR16              *ConfigResp;\r
   CHAR16              *Progress;\r
@@ -1348,8 +1669,14 @@ SetQuestionValue (
   CHAR16              *TemName;\r
   CHAR16              *TemString;\r
   UINTN               Index;\r
+  NAME_VALUE_NODE     *Node;\r
 \r
   Status = EFI_SUCCESS;\r
+  Node   = NULL;\r
+\r
+  if (SetValueTo >= GetSetValueWithMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   //\r
   // Statement don't have storage, skip them\r
@@ -1364,6 +1691,16 @@ SetQuestionValue (
   if (Question->ValueExpression != NULL) {\r
     return Status;\r
   }\r
+  \r
+  //\r
+  // Before set question value, evaluate its write expression.\r
+  //\r
+  if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {\r
+    Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
 \r
   //\r
   // Question value is provided by RTC\r
@@ -1449,127 +1786,190 @@ SetQuestionValue (
     Src = (UINT8 *) &Question->HiiValue.Value;\r
   }\r
 \r
-  IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);\r
-  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);\r
-  if (IsBufferStorage) {\r
-    //\r
-    // Copy to storage edit buffer\r
-    //\r
-    CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+    IsBufferStorage = TRUE;\r
   } else {\r
-    if (IsString) {\r
-      //\r
-      // Allocate enough string buffer.\r
-      //\r
-      Value = NULL;\r
-      BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);\r
-      Value = AllocateZeroPool (BufferLen);\r
-      ASSERT (Value != NULL);\r
+    IsBufferStorage = FALSE;\r
+  }\r
+  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);\r
+\r
+  if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {\r
+    if (IsBufferStorage) {\r
+      if (SetValueTo == GetSetValueWithEditBuffer) {\r
+        //\r
+        // Copy to storage edit buffer\r
+        //      \r
+        CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+      } else if (SetValueTo == GetSetValueWithBuffer) {\r
+        //\r
+        // Copy to storage edit buffer\r
+        //     \r
+        CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+      }\r
       //\r
-      // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
+      // Check whether question value has been changed.\r
       //\r
-      TemName = (CHAR16 *) Src;\r
-      TemString = Value;\r
-      for (; *TemName != L'\0'; TemName++) {\r
-        TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
+      if (CompareMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth) != 0) {\r
+        Question->ValueChanged = TRUE;\r
+      } else {\r
+        Question->ValueChanged = FALSE;\r
       }\r
     } else {\r
-      BufferLen = StorageWidth * 2 + 1;\r
-      Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));\r
-      ASSERT (Value != NULL);\r
+      if (IsString) {\r
+        //\r
+        // Allocate enough string buffer.\r
+        //\r
+        Value = NULL;\r
+        BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);\r
+        Value = AllocateZeroPool (BufferLen);\r
+        ASSERT (Value != NULL);\r
+        //\r
+        // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
+        //\r
+        TemName = (CHAR16 *) Src;\r
+        TemString = Value;\r
+        for (; *TemName != L'\0'; TemName++) {\r
+          TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
+        }\r
+      } else {\r
+        BufferLen = StorageWidth * 2 + 1;\r
+        Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));\r
+        ASSERT (Value != NULL);\r
+        //\r
+        // Convert Buffer to Hex String\r
+        //\r
+        TemBuffer = Src + StorageWidth - 1;\r
+        TemString = Value;\r
+        for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
+          TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
+        }\r
+      }\r
+\r
+      Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);\r
+      FreePool (Value);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
       //\r
-      // Convert Buffer to Hex String\r
+      // Check whether question value has been changed.\r
       //\r
-      TemBuffer = Src + StorageWidth - 1;\r
-      TemString = Value;\r
-      for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
-        TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
+      if (StrCmp (Node->Value, Node->EditValue) != 0) {\r
+        Question->ValueChanged = TRUE;\r
+      } else {\r
+        Question->ValueChanged = FALSE;\r
       }\r
     }\r
+  } else if (SetValueTo == GetSetValueWithHiiDriver) {\r
+    if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+      //\r
+      // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||\r
+      //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"\r
+      //\r
+      if (IsBufferStorage) {\r
+        Length = StrLen (Question->BlockName) + 7;\r
+      } else {\r
+        Length = StrLen (Question->VariableName) + 2;\r
+      }\r
+      if (!IsBufferStorage && IsString) {\r
+        Length += (StrLen ((CHAR16 *) Src) * 4);\r
+      } else {\r
+        Length += (StorageWidth * 2);\r
+      }\r
+      ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));\r
+      ASSERT (ConfigResp != NULL);\r
 \r
-    Status = SetValueByName (Storage, Question->VariableName, Value);\r
-    FreePool (Value);\r
-  }\r
-\r
-  if (!Cached) {\r
-    //\r
-    // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||\r
-    //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"\r
-    //\r
-    if (IsBufferStorage) {\r
-      Length = StrLen (Question->BlockName) + 7;\r
-    } else {\r
-      Length = StrLen (Question->VariableName) + 2;\r
-    }\r
-    if (!IsBufferStorage && IsString) {\r
-      Length += (StrLen ((CHAR16 *) Src) * 4);\r
-    } else {\r
-      Length += (StorageWidth * 2);\r
-    }\r
-    ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));\r
-    ASSERT (ConfigResp != NULL);\r
+      StrCpy (ConfigResp, Storage->ConfigHdr);\r
+      if (IsBufferStorage) {\r
+        StrCat (ConfigResp, Question->BlockName);\r
+        StrCat (ConfigResp, L"&VALUE=");\r
+      } else {\r
+        StrCat (ConfigResp, L"&");\r
+        StrCat (ConfigResp, Question->VariableName);\r
+        StrCat (ConfigResp, L"=");\r
+      }\r
 \r
-    StrCpy (ConfigResp, Storage->ConfigHdr);\r
-    if (IsBufferStorage) {\r
-      StrCat (ConfigResp, Question->BlockName);\r
-      StrCat (ConfigResp, L"&VALUE=");\r
-    } else {\r
-      StrCat (ConfigResp, L"&");\r
-      StrCat (ConfigResp, Question->VariableName);\r
-      StrCat (ConfigResp, L"=");\r
-    }\r
+      Value = ConfigResp + StrLen (ConfigResp);\r
 \r
-    Value = ConfigResp + StrLen (ConfigResp);\r
+      if (!IsBufferStorage && IsString) {\r
+        //\r
+        // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
+        //\r
+        TemName = (CHAR16 *) Src;\r
+        TemString = Value;\r
+        for (; *TemName != L'\0'; TemName++) {\r
+          TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
+        }\r
+      } else {\r
+        //\r
+        // Convert Buffer to Hex String\r
+        //\r
+        TemBuffer = Src + StorageWidth - 1;\r
+        TemString = Value;\r
+        for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
+          TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
+        }\r
+      }\r
 \r
-    if (!IsBufferStorage && IsString) {\r
       //\r
-      // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
+      // Convert to lower char.\r
       //\r
-      TemName = (CHAR16 *) Src;\r
-      TemString = Value;\r
-      for (; *TemName != L'\0'; TemName++) {\r
-        TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
+      for (TemString = Value; *Value != L'\0'; Value++) {\r
+        if (*Value >= L'A' && *Value <= L'Z') {\r
+          *Value = (CHAR16) (*Value - L'A' + L'a');\r
+        }\r
       }\r
-    } else {\r
+\r
       //\r
-      // Convert Buffer to Hex String\r
+      // Submit Question Value to Configuration Driver\r
       //\r
-      TemBuffer = Src + StorageWidth - 1;\r
-      TemString = Value;\r
-      for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {\r
-        TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
+      if (FormSet->ConfigAccess != NULL) {\r
+        Status = FormSet->ConfigAccess->RouteConfig (\r
+                                          FormSet->ConfigAccess,\r
+                                          ConfigResp,\r
+                                          &Progress\r
+                                          );\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (ConfigResp);\r
+          return Status;\r
+        }\r
       }\r
-    }\r
-\r
-    //\r
-    // Convert to lower char.\r
-    //\r
-    for (TemString = Value; *Value != L'\0'; Value++) {\r
-      if (*Value >= L'A' && *Value <= L'Z') {\r
-        *Value = (CHAR16) (*Value - L'A' + L'a');\r
+      FreePool (ConfigResp);\r
+      \r
+    } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+      TemBuffer = NULL;\r
+      TemBuffer = AllocateZeroPool(Storage->Size);\r
+      if (TemBuffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
       }\r
-    }\r
+      Length = Storage->Size;\r
+      Status = gRT->GetVariable (\r
+                       Storage->Name,\r
+                       &Storage->Guid,\r
+                       NULL,\r
+                       &Length,\r
+                       TemBuffer\r
+                       );\r
 \r
-    //\r
-    // Submit Question Value to Configuration Driver\r
-    //\r
-    if (FormSet->ConfigAccess != NULL) {\r
-      Status = FormSet->ConfigAccess->RouteConfig (\r
-                                        FormSet->ConfigAccess,\r
-                                        ConfigResp,\r
-                                        &Progress\r
-                                        );\r
-      if (EFI_ERROR (Status)) {\r
-        FreePool (ConfigResp);\r
+      CopyMem (TemBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+      \r
+      Status = gRT->SetVariable (\r
+                       Storage->Name,\r
+                       &Storage->Guid,\r
+                       Storage->Attributes,\r
+                       Storage->Size,\r
+                       TemBuffer\r
+                       );\r
+      FreePool (TemBuffer);\r
+      if (EFI_ERROR (Status)){\r
         return Status;\r
       }\r
     }\r
-    FreePool (ConfigResp);\r
-\r
     //\r
-    // Synchronize shadow Buffer\r
+    // Sync storage, from editbuffer to buffer.\r
     //\r
-    SynchronizeStorage (Storage);\r
+    CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
   }\r
 \r
   return Status;\r
@@ -1577,12 +1977,12 @@ SetQuestionValue (
 \r
 \r
 /**\r
-  Perform inconsistent check for a Form.\r
+  Perform nosubmitif check for a Form.\r
 \r
   @param  FormSet                FormSet data structure.\r
   @param  Form                   Form data structure.\r
   @param  Question               The Question to be validated.\r
-  @param  Type                   Validation type: InConsistent or NoSubmit\r
+  @param  Type                   Validation type: NoSubmit\r
 \r
   @retval EFI_SUCCESS            Form validation pass.\r
   @retval other                  Form validation failed.\r
@@ -1600,12 +2000,9 @@ ValidateQuestion (
   LIST_ENTRY              *Link;\r
   LIST_ENTRY              *ListHead;\r
   EFI_STRING              PopUp;\r
-  EFI_INPUT_KEY           Key;\r
   FORM_EXPRESSION         *Expression;\r
 \r
-  if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {\r
-    ListHead = &Question->InconsistentListHead;\r
-  } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
+  if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
     ListHead = &Question->NoSubmitListHead;\r
   } else {\r
     return EFI_UNSUPPORTED;\r
@@ -1623,16 +2020,16 @@ ValidateQuestion (
       return Status;\r
     }\r
 \r
-    if (Expression->Result.Value.b) {\r
+    if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {\r
       //\r
       // Condition meet, show up error message\r
       //\r
       if (Expression->Error != 0) {\r
         PopUp = GetToken (Expression->Error, FormSet->HiiHandle);\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);\r
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
-        FreePool (PopUp);\r
+        if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
+          gBrowserStatus = BROWSER_NO_SUBMIT_IF;\r
+          gErrorInfo     = PopUp;\r
+        }\r
       }\r
 \r
       return EFI_NOT_READY;\r
@@ -1646,10 +2043,10 @@ ValidateQuestion (
 \r
 \r
 /**\r
-  Perform NoSubmit check for a Form.\r
+  Perform NoSubmit check for each Form in FormSet.\r
 \r
   @param  FormSet                FormSet data structure.\r
-  @param  Form                   Form data structure.\r
+  @param  CurrentForm            Current input form data structure.\r
 \r
   @retval EFI_SUCCESS            Form validation pass.\r
   @retval other                  Form validation failed.\r
@@ -1658,1122 +2055,3151 @@ ValidateQuestion (
 EFI_STATUS\r
 NoSubmitCheck (\r
   IN  FORM_BROWSER_FORMSET            *FormSet,\r
-  IN  FORM_BROWSER_FORM               *Form\r
+  IN  FORM_BROWSER_FORM               *CurrentForm\r
   )\r
 {\r
   EFI_STATUS              Status;\r
   LIST_ENTRY              *Link;\r
   FORM_BROWSER_STATEMENT  *Question;\r
+  FORM_BROWSER_FORM       *Form;\r
+  LIST_ENTRY              *LinkForm;\r
 \r
-  Link = GetFirstNode (&Form->StatementListHead);\r
-  while (!IsNull (&Form->StatementListHead, Link)) {\r
-    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+  LinkForm = GetFirstNode (&FormSet->FormListHead);\r
+  while (!IsNull (&FormSet->FormListHead, LinkForm)) {\r
+    Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);\r
+    LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);\r
 \r
-    Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
+    if (CurrentForm != NULL && CurrentForm != Form) {\r
+      continue;\r
     }\r
 \r
-    Link = GetNextNode (&Form->StatementListHead, Link);\r
+    Link = GetFirstNode (&Form->StatementListHead);\r
+    while (!IsNull (&Form->StatementListHead, Link)) {\r
+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+      Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Link = GetNextNode (&Form->StatementListHead, Link);\r
+    }\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
-  Submit a Form.\r
+  Fill storage's edit copy with settings requested from Configuration Driver.\r
 \r
   @param  FormSet                FormSet data structure.\r
-  @param  Form                   Form data structure.\r
+  @param  Storage                The storage which need to sync.\r
+  @param  ConfigRequest          The config request string which used to sync storage.\r
+  @param  SyncOrRestore          Sync the buffer to editbuffer or Restore  the \r
+                                 editbuffer to buffer\r
+                                 if TRUE, copy the editbuffer to the buffer.\r
+                                 if FALSE, copy the buffer to the editbuffer.\r
 \r
   @retval EFI_SUCCESS            The function completed successfully.\r
 \r
 **/\r
 EFI_STATUS\r
-SubmitForm (\r
-  IN FORM_BROWSER_FORMSET             *FormSet,\r
-  IN FORM_BROWSER_FORM                *Form\r
+SynchronizeStorage (\r
+  IN  FORM_BROWSER_FORMSET        *FormSet,\r
+  OUT BROWSER_STORAGE             *Storage,\r
+  IN  CHAR16                      *ConfigRequest,\r
+  IN  BOOLEAN                     SyncOrRestore\r
   )\r
 {\r
   EFI_STATUS              Status;\r
-  LIST_ENTRY              *Link;\r
-  EFI_STRING              ConfigResp;\r
   EFI_STRING              Progress;\r
-  FORMSET_STORAGE         *Storage;\r
+  EFI_STRING              Result;\r
+  UINTN                   BufferSize;\r
+  LIST_ENTRY              *Link;\r
+  NAME_VALUE_NODE         *Node;\r
+  UINT8                   *Src;\r
+  UINT8                   *Dst;\r
 \r
-  //\r
-  // Validate the Form by NoSubmit check\r
-  //\r
-  Status = NoSubmitCheck (FormSet, Form);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  Status = EFI_SUCCESS;\r
+  Result = NULL;\r
 \r
-  //\r
-  // Submit Buffer storage or Name/Value storage\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
-    if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
-      continue;\r
-    }\r
-\r
-    //\r
-    // Skip if there is no RequestElement\r
-    //\r
-    if (Storage->ElementCount == 0) {\r
-      continue;\r
-    }\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    BufferSize = Storage->Size;\r
 \r
-    //\r
-    // Prepare <ConfigResp>\r
-    //\r
-    Status = StorageToConfigResp (Storage, &ConfigResp);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
+    if (SyncOrRestore) {\r
+      Src = Storage->EditBuffer;\r
+      Dst = Storage->Buffer;\r
+    } else {\r
+      Src = Storage->Buffer;\r
+      Dst = Storage->EditBuffer;\r
     }\r
 \r
-    //\r
-    // Send <ConfigResp> to Configuration Driver\r
-    //\r
-    if (FormSet->ConfigAccess != NULL) {\r
-      Status = FormSet->ConfigAccess->RouteConfig (\r
-                                        FormSet->ConfigAccess,\r
-                                        ConfigResp,\r
-                                        &Progress\r
-                                        );\r
+    if (ConfigRequest != NULL) {\r
+      Status = mHiiConfigRouting->BlockToConfig(\r
+                                    mHiiConfigRouting,\r
+                                    ConfigRequest,\r
+                                    Src,\r
+                                    BufferSize,\r
+                                    &Result,\r
+                                    &Progress\r
+                                    );\r
       if (EFI_ERROR (Status)) {\r
-        FreePool (ConfigResp);\r
         return Status;\r
       }\r
+\r
+      Status = mHiiConfigRouting->ConfigToBlock (\r
+                                    mHiiConfigRouting,\r
+                                    Result,\r
+                                    Dst,\r
+                                    &BufferSize,\r
+                                    &Progress\r
+                                    );\r
+      if (Result != NULL) {\r
+        FreePool (Result);\r
+      }\r
+    } else {\r
+      CopyMem (Dst, Src, BufferSize);\r
     }\r
-    FreePool (ConfigResp);\r
+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    Link = GetFirstNode (&Storage->NameValueListHead);\r
+    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
 \r
-    //\r
-    // Config success, update storage shadow Buffer\r
-    //\r
-    SynchronizeStorage (Storage);\r
-  }\r
+      if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||\r
+          (ConfigRequest == NULL)) {\r
+        if (SyncOrRestore) {\r
+          NewStringCpy (&Node->Value, Node->EditValue);\r
+        } else {\r
+          NewStringCpy (&Node->EditValue, Node->Value);\r
+        }\r
+      }\r
 \r
-  gNvUpdateRequired = FALSE;\r
+      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+    }\r
+  }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
-\r
 /**\r
-  Reset Question to its default value.\r
-\r
-  @param  FormSet                The form set.\r
-  @param  Form                   The form.\r
-  @param  Question               The question.\r
-  @param  DefaultId              The Class of the default.\r
+  When discard the question value, call the callback function with Changed type\r
+  to inform the hii driver.\r
 \r
-  @retval EFI_SUCCESS            Question is reset to default value.\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
 \r
 **/\r
-EFI_STATUS\r
-GetQuestionDefault (\r
+VOID\r
+SendDiscardInfoToDriver (\r
   IN FORM_BROWSER_FORMSET             *FormSet,\r
-  IN FORM_BROWSER_FORM                *Form,\r
-  IN FORM_BROWSER_STATEMENT           *Question,\r
-  IN UINT16                           DefaultId\r
+  IN FORM_BROWSER_FORM                *Form\r
   )\r
 {\r
-  EFI_STATUS              Status;\r
-  LIST_ENTRY              *Link;\r
-  QUESTION_DEFAULT        *Default;\r
-  QUESTION_OPTION         *Option;\r
-  EFI_HII_VALUE           *HiiValue;\r
-  UINT8                   Index;\r
-  EFI_STRING              StrValue;\r
-\r
-  Status   = EFI_SUCCESS;\r
-  StrValue = NULL;\r
-\r
-  //\r
-  // Statement don't have storage, skip them\r
-  //\r
-  if (Question->QuestionId == 0) {\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // There are three ways to specify default value for a Question:\r
-  //  1, use nested EFI_IFR_DEFAULT (highest priority)\r
-  //  2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)\r
-  //  3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)\r
-  //\r
-  HiiValue = &Question->HiiValue;\r
-\r
-  //\r
-  // EFI_IFR_DEFAULT has highest priority\r
-  //\r
-  if (!IsListEmpty (&Question->DefaultListHead)) {\r
-    Link = GetFirstNode (&Question->DefaultListHead);\r
-    while (!IsNull (&Question->DefaultListHead, Link)) {\r
-      Default = QUESTION_DEFAULT_FROM_LINK (Link);\r
+  LIST_ENTRY                  *Link;\r
+  FORM_BROWSER_STATEMENT      *Question;\r
+  EFI_IFR_TYPE_VALUE          *TypeValue;\r
+  EFI_BROWSER_ACTION_REQUEST  ActionRequest;\r
 \r
-      if (Default->DefaultId == DefaultId) {\r
-        if (Default->ValueExpression != NULL) {\r
-          //\r
-          // Default is provided by an Expression, evaluate it\r
-          //\r
-          Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);\r
-          if (EFI_ERROR (Status)) {\r
-            return Status;\r
-          }\r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
 \r
-          CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE));\r
-        } else {\r
-          //\r
-          // Default value is embedded in EFI_IFR_DEFAULT\r
-          //\r
-          CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));\r
-        }\r
+    if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+      continue;\r
+    }\r
 \r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
-          StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);\r
-          if (StrValue == NULL) {\r
-            return EFI_NOT_FOUND;\r
-          }\r
-          Question->BufferValue = AllocateCopyPool (StrSize (StrValue), StrValue);\r
-        }\r
+    if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
+      continue;\r
+    }\r
 \r
-        return EFI_SUCCESS;\r
-      }\r
+    if (!Question->ValueChanged) {\r
+      continue;\r
+    }\r
 \r
-      Link = GetNextNode (&Question->DefaultListHead, Link);\r
+    if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {\r
+      TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;\r
+    } else {\r
+      TypeValue = &Question->HiiValue.Value;\r
     }\r
+\r
+    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+    FormSet->ConfigAccess->Callback (\r
+                             FormSet->ConfigAccess,\r
+                             EFI_BROWSER_ACTION_CHANGED,\r
+                             Question->QuestionId,\r
+                             Question->HiiValue.Type,\r
+                             TypeValue,\r
+                             &ActionRequest\r
+                             );\r
   }\r
+}\r
 \r
-  //\r
-  // EFI_ONE_OF_OPTION\r
-  //\r
-  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {\r
-    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {\r
-      //\r
-      // OneOfOption could only provide Standard and Manufacturing default\r
-      //\r
-      Link = GetFirstNode (&Question->OptionListHead);\r
-      while (!IsNull (&Question->OptionListHead, Link)) {\r
-        Option = QUESTION_OPTION_FROM_LINK (Link);\r
+/**\r
+  Validate the FormSet. If the formset is not validate, remove it from the list.\r
 \r
-        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||\r
-            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))\r
-           ) {\r
-          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
+  @param  FormSet                The input FormSet which need to validate.\r
 \r
-          return EFI_SUCCESS;\r
-        }\r
+  @retval TRUE                   The handle is validate.\r
+  @retval FALSE                  The handle is invalidate.\r
 \r
-        Link = GetNextNode (&Question->OptionListHead, Link);\r
-      }\r
-    }\r
-  }\r
+**/\r
+BOOLEAN\r
+ValidateFormSet (\r
+  FORM_BROWSER_FORMSET    *FormSet\r
+  )\r
+{\r
+  EFI_HII_HANDLE          *HiiHandles;\r
+  UINTN                   Index;\r
+  BOOLEAN                 Find;\r
 \r
+  ASSERT (FormSet != NULL);\r
+  Find = FALSE;\r
   //\r
-  // EFI_IFR_CHECKBOX - lowest priority\r
+  // Get all the Hii handles\r
   //\r
-  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {\r
-    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {\r
-      //\r
-      // Checkbox could only provide Standard and Manufacturing default\r
-      //\r
-      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||\r
-          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))\r
-         ) {\r
-        HiiValue->Value.b = TRUE;\r
-      } else {\r
-        HiiValue->Value.b = FALSE;\r
-      }\r
-\r
-      return EFI_SUCCESS;\r
-    }\r
-  }\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
 \r
   //\r
-  // For Questions without default\r
+  // Search for formset of each class type\r
   //\r
-  switch (Question->Operand) {\r
-  case EFI_IFR_ONE_OF_OP:\r
-    //\r
-    // Take first oneof option as oneof's default value\r
-    //\r
-    if (ValueToOption (Question, HiiValue) == NULL) {\r
-      Link = GetFirstNode (&Question->OptionListHead);\r
-      if (!IsNull (&Question->OptionListHead, Link)) {\r
-        Option = QUESTION_OPTION_FROM_LINK (Link);\r
-        CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
-      }\r
-    }\r
-    break;\r
-\r
-  case EFI_IFR_ORDERED_LIST_OP:\r
-    //\r
-    // Take option sequence in IFR as ordered list's default value\r
-    //\r
-    Index = 0;\r
-    Link = GetFirstNode (&Question->OptionListHead);\r
-    while (!IsNull (&Question->OptionListHead, Link)) {\r
-      Option = QUESTION_OPTION_FROM_LINK (Link);\r
-\r
-      SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);\r
-\r
-      Index++;\r
-      if (Index >= Question->MaxContainers) {\r
-        break;\r
-      }\r
-\r
-      Link = GetNextNode (&Question->OptionListHead, Link);\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    if (HiiHandles[Index] == FormSet->HiiHandle) {\r
+      Find = TRUE;\r
+      break;\r
     }\r
-    break;\r
-\r
-  default:\r
-    Status = EFI_NOT_FOUND;\r
-    break;\r
   }\r
 \r
-  return Status;\r
-}\r
+  if (!Find) {\r
+    CleanBrowserStorage(FormSet);\r
+    RemoveEntryList (&FormSet->Link);\r
+    DestroyFormSet (FormSet);\r
+  }\r
 \r
+  FreePool (HiiHandles);\r
 \r
+  return Find;\r
+}\r
 /**\r
-  Reset Questions in a Form to their default value.\r
+  Check whether need to enable the reset flag in form level.\r
+  Also clean all ValueChanged flag in question.\r
 \r
-  @param  FormSet                FormSet data structure.\r
-  @param  Form                   The Form which to be reset.\r
-  @param  DefaultId              The Class of the default.\r
-\r
-  @retval EFI_SUCCESS            The function completed successfully.\r
+  @param  SetFlag                Whether need to set the Reset Flag.\r
+  @param  Form                   Form data structure.\r
 \r
 **/\r
-EFI_STATUS\r
-ExtractFormDefault (\r
-  IN FORM_BROWSER_FORMSET             *FormSet,\r
-  IN FORM_BROWSER_FORM                *Form,\r
-  IN UINT16                           DefaultId\r
+VOID\r
+UpdateFlagForForm (\r
+  IN BOOLEAN                          SetFlag,\r
+  IN FORM_BROWSER_FORM                *Form\r
   )\r
 {\r
-  EFI_STATUS              Status;\r
   LIST_ENTRY              *Link;\r
   FORM_BROWSER_STATEMENT  *Question;\r
+  BOOLEAN                 FindOne;\r
 \r
+  FindOne = FALSE;\r
   Link = GetFirstNode (&Form->StatementListHead);\r
   while (!IsNull (&Form->StatementListHead, Link)) {\r
     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
-    Link = GetNextNode (&Form->StatementListHead, Link);\r
-\r
-    //\r
-    // If Question is disabled, don't reset it to default\r
-    //\r
-    if (Question->DisableExpression != NULL) {\r
-      Status = EvaluateExpression (FormSet, Form, Question->DisableExpression);\r
-      if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b) {\r
-        continue;\r
-      }\r
-    }\r
-\r
-    //\r
-    // Reset Question to its default value\r
-    //\r
-    Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
+  \r
+    if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {\r
+      gResetRequired = TRUE;\r
+    } \r
 \r
-    //\r
-    // Synchronize Buffer storage's Edit buffer\r
-    //\r
-    if ((Question->Storage != NULL) &&\r
-        (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
-      SetQuestionValue (FormSet, Form, Question, TRUE);\r
+    if (Question->ValueChanged) {\r
+      Question->ValueChanged = FALSE;\r
     }\r
+  \r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
   }\r
-\r
-  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Initialize Question's Edit copy from Storage.\r
+  Check whether need to enable the reset flag.\r
+  Also clean ValueChanged flag for all statements.\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
+  Form level or formset level, only one.\r
+  \r
+  @param  SetFlag                Whether need to set the Reset Flag.\r
   @param  FormSet                FormSet data structure.\r
   @param  Form                   Form data structure.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-\r
 **/\r
-EFI_STATUS\r
-LoadFormConfig (\r
-  IN OUT UI_MENU_SELECTION    *Selection,\r
-  IN FORM_BROWSER_FORMSET     *FormSet,\r
-  IN FORM_BROWSER_FORM        *Form\r
+VOID\r
+ValueChangeResetFlagUpdate (\r
+  IN BOOLEAN                          SetFlag,\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form  \r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  LIST_ENTRY                  *Link;\r
-  FORM_BROWSER_STATEMENT      *Question;\r
-  UINT8                       *BufferValue;\r
-  UINTN                       StorageWidth;\r
-  EFI_HII_VALUE               *HiiValue;\r
-  EFI_BROWSER_ACTION_REQUEST  ActionRequest;\r
-  \r
-  Link = GetFirstNode (&Form->StatementListHead);\r
-  while (!IsNull (&Form->StatementListHead, Link)) {\r
-    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+  FORM_BROWSER_FORM       *CurrentForm;\r
+  LIST_ENTRY              *Link;\r
+\r
+  //\r
+  // Form != NULL means only check form level.\r
+  //\r
+  if (Form != NULL) {\r
+    UpdateFlagForForm(SetFlag, Form);\r
+    return;\r
+  }\r
+\r
+  Link = GetFirstNode (&FormSet->FormListHead);\r
+  while (!IsNull (&FormSet->FormListHead, Link)) {\r
+    CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+\r
+    UpdateFlagForForm(SetFlag, CurrentForm);\r
+  }\r
+}\r
+\r
+/**\r
+  Discard data based on the input setting scope (Form, FormSet or System).\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  SettingScope           Setting Scope for Discard action.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscardForm (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN BROWSER_SETTING_SCOPE            SettingScope\r
+  )\r
+{\r
+  LIST_ENTRY                   *Link;\r
+  FORMSET_STORAGE              *Storage;\r
+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;\r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+\r
+  //\r
+  // Check the supported setting level.\r
+  //\r
+  if (SettingScope >= MaxLevel) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {\r
+    ConfigInfo = NULL;\r
+    Link = GetFirstNode (&Form->ConfigRequestHead);\r
+    while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
+      ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);\r
+      Link = GetNextNode (&Form->ConfigRequestHead, Link);\r
+\r
+      if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip if there is no RequestElement\r
+      //\r
+      if (ConfigInfo->ElementCount == 0) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Prepare <ConfigResp>\r
+      //\r
+      SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);\r
+\r
+      //\r
+      // Call callback with Changed type to inform the driver.\r
+      //\r
+      SendDiscardInfoToDriver (FormSet, Form);\r
+    }\r
+\r
+    ValueChangeResetFlagUpdate (FALSE, NULL, Form);\r
+  } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {\r
 \r
     //\r
-    // Initialize local copy of Value for each Question\r
+    // Discard Buffer storage or Name/Value storage\r
     //\r
-    Status = GetQuestionValue (FormSet, Form, Question, TRUE);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\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
+      if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip if there is no RequestElement\r
+      //\r
+      if (Storage->ElementCount == 0) {\r
+        continue;\r
+      }\r
+\r
+      SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE);\r
     }\r
+\r
+    Link = GetFirstNode (&FormSet->FormListHead);\r
+    while (!IsNull (&FormSet->FormListHead, Link)) {\r
+      Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+      Link = GetNextNode (&FormSet->FormListHead, Link);\r
+      \r
+      //\r
+      // Call callback with Changed type to inform the driver.\r
+      //\r
+      SendDiscardInfoToDriver (FormSet, Form);\r
+    }\r
+\r
+    ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);\r
+  } else if (SettingScope == SystemLevel) {\r
+    //\r
+    // System Level Discard.\r
+    //\r
     \r
     //\r
-    // Check whether EfiVarstore with CallBack can be got.\r
+    // Discard changed value for each FormSet in the maintain list.\r
     //\r
-    if ((Question->QuestionId != 0) && (Question->Storage != NULL) &&\r
-        (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) && \r
-        ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {\r
+    Link = GetFirstNode (&gBrowserFormSetList);\r
+    while (!IsNull (&gBrowserFormSetList, Link)) {\r
+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+      Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      if (!ValidateFormSet(LocalFormSet)) {\r
+        continue;\r
+      }\r
+      DiscardForm (LocalFormSet, NULL, FormSetLevel);\r
+      if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {\r
+        //\r
+        // Remove maintain backup list after discard except for the current using FormSet.\r
+        //\r
+        CleanBrowserStorage(LocalFormSet);\r
+        RemoveEntryList (&LocalFormSet->Link);\r
+        DestroyFormSet (LocalFormSet);\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;  \r
+}\r
+\r
+/**\r
+  Submit data based on the input Setting level (Form, FormSet or System).\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  SettingScope           Setting Scope for Submit action.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.\r
+\r
+**/\r
+EFI_STATUS\r
+SubmitForm (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN BROWSER_SETTING_SCOPE            SettingScope\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  LIST_ENTRY              *Link;\r
+  EFI_STRING              ConfigResp;\r
+  EFI_STRING              Progress;\r
+  BROWSER_STORAGE         *Storage;\r
+  FORMSET_STORAGE         *FormSetStorage;\r
+  UINTN                   BufferSize;\r
+  UINT8                   *TmpBuf;  \r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;\r
+\r
+  //\r
+  // Check the supported setting level.\r
+  //\r
+  if (SettingScope >= MaxLevel) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Validate the Form by NoSubmit check\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  if (SettingScope == FormLevel) {\r
+    Status = NoSubmitCheck (FormSet, Form);\r
+  } else if (SettingScope == FormSetLevel) {\r
+    Status = NoSubmitCheck (FormSet, NULL);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {\r
+    ConfigInfo = NULL;\r
+    Link = GetFirstNode (&Form->ConfigRequestHead);\r
+    while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
+      ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);\r
+      Link = GetNextNode (&Form->ConfigRequestHead, Link);\r
+\r
+      Storage = ConfigInfo->Storage;\r
+      if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+        continue;\r
+      }\r
+\r
       //\r
-      // ConfigAccess can't be NULL.\r
+      // Skip if there is no RequestElement\r
       //\r
-      if (FormSet->ConfigAccess == NULL) {\r
-        return EFI_UNSUPPORTED;\r
+      if (ConfigInfo->ElementCount == 0) {\r
+        continue;\r
       }\r
+\r
       //\r
-      // Check QuestionValue does exist.\r
+      // 1. Prepare <ConfigResp>\r
       //\r
-      StorageWidth = Question->StorageWidth;\r
-      if (Question->BufferValue != NULL) {\r
-        BufferValue  = Question->BufferValue;\r
-      } else {\r
-        BufferValue = (UINT8 *) &Question->HiiValue.Value;\r
+      Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
       }\r
-      Status = gRT->GetVariable (\r
-                       Question->VariableName,\r
-                       &Question->Storage->Guid,\r
-                       NULL,\r
-                       &StorageWidth,\r
-                       BufferValue\r
-                       );\r
 \r
-      if (!EFI_ERROR (Status)) {\r
-        ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-        HiiValue = &Question->HiiValue;\r
-        BufferValue = (UINT8 *) &Question->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 *) Question->BufferValue, FormSet->HiiHandle);\r
-        } else if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
-          BufferValue = Question->BufferValue;\r
+      //\r
+      // 2. Set value to hii driver or efi variable.\r
+      //\r
+      if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+          Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+        //\r
+        // Send <ConfigResp> to Configuration Driver\r
+        //\r
+        if (FormSet->ConfigAccess != NULL) {\r
+          Status = FormSet->ConfigAccess->RouteConfig (\r
+                                            FormSet->ConfigAccess,\r
+                                            ConfigResp,\r
+                                            &Progress\r
+                                            );\r
+          if (EFI_ERROR (Status)) {\r
+            FreePool (ConfigResp);\r
+            return Status;\r
+          }\r
+        }\r
+      } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+        TmpBuf = NULL;\r
+        TmpBuf = AllocateZeroPool(Storage->Size);\r
+        if (TmpBuf == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          return Status;\r
         }\r
 \r
-        Status = FormSet->ConfigAccess->Callback (\r
-                                 FormSet->ConfigAccess,\r
-                                 EFI_BROWSER_ACTION_RETRIEVE,\r
-                                 Question->QuestionId,\r
-                                 HiiValue->Type,\r
-                                 (EFI_IFR_TYPE_VALUE *) BufferValue,\r
-                                 &ActionRequest\r
-                                 );\r
+        BufferSize = Storage->Size;\r
+        Status = gRT->GetVariable (\r
+                         Storage->Name,\r
+                         &Storage->Guid,\r
+                         NULL,\r
+                         &BufferSize,\r
+                         TmpBuf\r
+                         );\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (TmpBuf);\r
+          FreePool (ConfigResp);\r
+          return Status;\r
+        }\r
+        ASSERT (BufferSize == Storage->Size);      \r
+        Status = mHiiConfigRouting->ConfigToBlock (\r
+                                      mHiiConfigRouting,\r
+                                      ConfigResp,\r
+                                      TmpBuf,\r
+                                      &BufferSize,\r
+                                      &Progress\r
+                                      );\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (TmpBuf);\r
+          FreePool (ConfigResp);\r
+          return Status;\r
+        }\r
 \r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
-          //\r
-          // Clean the String in HII Database\r
-          //\r
-          DeleteString (HiiValue->Value.string, FormSet->HiiHandle);\r
+        Status = gRT->SetVariable (\r
+                         Storage->Name,\r
+                         &Storage->Guid,\r
+                         Storage->Attributes,\r
+                         Storage->Size,\r
+                         TmpBuf\r
+                         );\r
+        FreePool (TmpBuf);\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (ConfigResp);\r
+          return Status;\r
         }\r
+      }\r
+      FreePool (ConfigResp);\r
+      //\r
+      // 3. Config success, update storage shadow Buffer, only update the data belong to this form.\r
+      //\r
+      SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);\r
+    }\r
 \r
-        if (!EFI_ERROR (Status)) {\r
-          switch (ActionRequest) {\r
-          case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-            gResetRequired = TRUE;\r
-            break;\r
+    //\r
+    // 4. Update the NV flag.\r
+    // \r
+    ValueChangeResetFlagUpdate(TRUE, NULL, Form);\r
+  } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {\r
+    //\r
+    // Submit Buffer storage or Name/Value storage\r
+    //\r
+    Link = GetFirstNode (&FormSet->StorageListHead);\r
+    while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+      FormSetStorage = (FORMSET_STORAGE_FROM_LINK (Link));\r
+      Storage        = FormSetStorage->BrowserStorage;\r
+      Link = GetNextNode (&FormSet->StorageListHead, Link);\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
+      if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+        continue;\r
+      }\r
 \r
-          case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            break;\r
+      //\r
+      // Skip if there is no RequestElement\r
+      //\r
+      if (FormSetStorage->ElementCount == 0) {\r
+        continue;\r
+      }\r
 \r
-          default:\r
-            break;\r
+      //\r
+      // 1. Prepare <ConfigResp>\r
+      //\r
+      Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+          Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+\r
+        //\r
+        // 2. Send <ConfigResp> to Configuration Driver\r
+        //\r
+        if (FormSet->ConfigAccess != NULL) {\r
+          Status = FormSet->ConfigAccess->RouteConfig (\r
+                                            FormSet->ConfigAccess,\r
+                                            ConfigResp,\r
+                                            &Progress\r
+                                            );\r
+          if (EFI_ERROR (Status)) {\r
+            FreePool (ConfigResp);\r
+            return Status;\r
           }\r
         }\r
+      } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+        //\r
+        // 1&2. Set the edit data to the variable.\r
+        //\r
+        TmpBuf = NULL;\r
+        TmpBuf = AllocateZeroPool (Storage->Size);\r
+        if (TmpBuf == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          return Status;\r
+        }        \r
+        BufferSize = Storage->Size;\r
+        Status = gRT->GetVariable (\r
+                       Storage->Name,\r
+                       &Storage->Guid,\r
+                       NULL,\r
+                       &BufferSize,\r
+                       TmpBuf\r
+                       );\r
+        ASSERT (BufferSize == Storage->Size);      \r
+        Status = mHiiConfigRouting->ConfigToBlock (\r
+                                      mHiiConfigRouting,\r
+                                      ConfigResp,\r
+                                      TmpBuf,\r
+                                      &BufferSize,\r
+                                      &Progress\r
+                                      );\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (TmpBuf);\r
+          FreePool (ConfigResp);\r
+          return Status;\r
+        }\r
+\r
+        Status = gRT->SetVariable (\r
+                         Storage->Name,\r
+                         &Storage->Guid,\r
+                         Storage->Attributes,\r
+                         Storage->Size,\r
+                         TmpBuf\r
+                         );\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (TmpBuf);\r
+          FreePool (ConfigResp);\r
+          return Status;\r
+        }\r
+        FreePool (TmpBuf);\r
       }\r
+      FreePool (ConfigResp);\r
+      //\r
+      // 3. Config success, update storage shadow Buffer\r
+      //\r
+      SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE);\r
     }\r
 \r
-    Link = GetNextNode (&Form->StatementListHead, Link);\r
+    //\r
+    // 4. Update the NV flag.\r
+    // \r
+    ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);\r
+  } else if (SettingScope == SystemLevel) {\r
+    //\r
+    // System Level Save.\r
+    //\r
+\r
+    //\r
+    // Save changed value for each FormSet in the maintain list.\r
+    //\r
+    Link = GetFirstNode (&gBrowserFormSetList);\r
+    while (!IsNull (&gBrowserFormSetList, Link)) {\r
+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+      Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      if (!ValidateFormSet(LocalFormSet)) {\r
+        continue;\r
+      }\r
+      SubmitForm (LocalFormSet, NULL, FormSetLevel);\r
+      if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {\r
+        //\r
+        // Remove maintain backup list after save except for the current using FormSet.\r
+        //\r
+        CleanBrowserStorage(LocalFormSet);\r
+        RemoveEntryList (&LocalFormSet->Link);\r
+        DestroyFormSet (LocalFormSet);\r
+      }\r
+    }\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Initialize Question's Edit copy from Storage for the whole Formset.\r
+  Get Question default value from AltCfg string.\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
-  @param  FormSet                FormSet data structure.\r
+  @param  FormSet                The form set.\r
+  @param  Question               The question.\r
+  @param  DefaultId              The default Id.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_SUCCESS            Question is reset to default value.\r
 \r
 **/\r
 EFI_STATUS\r
-LoadFormSetConfig (\r
-  IN OUT UI_MENU_SELECTION    *Selection,\r
-  IN     FORM_BROWSER_FORMSET *FormSet\r
+GetDefaultValueFromAltCfg (\r
+  IN     FORM_BROWSER_FORMSET             *FormSet,\r
+  IN OUT FORM_BROWSER_STATEMENT           *Question,\r
+  IN     UINT16                           DefaultId\r
   )\r
 {\r
-  EFI_STATUS            Status;\r
-  LIST_ENTRY            *Link;\r
-  FORM_BROWSER_FORM     *Form;\r
+  BOOLEAN             IsBufferStorage;\r
+  BOOLEAN             IsString;  \r
+  UINTN               Length;\r
+  BROWSER_STORAGE     *Storage;\r
+  CHAR16              *ConfigRequest;\r
+  CHAR16              *Progress;\r
+  CHAR16              *Result;\r
+  CHAR16              *ConfigResp;\r
+  CHAR16              *Value;\r
+  CHAR16              *StringPtr;\r
+  UINTN               LengthStr;\r
+  UINT8               *Dst;\r
+  CHAR16              TemStr[5];\r
+  UINTN               Index;\r
+  UINT8               DigitUint8;\r
+  EFI_STATUS          Status;\r
 \r
-  Link = GetFirstNode (&FormSet->FormListHead);\r
-  while (!IsNull (&FormSet->FormListHead, Link)) {\r
-    Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+  Status        = EFI_NOT_FOUND;\r
+  Length        = 0;\r
+  Dst           = NULL;\r
+  ConfigRequest = NULL;\r
+  Result        = NULL;\r
+  ConfigResp    = NULL;\r
+  Value         = NULL;\r
+  Storage       = Question->Storage;\r
+\r
+  if ((Storage == NULL) || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    return Status;\r
+  }\r
 \r
+  //\r
+  // Question Value is provided by Buffer Storage or NameValue Storage\r
+  //\r
+  if (Question->BufferValue != NULL) {\r
     //\r
-    // Initialize local copy of Value for each Form\r
+    // This Question is password or orderedlist\r
     //\r
-    Status = LoadFormConfig (Selection, FormSet, Form);\r
-    if (EFI_ERROR (Status)) {\r
+    Dst = Question->BufferValue;\r
+  } else {\r
+    //\r
+    // Other type of Questions\r
+    //\r
+    Dst = (UINT8 *) &Question->HiiValue.Value;\r
+  }\r
+\r
+  IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);\r
+  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);\r
+\r
+  //\r
+  // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||\r
+  //                   <ConfigHdr> + "&" + <VariableName>\r
+  //\r
+  if (IsBufferStorage) {\r
+    Length  = StrLen (Storage->ConfigHdr);\r
+    Length += StrLen (Question->BlockName);\r
+  } else {\r
+    Length  = StrLen (Storage->ConfigHdr);\r
+    Length += StrLen (Question->VariableName) + 1;\r
+  }\r
+  ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
+  ASSERT (ConfigRequest != NULL);\r
+\r
+  StrCpy (ConfigRequest, Storage->ConfigHdr);\r
+  if (IsBufferStorage) {\r
+    StrCat (ConfigRequest, Question->BlockName);\r
+  } else {\r
+    StrCat (ConfigRequest, L"&");\r
+    StrCat (ConfigRequest, Question->VariableName);\r
+  }\r
+\r
+  Status = FormSet->ConfigAccess->ExtractConfig (\r
+                                    FormSet->ConfigAccess,\r
+                                    ConfigRequest,\r
+                                    &Progress,\r
+                                    &Result\r
+                                    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)\r
+  //    Get the default configuration string according to the default ID.\r
+  //\r
+  Status = mHiiConfigRouting->GetAltConfig (\r
+                                mHiiConfigRouting,\r
+                                Result,\r
+                                &Storage->Guid,\r
+                                Storage->Name,\r
+                                NULL,\r
+                                &DefaultId,  // it can be NULL to get the current setting.\r
+                                &ConfigResp\r
+                              );\r
+  \r
+  //\r
+  // The required setting can't be found. So, it is not required to be validated and set.\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Skip <ConfigRequest>\r
+  //\r
+  if (IsBufferStorage) {\r
+    Value = StrStr (ConfigResp, L"&VALUE");\r
+    ASSERT (Value != NULL);\r
+    //\r
+    // Skip "&VALUE"\r
+    //\r
+    Value = Value + 6;\r
+  } else {\r
+    Value = StrStr (ConfigResp, Question->VariableName);\r
+    ASSERT (Value != NULL);\r
+\r
+    Value = Value + StrLen (Question->VariableName);\r
+  }\r
+  if (*Value != '=') {\r
+    Status = EFI_NOT_FOUND;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Skip '=', point to value\r
+  //\r
+  Value = Value + 1;\r
+\r
+  //\r
+  // Suppress <AltResp> if any\r
+  //\r
+  StringPtr = Value;\r
+  while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
+    StringPtr++;\r
+  }\r
+  *StringPtr = L'\0';\r
+\r
+  LengthStr = StrLen (Value);\r
+  if (!IsBufferStorage && IsString) {\r
+    StringPtr = (CHAR16 *) Dst;\r
+    ZeroMem (TemStr, sizeof (TemStr));\r
+    for (Index = 0; Index < LengthStr; Index += 4) {\r
+      StrnCpy (TemStr, Value + Index, 4);\r
+      StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);\r
+    }\r
+    //\r
+    // Add tailing L'\0' character\r
+    //\r
+    StringPtr[Index/4] = L'\0';\r
+  } else {\r
+    ZeroMem (TemStr, sizeof (TemStr));\r
+    for (Index = 0; Index < LengthStr; Index ++) {\r
+      TemStr[0] = Value[LengthStr - Index - 1];\r
+      DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+      if ((Index & 1) == 0) {\r
+        Dst [Index/2] = DigitUint8;\r
+      } else {\r
+        Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);\r
+      }\r
+    }\r
+  }\r
+\r
+Done:\r
+  if (ConfigRequest != NULL){\r
+    FreePool (ConfigRequest);\r
+  }\r
+\r
+  if (ConfigResp != NULL) {\r
+    FreePool (ConfigResp);\r
+  }\r
+  \r
+  if (Result != NULL) {\r
+    FreePool (Result);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get default Id value used for browser.\r
+\r
+  @param  DefaultId              The default id value used by hii.\r
+\r
+  @retval Browser used default value.\r
+\r
+**/\r
+INTN\r
+GetDefaultIdForCallBack (\r
+  UINTN DefaultId\r
+  )\r
+{ \r
+  if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_STANDARD;\r
+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;\r
+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_SAFE;\r
+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;\r
+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;\r
+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;\r
+  } else {\r
+    return -1;\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Return data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+\r
+  @retval Value                  The data to be returned\r
+\r
+**/\r
+UINT64\r
+GetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index\r
+  )\r
+{\r
+  UINT64 Data;\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  Data = 0;\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    Data = (UINT64) *(((UINT8 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    Data = (UINT64) *(((UINT16 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    Data = (UINT64) *(((UINT32 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    Data = (UINT64) *(((UINT64 *) Array) + Index);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+\r
+/**\r
+  Set value of a data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+  @param  Value                  The value to be set.\r
+\r
+**/\r
+VOID\r
+SetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index,\r
+  IN UINT64                   Value\r
+  )\r
+{\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Search an Option of a Question by its value.\r
+\r
+  @param  Question               The Question\r
+  @param  OptionValue            Value for Option to be searched.\r
+\r
+  @retval Pointer                Pointer to the found Option.\r
+  @retval NULL                   Option not found.\r
+\r
+**/\r
+QUESTION_OPTION *\r
+ValueToOption (\r
+  IN FORM_BROWSER_STATEMENT   *Question,\r
+  IN EFI_HII_VALUE            *OptionValue\r
+  )\r
+{\r
+  LIST_ENTRY       *Link;\r
+  QUESTION_OPTION  *Option;\r
+  INTN             Result;\r
+\r
+  Link = GetFirstNode (&Question->OptionListHead);\r
+  while (!IsNull (&Question->OptionListHead, Link)) {\r
+    Option = QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+    if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
+      //\r
+      // Check the suppressif condition, only a valid option can be return.\r
+      //\r
+      if ((Option->SuppressExpression == NULL) ||\r
+          ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {\r
+        return Option;\r
+      }\r
+    }\r
+\r
+    Link = GetNextNode (&Question->OptionListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Reset Question to its default value.\r
+\r
+  @param  FormSet                The form set.\r
+  @param  Form                   The form.\r
+  @param  Question               The question.\r
+  @param  DefaultId              The Class of the default.\r
+\r
+  @retval EFI_SUCCESS            Question is reset to default value.\r
+\r
+**/\r
+EFI_STATUS\r
+GetQuestionDefault (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN FORM_BROWSER_STATEMENT           *Question,\r
+  IN UINT16                           DefaultId\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  LIST_ENTRY              *Link;\r
+  QUESTION_DEFAULT        *Default;\r
+  QUESTION_OPTION         *Option;\r
+  EFI_HII_VALUE           *HiiValue;\r
+  UINT8                   Index;\r
+  EFI_STRING              StrValue;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  INTN                            Action;\r
+\r
+  Status   = EFI_NOT_FOUND;\r
+  StrValue = NULL;\r
+\r
+  //\r
+  // Statement don't have storage, skip them\r
+  //\r
+  if (Question->QuestionId == 0) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // There are Five ways to specify default value for a Question:\r
+  //  1, use call back function (highest priority)\r
+  //  2, use ExtractConfig function\r
+  //  3, use nested EFI_IFR_DEFAULT \r
+  //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)\r
+  //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)\r
+  //\r
+  HiiValue = &Question->HiiValue;\r
+\r
+  //\r
+  // Get Question defaut value from call back function.\r
+  //\r
+  ConfigAccess = FormSet->ConfigAccess;\r
+  Action = GetDefaultIdForCallBack (DefaultId);\r
+  if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
+    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+    Status = ConfigAccess->Callback (\r
+                             ConfigAccess,\r
+                             Action,\r
+                             Question->QuestionId,\r
+                             HiiValue->Type,\r
+                             &HiiValue->Value,\r
+                             &ActionRequest\r
+                             );\r
+    if (!EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
+  }\r
 \r
-    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  //\r
+  // Get default value from altcfg string.\r
+  //\r
+  if (ConfigAccess != NULL) {  \r
+    Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);\r
+    if (!EFI_ERROR (Status)) {\r
+        return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // EFI_IFR_DEFAULT has highest priority\r
+  //\r
+  if (!IsListEmpty (&Question->DefaultListHead)) {\r
+    Link = GetFirstNode (&Question->DefaultListHead);\r
+    while (!IsNull (&Question->DefaultListHead, Link)) {\r
+      Default = QUESTION_DEFAULT_FROM_LINK (Link);\r
+\r
+      if (Default->DefaultId == DefaultId) {\r
+        if (Default->ValueExpression != NULL) {\r
+          //\r
+          // Default is provided by an Expression, evaluate it\r
+          //\r
+          Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+\r
+          if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {\r
+            ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);\r
+            if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {\r
+              CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);\r
+              Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;\r
+            } else {\r
+              CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);\r
+              Question->HiiValue.BufferLen = Question->StorageWidth;\r
+            }\r
+            FreePool (Default->ValueExpression->Result.Buffer);\r
+          }\r
+          HiiValue->Type = Default->ValueExpression->Result.Type;\r
+          CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));       \r
+        } else {\r
+          //\r
+          // Default value is embedded in EFI_IFR_DEFAULT\r
+          //\r
+          CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));\r
+        }\r
+\r
+        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+          StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);\r
+          if (StrValue == NULL) {\r
+            return EFI_NOT_FOUND;\r
+          }\r
+          if (Question->StorageWidth > StrSize (StrValue)) {\r
+            CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));\r
+          } else {\r
+            CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);\r
+          }\r
+        }\r
+\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      Link = GetNextNode (&Question->DefaultListHead, Link);\r
+    }\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  //\r
+  // EFI_ONE_OF_OPTION\r
+  //\r
+  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {\r
+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {\r
+      //\r
+      // OneOfOption could only provide Standard and Manufacturing default\r
+      //\r
+      Link = GetFirstNode (&Question->OptionListHead);\r
+      while (!IsNull (&Question->OptionListHead, Link)) {\r
+        Option = QUESTION_OPTION_FROM_LINK (Link);\r
+        Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+        if ((Option->SuppressExpression != NULL) &&\r
+            EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+          continue;\r
+        }\r
+\r
+        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||\r
+            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))\r
+           ) {\r
+          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
+\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // EFI_IFR_CHECKBOX - lowest priority\r
+  //\r
+  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {\r
+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {\r
+      //\r
+      // Checkbox could only provide Standard and Manufacturing default\r
+      //\r
+      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||\r
+          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))\r
+         ) {\r
+        HiiValue->Value.b = TRUE;\r
+      } else {\r
+        HiiValue->Value.b = FALSE;\r
+      }\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  // For Questions without default\r
+  //\r
+  Status = EFI_NOT_FOUND;\r
+  switch (Question->Operand) {\r
+  case EFI_IFR_NUMERIC_OP:\r
+    //\r
+    // Take minimum value as numeric default value\r
+    //\r
+    if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {\r
+      HiiValue->Value.u64 = Question->Minimum;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_ONE_OF_OP:\r
+    //\r
+    // Take first oneof option as oneof's default value\r
+    //\r
+    if (ValueToOption (Question, HiiValue) == NULL) {\r
+      Link = GetFirstNode (&Question->OptionListHead);\r
+      while (!IsNull (&Question->OptionListHead, Link)) {\r
+        Option = QUESTION_OPTION_FROM_LINK (Link);\r
+        Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+        if ((Option->SuppressExpression != NULL) &&\r
+            EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+          continue;\r
+        }\r
+\r
+        CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
+        Status = EFI_SUCCESS;\r
+        break;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+    //\r
+    // Take option sequence in IFR as ordered list's default value\r
+    //\r
+    Index = 0;\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    while (!IsNull (&Question->OptionListHead, Link)) {\r
+      Status = EFI_SUCCESS;\r
+      Option = QUESTION_OPTION_FROM_LINK (Link);\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+      if ((Option->SuppressExpression != NULL) &&\r
+          EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+        continue;\r
+      }\r
+\r
+      SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);\r
+\r
+      Index++;\r
+      if (Index >= Question->MaxContainers) {\r
+        break;\r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reset Questions to their initial value or default value in a Form, Formset or System.\r
+\r
+  GetDefaultValueScope parameter decides which questions will reset \r
+  to its default value.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  DefaultId              The Class of the default.\r
+  @param  SettingScope           Setting Scope for Default action.\r
+  @param  GetDefaultValueScope   Get default value scope.\r
+  @param  Storage                Get default value only for this storage.\r
+  @param  RetrieveValueFirst     Whether call the retrieve call back to\r
+                                 get the initial value before get default\r
+                                 value.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.\r
+\r
+**/\r
+EFI_STATUS\r
+ExtractDefault (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN UINT16                           DefaultId,\r
+  IN BROWSER_SETTING_SCOPE            SettingScope,\r
+  IN BROWSER_GET_DEFAULT_VALUE        GetDefaultValueScope,\r
+  IN BROWSER_STORAGE                  *Storage OPTIONAL,\r
+  IN BOOLEAN                          RetrieveValueFirst\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  LIST_ENTRY              *FormLink;\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Check the supported setting level.\r
+  //\r
+  if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  if (SettingScope == FormLevel) {\r
+    //\r
+    // Extract Form default\r
+    //\r
+    Link = GetFirstNode (&Form->StatementListHead);\r
+    while (!IsNull (&Form->StatementListHead, Link)) {\r
+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+      Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+      //\r
+      // If get default value only for this storage, check the storage first.\r
+      //\r
+      if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // If get default value only for no storage question, just skip the question which has storage.\r
+      //\r
+      if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // If Question is disabled, don't reset it to default\r
+      //\r
+      if (Question->Expression != NULL) {\r
+        if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {\r
+          continue;\r
+        }\r
+      }\r
+\r
+      if (RetrieveValueFirst) {\r
+        //\r
+        // Call the Retrieve call back to get the initial question value.\r
+        //\r
+        Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);\r
+      }\r
+\r
+      //\r
+      // If not request to get the initial value or get initial value fail, then get default value.\r
+      //\r
+      if (!RetrieveValueFirst || EFI_ERROR (Status)) {\r
+        Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Synchronize Buffer storage's Edit buffer\r
+      //\r
+      if ((Question->Storage != NULL) &&\r
+          (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
+        SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+      }\r
+    }\r
+  } else if (SettingScope == FormSetLevel) {\r
+    FormLink = GetFirstNode (&FormSet->FormListHead);\r
+    while (!IsNull (&FormSet->FormListHead, FormLink)) {\r
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);\r
+      ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);\r
+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);\r
+    }\r
+  } else if (SettingScope == SystemLevel) {\r
+    //\r
+    // Preload all Hii formset.\r
+    //\r
+    LoadAllHiiFormset();\r
+       \r
+    //\r
+    // Set Default Value for each FormSet in the maintain list.\r
+    //\r
+    Link = GetFirstNode (&gBrowserFormSetList);\r
+    while (!IsNull (&gBrowserFormSetList, Link)) {\r
+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+      Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      if (!ValidateFormSet(LocalFormSet)) {\r
+        continue;\r
+      }\r
+      ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Validate whether this question's value has changed.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  Question               Question to be initialized.\r
+  @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.\r
+\r
+  @retval TRUE                   Question's value has changed.\r
+  @retval FALSE                  Question's value has not changed\r
+\r
+**/\r
+BOOLEAN\r
+IsQuestionValueChanged (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN OUT FORM_BROWSER_STATEMENT       *Question,\r
+  IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom\r
+  )\r
+{\r
+  EFI_HII_VALUE    BackUpValue;\r
+  CHAR8            *BackUpBuffer;\r
+  EFI_STATUS       Status;\r
+  BOOLEAN          ValueChanged;\r
+  UINTN            BufferWidth;\r
+\r
+  //\r
+  // For quetion without storage, always mark it as data not changed.\r
+  //\r
+  if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {\r
+    return FALSE;\r
+  }\r
+\r
+  BackUpBuffer = NULL;\r
+  ValueChanged = FALSE;\r
+\r
+  switch (Question->Operand) {\r
+    case EFI_IFR_ORDERED_LIST_OP:\r
+      BufferWidth  = Question->StorageWidth;\r
+      BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);\r
+      ASSERT (BackUpBuffer != NULL);\r
+      break;\r
+\r
+    case EFI_IFR_STRING_OP:\r
+    case EFI_IFR_PASSWORD_OP:\r
+      BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);\r
+      BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);\r
+      ASSERT (BackUpBuffer != NULL);\r
+      break;\r
+\r
+    default:\r
+      BufferWidth = 0;\r
+      break;\r
+  }\r
+  CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));\r
+\r
+  Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||\r
+      CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {\r
+    ValueChanged = TRUE;\r
+  }\r
+\r
+  CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));\r
+  CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);\r
+\r
+  if (BackUpBuffer != NULL) {\r
+    FreePool (BackUpBuffer);\r
+  }\r
+\r
+  return ValueChanged;\r
+}\r
+\r
+/**\r
+  Initialize Question's Edit copy from Storage.\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
+                                 If Selection is NULL, only initialize Question value.\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadFormConfig (\r
+  IN OUT UI_MENU_SELECTION    *Selection,\r
+  IN FORM_BROWSER_FORMSET     *FormSet,\r
+  IN FORM_BROWSER_FORM        *Form\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  LIST_ENTRY                  *Link;\r
+  FORM_BROWSER_STATEMENT      *Question;\r
+  UINT8                       *BufferValue;\r
+  UINTN                       StorageWidth;\r
+  \r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+    //\r
+    // Initialize local copy of Value for each Question\r
+    //\r
+    if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {\r
+      Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);\r
+    } else {\r
+      Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {\r
+      HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);\r
+    }\r
+\r
+    //\r
+    // Call the Retrieve call back function for all questions.\r
+    //\r
+    if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&\r
+        ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {\r
+      //\r
+      // Check QuestionValue does exist.\r
+      //\r
+      StorageWidth = Question->StorageWidth;\r
+      if (Question->BufferValue != NULL) {\r
+        BufferValue  = Question->BufferValue;\r
+      } else {\r
+        BufferValue = (UINT8 *) &Question->HiiValue.Value;\r
+      }\r
+\r
+      //\r
+      // For efivarstore storage, initial question value first.\r
+      //\r
+      if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
+        Status = gRT->GetVariable (\r
+                         Question->VariableName,\r
+                         &Question->Storage->Guid,\r
+                         NULL,\r
+                         &StorageWidth,\r
+                         BufferValue\r
+                         );\r
+      }\r
+\r
+      Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);\r
+    }\r
+\r
+    //\r
+    // Update Question Value changed flag.\r
+    //\r
+    Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);\r
+\r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize Question's Edit copy from Storage for the whole Formset.\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
+                                 If Selection is NULL, only initialize Question value.\r
+  @param  FormSet                FormSet data structure.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadFormSetConfig (\r
+  IN OUT UI_MENU_SELECTION    *Selection,\r
+  IN     FORM_BROWSER_FORMSET *FormSet\r
+  )\r
+{\r
+  EFI_STATUS            Status;\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
+    //\r
+    // Initialize local copy of Value for each Form\r
+    //\r
+    Status = LoadFormConfig (Selection, FormSet, Form);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  }\r
+\r
+  //\r
+  // Finished question initialization.\r
+  // \r
+  FormSet->QuestionInited = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Remove the Request element from the Config Request.\r
+\r
+  @param  Storage                Pointer to the browser storage.\r
+  @param  RequestElement         The pointer to the Request element.\r
+\r
+**/\r
+VOID\r
+RemoveElement (\r
+  IN OUT BROWSER_STORAGE      *Storage,\r
+  IN     CHAR16               *RequestElement\r
+  )\r
+{\r
+  CHAR16   *NewStr;\r
+  CHAR16   *DestStr;\r
+\r
+  ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);\r
+\r
+  NewStr = StrStr (Storage->ConfigRequest, RequestElement);\r
+\r
+  if (NewStr == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Remove this element from this ConfigRequest.\r
+  //\r
+  DestStr = NewStr;\r
+  NewStr += StrLen (RequestElement);\r
+  CopyMem (DestStr, NewStr, StrSize (NewStr));\r
+  \r
+  Storage->SpareStrLen += StrLen (RequestElement);  \r
+}\r
+\r
+/**\r
+  Adjust config request in storage, remove the request elements existed in the input ConfigRequest.\r
+\r
+  @param  Storage                Pointer to the browser storage.\r
+  @param  ConfigRequest          The pointer to the Request element.\r
+\r
+**/\r
+VOID\r
+RemoveConfigRequest (\r
+  BROWSER_STORAGE   *Storage,\r
+  CHAR16            *ConfigRequest\r
+  )\r
+{\r
+  CHAR16       *RequestElement;\r
+  CHAR16       *NextRequestElement;\r
+  CHAR16       *SearchKey;\r
+\r
+  //\r
+  // No request element in it, just return.\r
+  //\r
+  if (ConfigRequest == NULL) {\r
+    return;\r
+  }\r
+\r
+  if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    //\r
+    // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
+    //\r
+    SearchKey = L"&";\r
+  } else {\r
+    //\r
+    // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage\r
+    //\r
+    SearchKey = L"&OFFSET";\r
+  }\r
+\r
+  //\r
+  // Find SearchKey storage\r
+  //\r
+  if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    RequestElement = StrStr (ConfigRequest, L"PATH");\r
+    ASSERT (RequestElement != NULL);\r
+    RequestElement = StrStr (RequestElement, SearchKey);    \r
+  } else {\r
+    RequestElement = StrStr (ConfigRequest, SearchKey);\r
+  }\r
+\r
+  while (RequestElement != NULL) {\r
+    //\r
+    // +1 to avoid find header itself.\r
+    //\r
+    NextRequestElement = StrStr (RequestElement + 1, SearchKey);\r
+\r
+    //\r
+    // The last Request element in configRequest string.\r
+    //\r
+    if (NextRequestElement != NULL) {\r
+      //\r
+      // Replace "&" with '\0'.\r
+      //\r
+      *NextRequestElement = L'\0';\r
+    }\r
+\r
+    RemoveElement (Storage, RequestElement);\r
+\r
+    if (NextRequestElement != NULL) {\r
+      //\r
+      // Restore '&' with '\0' for later used.\r
+      //\r
+      *NextRequestElement = L'&';\r
+    }\r
+\r
+    RequestElement = NextRequestElement;\r
+  }\r
+\r
+  //\r
+  // If no request element remain, just remove the ConfigRequest string.\r
+  //\r
+  if (StrCmp (Storage->ConfigRequest, Storage->ConfigHdr) == 0) {\r
+    FreePool (Storage->ConfigRequest);\r
+    Storage->ConfigRequest = NULL;\r
+    Storage->SpareStrLen   = 0;\r
+  }\r
+}\r
+\r
+/**\r
+  Base on the current formset info, clean the ConfigRequest string in browser storage.\r
+\r
+  @param  FormSet                Pointer of the FormSet\r
+\r
+**/\r
+VOID\r
+CleanBrowserStorage (\r
+  IN OUT FORM_BROWSER_FORMSET  *FormSet\r
+  )\r
+{\r
+  LIST_ENTRY            *Link;\r
+  FORMSET_STORAGE       *Storage;\r
+  CHAR16                *ConfigRequest;\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
+    if ((Storage->BrowserStorage->Type != EFI_HII_VARSTORE_BUFFER) && \r
+        (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) && \r
+        (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+      continue;\r
+    }\r
+\r
+    if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {\r
+      continue;\r
+    }\r
+\r
+    ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements;\r
+    RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest);\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether current element in the ConfigReqeust string.\r
+\r
+  @param  BrowserStorage                Storage which includes ConfigReqeust.\r
+  @param  RequestElement                New element need to check.\r
+\r
+  @retval TRUE        The Element is in the ConfigReqeust string.\r
+  @retval FALSE       The Element not in the configReqeust String.\r
+\r
+**/\r
+BOOLEAN \r
+ElementValidation (\r
+  BROWSER_STORAGE   *BrowserStorage,\r
+  CHAR16            *RequestElement\r
+  )\r
+{\r
+  return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;\r
+}\r
+\r
+/**\r
+  Append the Request element to the Config Request.\r
+\r
+  @param  ConfigRequest          Current ConfigRequest info.\r
+  @param  SpareStrLen            Current remain free buffer for config reqeust.\r
+  @param  RequestElement         New Request element.\r
+\r
+**/\r
+VOID\r
+AppendConfigRequest (\r
+  IN OUT CHAR16               **ConfigRequest,\r
+  IN OUT UINTN                *SpareStrLen,\r
+  IN     CHAR16               *RequestElement\r
+  )\r
+{\r
+  CHAR16   *NewStr;\r
+  UINTN    StringSize;\r
+  UINTN    StrLength;\r
+\r
+  StrLength = StrLen (RequestElement);\r
+\r
+  //\r
+  // Append <RequestElement> to <ConfigRequest>\r
+  //\r
+  if (StrLength > *SpareStrLen) {\r
+    //\r
+    // Old String buffer is not sufficient for RequestElement, allocate a new one\r
+    //\r
+    StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);\r
+    NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));\r
+    ASSERT (NewStr != NULL);\r
+\r
+    if (*ConfigRequest != NULL) {\r
+      CopyMem (NewStr, *ConfigRequest, StringSize);\r
+      FreePool (*ConfigRequest);\r
+    }\r
+    *ConfigRequest = NewStr;\r
+    *SpareStrLen   = CONFIG_REQUEST_STRING_INCREMENTAL;\r
+  }\r
+\r
+  StrCat (*ConfigRequest, RequestElement);\r
+  *SpareStrLen -= StrLength;\r
+}\r
+\r
+/**\r
+  Adjust the config request info, remove the request elements which already in AllConfigRequest string.\r
+\r
+  @param  Storage                Form set Storage.\r
+\r
+  @retval TRUE                   Has element not covered by current used elements, need to continue to call ExtractConfig\r
+  @retval FALSE                  All elements covered by current used elements.\r
+\r
+**/\r
+BOOLEAN \r
+ConfigRequestAdjust (\r
+  IN  FORMSET_STORAGE         *Storage\r
+  )\r
+{\r
+  CHAR16       *RequestElement;\r
+  CHAR16       *NextRequestElement;\r
+  CHAR16       *RetBuf;\r
+  UINTN        SpareBufLen;\r
+  CHAR16       *SearchKey;\r
+  BOOLEAN      RetVal;\r
+\r
+  SpareBufLen    = 0;\r
+  RetBuf         = NULL;\r
+  RetVal         = FALSE;\r
+\r
+  if (Storage->BrowserStorage->ConfigRequest == NULL) {\r
+    Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+    if (Storage->ConfigElements != NULL) {\r
+      FreePool (Storage->ConfigElements);\r
+    }\r
+    Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+    return TRUE;\r
+  }\r
+\r
+  if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    //\r
+    // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
+    //\r
+    SearchKey = L"&";\r
+  } else {\r
+    //\r
+    // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage\r
+    //\r
+    SearchKey = L"&OFFSET";\r
+  }\r
+\r
+  //\r
+  // Prepare the config header.\r
+  // \r
+  RetBuf = AllocateCopyPool(StrSize (Storage->BrowserStorage->ConfigHdr), Storage->BrowserStorage->ConfigHdr);\r
+  ASSERT (RetBuf != NULL);\r
+\r
+  //\r
+  // Find SearchKey storage\r
+  //\r
+  if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    RequestElement = StrStr (Storage->ConfigRequest, L"PATH");\r
+    ASSERT (RequestElement != NULL);\r
+    RequestElement = StrStr (RequestElement, SearchKey);    \r
+  } else {\r
+    RequestElement = StrStr (Storage->ConfigRequest, SearchKey);\r
+  }\r
+\r
+  while (RequestElement != NULL) {\r
+    //\r
+    // +1 to avoid find header itself.\r
+    //\r
+    NextRequestElement = StrStr (RequestElement + 1, SearchKey);\r
+\r
+    //\r
+    // The last Request element in configRequest string.\r
+    //\r
+    if (NextRequestElement != NULL) {\r
+      //\r
+      // Replace "&" with '\0'.\r
+      //\r
+      *NextRequestElement = L'\0';\r
+    }\r
\r
+    if (!ElementValidation (Storage->BrowserStorage, RequestElement)) {\r
+      //\r
+      // Add this element to the Storage->BrowserStorage->AllRequestElement.\r
+      //\r
+      AppendConfigRequest(&Storage->BrowserStorage->ConfigRequest, &Storage->BrowserStorage->SpareStrLen, RequestElement);\r
+      AppendConfigRequest (&RetBuf, &SpareBufLen, RequestElement);\r
+      RetVal = TRUE;\r
+    }\r
+\r
+    if (NextRequestElement != NULL) {\r
+      //\r
+      // Restore '&' with '\0' for later used.\r
+      //\r
+      *NextRequestElement = L'&';\r
+    }\r
+\r
+    RequestElement = NextRequestElement;\r
+  }\r
+\r
+  if (RetVal) {\r
+    if (Storage->ConfigElements != NULL) {\r
+      FreePool (Storage->ConfigElements);\r
+    }\r
+    Storage->ConfigElements = RetBuf;\r
+  } else {\r
+    FreePool (RetBuf);\r
+  }\r
+\r
+  return RetVal;\r
+}\r
+\r
+/**\r
+\r
+  Base on ConfigRequest info to get default value for current formset. \r
+\r
+  ConfigRequest info include the info about which questions in current formset need to \r
+  get default value. This function only get these questions default value.\r
+  \r
+  @param  FormSet                FormSet data structure.\r
+  @param  Storage                Storage need to update value.\r
+  @param  ConfigRequest          The config request string.\r
+\r
+**/\r
+VOID\r
+GetDefaultForFormset (\r
+  IN FORM_BROWSER_FORMSET    *FormSet,\r
+  IN BROWSER_STORAGE         *Storage,\r
+  IN CHAR16                  *ConfigRequest\r
+  )\r
+{\r
+  UINT8             *BackUpBuf;\r
+  UINTN             BufferSize;\r
+  LIST_ENTRY        BackUpList;\r
+  NAME_VALUE_NODE   *Node;\r
+  LIST_ENTRY        *Link;\r
+  LIST_ENTRY        *NodeLink;\r
+  NAME_VALUE_NODE   *TmpNode;\r
+  EFI_STATUS        Status;\r
+  EFI_STRING        Progress;\r
+  EFI_STRING        Result;\r
+\r
+  BackUpBuf = NULL;\r
+  InitializeListHead(&BackUpList);\r
+\r
+  //\r
+  // Back update the edit buffer.\r
+  // \r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);\r
+    ASSERT (BackUpBuf != NULL);\r
+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    Link = GetFirstNode (&Storage->NameValueListHead);\r
+    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+\r
+      //\r
+      // Only back Node belong to this formset.\r
+      //\r
+      if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {\r
+        continue;\r
+      }\r
+\r
+      TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);\r
+      TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);\r
+      TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
+\r
+      InsertTailList(&BackUpList, &TmpNode->Link);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get default value.\r
+  //\r
+  ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);\r
+\r
+  //\r
+  // Update the question value based on the input ConfigRequest.\r
+  //\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    ASSERT (BackUpBuf != NULL);\r
+    BufferSize = Storage->Size;\r
+    Status = mHiiConfigRouting->BlockToConfig(\r
+                                  mHiiConfigRouting,\r
+                                  ConfigRequest,\r
+                                  Storage->EditBuffer,\r
+                                  BufferSize,\r
+                                  &Result,\r
+                                  &Progress\r
+                                  );\r
+    ASSERT_EFI_ERROR (Status);\r
+    \r
+    Status = mHiiConfigRouting->ConfigToBlock (\r
+                                  mHiiConfigRouting,\r
+                                  Result,\r
+                                  BackUpBuf,\r
+                                  &BufferSize,\r
+                                  &Progress\r
+                                  );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    if (Result != NULL) {\r
+      FreePool (Result);\r
+    }\r
+    \r
+    CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);\r
+    FreePool (BackUpBuf);\r
+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    //\r
+    // Update question value, only element in ConfigReqeust will be update.\r
+    //\r
+    Link = GetFirstNode (&BackUpList);\r
+    while (!IsNull (&BackUpList, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+      Link = GetNextNode (&BackUpList, Link);\r
+\r
+      if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
+        continue;\r
+      }\r
+\r
+      NodeLink = GetFirstNode (&Storage->NameValueListHead);\r
+      while (!IsNull (&Storage->NameValueListHead, NodeLink)) {\r
+        TmpNode  = NAME_VALUE_NODE_FROM_LINK (NodeLink);\r
+        NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);\r
+      \r
+        if (StrCmp (Node->Name, TmpNode->Name) != 0) {\r
+          continue;\r
+        }\r
+\r
+        FreePool (TmpNode->EditValue);\r
+        TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
+\r
+        RemoveEntryList (&Node->Link);\r
+        FreePool (Node->EditValue);\r
+        FreePool (Node->Name);\r
+        FreePool (Node);\r
+      }\r
+    }\r
+\r
+    //\r
+    // Restore the Name/Value node.\r
+    //  \r
+    Link = GetFirstNode (&BackUpList);\r
+    while (!IsNull (&BackUpList, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+      Link = GetNextNode (&BackUpList, Link);\r
\r
+      //\r
+      // Free this node.\r
+      //\r
+      RemoveEntryList (&Node->Link);\r
+      FreePool (Node->EditValue);\r
+      FreePool (Node->Name);\r
+      FreePool (Node);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Fill storage's edit copy with settings requested from Configuration Driver.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Storage                Buffer Storage.\r
+\r
+**/\r
+VOID\r
+LoadStorage (\r
+  IN FORM_BROWSER_FORMSET    *FormSet,\r
+  IN FORMSET_STORAGE         *Storage\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_STRING  Progress;\r
+  EFI_STRING  Result;\r
+  CHAR16      *StrPtr;\r
+\r
+  switch (Storage->BrowserStorage->Type) {\r
+    case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+      return;\r
+\r
+    case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+      if (Storage->BrowserStorage->ReferenceCount > 1) {\r
+        ConfigRequestAdjust(Storage);\r
+        return;\r
+      }\r
+\r
+      Status = gRT->GetVariable (\r
+                       Storage->BrowserStorage->Name,\r
+                       &Storage->BrowserStorage->Guid,\r
+                       NULL,\r
+                       (UINTN*)&Storage->BrowserStorage->Size,\r
+                       Storage->BrowserStorage->EditBuffer\r
+                       );\r
+      //\r
+      // If get variable fail, extract default from IFR binary\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);\r
+      }\r
+\r
+      Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+      //\r
+      // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. \r
+      //\r
+      SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE);\r
+      break;\r
+\r
+    case EFI_HII_VARSTORE_BUFFER:\r
+    case EFI_HII_VARSTORE_NAME_VALUE:\r
+      //\r
+      // Skip if there is no RequestElement\r
+      //\r
+      if (Storage->ElementCount == 0) {\r
+        return;\r
+      }\r
+\r
+      //\r
+      // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig\r
+      // will used to call ExtractConfig.\r
+      // If not elements need to udpate, return.\r
+      //\r
+      if (!ConfigRequestAdjust(Storage)) {\r
+        return;\r
+      }\r
+      ASSERT (Storage->ConfigElements != NULL);\r
+\r
+      Status = EFI_NOT_FOUND;\r
+      if (FormSet->ConfigAccess != NULL) { \r
+        //\r
+        // Request current settings from Configuration Driver\r
+        //\r
+        Status = FormSet->ConfigAccess->ExtractConfig (\r
+                                          FormSet->ConfigAccess,\r
+                                          Storage->ConfigElements,\r
+                                          &Progress,\r
+                                          &Result\r
+                                          );\r
+        \r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // Convert Result from <ConfigAltResp> to <ConfigResp>\r
+          //\r
+          StrPtr = StrStr (Result, L"&GUID=");\r
+          if (StrPtr != NULL) {\r
+            *StrPtr = L'\0';\r
+          }\r
+          \r
+          Status = ConfigRespToStorage (Storage->BrowserStorage, Result);\r
+          FreePool (Result);\r
+        }\r
+      }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Base on the configRequest string to get default value.\r
+        //\r
+        GetDefaultForFormset (FormSet, Storage->BrowserStorage, Storage->ConfigElements);\r
+      }\r
+\r
+      SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigElements, TRUE);\r
+      break;\r
+\r
+    default:\r
+      break;\r
+  }\r
+}\r
+\r
+/**\r
+  Get current setting of Questions.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+\r
+**/\r
+VOID\r
+InitializeCurrentSetting (\r
+  IN OUT FORM_BROWSER_FORMSET             *FormSet\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORMSET_STORAGE         *Storage;\r
+  FORM_BROWSER_FORMSET    *OldFormSet;\r
+\r
+  //\r
+  // Extract default from IFR binary for no storage questions.\r
+  //  \r
+  ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);\r
+\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
+\r
+    LoadStorage (FormSet, Storage);\r
+\r
+    Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+  }\r
+\r
+  //\r
+  // Try to find pre FormSet in the maintain backup list.\r
+  // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.\r
+  //\r
+  OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);\r
+  if (OldFormSet != NULL) {\r
+    RemoveEntryList (&OldFormSet->Link);\r
+    DestroyFormSet (OldFormSet);\r
+  }\r
+  InsertTailList (&gBrowserFormSetList, &FormSet->Link);\r
+}\r
+\r
+\r
+/**\r
+  Fetch the Ifr binary data of a FormSet.\r
+\r
+  @param  Handle                 PackageList Handle\r
+  @param  FormSetGuid            On input, GUID or class GUID of a formset. If not\r
+                                 specified (NULL or zero GUID), take the first\r
+                                 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
+                                 found in package list.\r
+                                 On output, GUID of the formset found(if not NULL).\r
+  @param  BinaryLength           The length of the FormSet IFR binary.\r
+  @param  BinaryData             The buffer designed to receive the FormSet.\r
+\r
+  @retval EFI_SUCCESS            Buffer filled with the requested FormSet.\r
+                                 BufferLength was updated.\r
+  @retval EFI_INVALID_PARAMETER  The handle is unknown.\r
+  @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot\r
+                                 be found with the requested FormId.\r
+\r
+**/\r
+EFI_STATUS\r
+GetIfrBinaryData (\r
+  IN  EFI_HII_HANDLE   Handle,\r
+  IN OUT EFI_GUID      *FormSetGuid,\r
+  OUT UINTN            *BinaryLength,\r
+  OUT UINT8            **BinaryData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
+  UINTN                        BufferSize;\r
+  UINT8                        *Package;\r
+  UINT8                        *OpCodeData;\r
+  UINT32                       Offset;\r
+  UINT32                       Offset2;\r
+  UINT32                       PackageListLength;\r
+  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
+  UINT8                        Index;\r
+  UINT8                        NumberOfClassGuid;\r
+  BOOLEAN                      ClassGuidMatch;\r
+  EFI_GUID                     *ClassGuid;\r
+  EFI_GUID                     *ComparingGuid;\r
+\r
+  OpCodeData = NULL;\r
+  Package = NULL;\r
+  ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+  //\r
+  // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list\r
+  //\r
+  if (FormSetGuid == NULL) {\r
+    ComparingGuid = &gZeroGuid;\r
+  } else {\r
+    ComparingGuid = FormSetGuid;\r
+  }\r
+\r
+  //\r
+  // Get HII PackageList\r
+  //\r
+  BufferSize = 0;\r
+  HiiPackageList = NULL;\r
+  Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    HiiPackageList = AllocatePool (BufferSize);\r
+    ASSERT (HiiPackageList != NULL);\r
+\r
+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (HiiPackageList != NULL);\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
+  ClassGuidMatch = FALSE;\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 (FormSetGuid, &gZeroGuid) || \r
+              CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+            break;\r
+          }\r
+\r
+          if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {\r
+            //\r
+            // Try to compare against formset class GUID\r
+            //\r
+            NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);\r
+            ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));\r
+            for (Index = 0; Index < NumberOfClassGuid; Index++) {\r
+              if (CompareGuid (ComparingGuid, ClassGuid + Index)) {\r
+                ClassGuidMatch = TRUE;\r
+                break;\r
+              }\r
+            }\r
+            if (ClassGuidMatch) {\r
+              break;\r
+            }\r
+          } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {\r
+            ClassGuidMatch = TRUE;\r
+            break;\r
+          }\r
+        }\r
+\r
+        Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+      }\r
+\r
+      if (Offset2 < PackageHeader.Length) {\r
+        //\r
+        // Target formset found\r
+        //\r
+        break;\r
+      }\r
+    }\r
+\r
+    Offset += PackageHeader.Length;\r
+  }\r
+\r
+  if (Offset >= PackageListLength) {\r
+    //\r
+    // Form package not found in this Package List\r
+    //\r
+    FreePool (HiiPackageList);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (FormSetGuid != NULL) {\r
+    //\r
+    // Return the FormSet GUID\r
+    //\r
+    CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
+  }\r
+\r
+  //\r
+  // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes\r
+  // in this FormSet; So, here just simply copy the data from start of a FormSet to the end\r
+  // of the Form Package.\r
+  //\r
+  *BinaryLength = PackageHeader.Length - Offset2;\r
+  *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);\r
+\r
+  FreePool (HiiPackageList);\r
+\r
+  if (*BinaryData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Initialize the internal data structure of a FormSet.\r
+\r
+  @param  Handle                 PackageList Handle\r
+  @param  FormSetGuid            On input, GUID or class GUID of a formset. If not\r
+                                 specified (NULL or zero GUID), take the first\r
+                                 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
+                                 found in package list.\r
+                                 On output, GUID of the formset found(if not NULL).\r
+  @param  FormSet                FormSet data structure.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_NOT_FOUND          The specified FormSet could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeFormSet (\r
+  IN  EFI_HII_HANDLE                   Handle,\r
+  IN OUT EFI_GUID                      *FormSetGuid,\r
+  OUT FORM_BROWSER_FORMSET             *FormSet\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                DriverHandle;\r
+\r
+  Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;\r
+  FormSet->HiiHandle = Handle;\r
+  CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));\r
+  FormSet->QuestionInited = FALSE;\r
+\r
+  //\r
+  // Retrieve ConfigAccess Protocol associated with this HiiPackageList\r
+  //\r
+  Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  FormSet->DriverHandle = DriverHandle;\r
+  Status = gBS->HandleProtocol (\r
+                  DriverHandle,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  (VOID **) &FormSet->ConfigAccess\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Configuration Driver don't attach ConfigAccess protocol to its HII package\r
+    // list, then there will be no configuration action required\r
+    //\r
+    FormSet->ConfigAccess = NULL;\r
+  }\r
+\r
+  //\r
+  // Parse the IFR binary OpCodes\r
+  //\r
+  Status = ParseOpCodes (FormSet);\r
+\r
+  return Status;\r
 }\r
 \r
-/**\r
-  Fill storage's edit copy with settings requested from Configuration Driver.\r
-\r
-  @param  FormSet                FormSet data structure.\r
-  @param  Storage                Buffer Storage.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
+/**\r
+  Save globals used by previous call to SendForm(). SendForm() may be called from \r
+  HiiConfigAccess.Callback(), this will cause SendForm() be reentried.\r
+  So, save globals of previous call to SendForm() and restore them upon exit.\r
 \r
 **/\r
-EFI_STATUS\r
-LoadStorage (\r
-  IN FORM_BROWSER_FORMSET    *FormSet,\r
-  IN FORMSET_STORAGE         *Storage\r
+VOID\r
+SaveBrowserContext (\r
+  VOID\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  EFI_STRING  Progress;\r
-  EFI_STRING  Result;\r
-  CHAR16      *StrPtr;\r
-\r
-  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  if (FormSet->ConfigAccess == NULL) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
+  BROWSER_CONTEXT  *Context;\r
+  FORM_ENTRY_INFO     *MenuList;\r
 \r
-  if (Storage->ElementCount == 0) {\r
+  gBrowserContextCount++;\r
+  if (gBrowserContextCount == 1) {\r
     //\r
-    // Skip if there is no RequestElement\r
+    // This is not reentry of SendForm(), no context to save\r
     //\r
-    return EFI_SUCCESS;\r
+    return;\r
   }\r
 \r
   //\r
-  // Request current settings from Configuration Driver\r
+  // Not support SendForm nest in another SendForm, assert here.\r
   //\r
-  Status = FormSet->ConfigAccess->ExtractConfig (\r
-                                    FormSet->ConfigAccess,\r
-                                    Storage->ConfigRequest,\r
-                                    &Progress,\r
-                                    &Result\r
-                                    );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  ASSERT (FALSE);\r
+\r
+  Context = AllocatePool (sizeof (BROWSER_CONTEXT));\r
+  ASSERT (Context != NULL);\r
+\r
+  Context->Signature = BROWSER_CONTEXT_SIGNATURE;\r
+\r
+  //\r
+  // Save FormBrowser context\r
+  //\r
+  Context->ResetRequired        = gResetRequired;\r
+  Context->ExitRequired         = gExitRequired;\r
+  Context->HiiHandle            = mCurrentHiiHandle;\r
 \r
   //\r
-  // Convert Result from <ConfigAltResp> to <ConfigResp>\r
+  // Save the menu history data.\r
   //\r
-  StrPtr = StrStr (Result, L"ALTCFG");\r
-  if (StrPtr != NULL) {\r
-    *StrPtr = L'\0';\r
+  InitializeListHead(&Context->FormHistoryList);\r
+  while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+\r
+    InsertTailList(&Context->FormHistoryList, &MenuList->Link);\r
   }\r
 \r
-  Status = ConfigRespToStorage (Storage, Result);\r
-  FreePool (Result);\r
-  return Status;\r
+  //\r
+  // Insert to FormBrowser context list\r
+  //\r
+  InsertHeadList (&gBrowserContextList, &Context->Link);\r
 }\r
 \r
 \r
 /**\r
-  Copy uncommitted data from source Storage to destination Storage.\r
-\r
-  @param  Dst                    Target Storage for uncommitted data.\r
-  @param  Src                    Source Storage for uncommitted data.\r
-\r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-  @retval EFI_INVALID_PARAMETER  Source and destination Storage is not the same type.\r
+  Restore globals used by previous call to SendForm().\r
 \r
 **/\r
-EFI_STATUS\r
-CopyStorage (\r
-  IN OUT FORMSET_STORAGE     *Dst,\r
-  IN FORMSET_STORAGE         *Src\r
+VOID\r
+RestoreBrowserContext (\r
+  VOID\r
   )\r
 {\r
-  LIST_ENTRY          *Link;\r
-  NAME_VALUE_NODE     *Node;\r
+  LIST_ENTRY       *Link;\r
+  BROWSER_CONTEXT  *Context;\r
+  FORM_ENTRY_INFO     *MenuList;\r
 \r
-  if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {\r
-    return EFI_INVALID_PARAMETER;\r
+  ASSERT (gBrowserContextCount != 0);\r
+  gBrowserContextCount--;\r
+  if (gBrowserContextCount == 0) {\r
+    //\r
+    // This is not reentry of SendForm(), no context to restore\r
+    //\r
+    return;\r
   }\r
 \r
-  switch (Src->Type) {\r
-  case EFI_HII_VARSTORE_BUFFER:\r
-    CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);\r
-    break;\r
+  ASSERT (!IsListEmpty (&gBrowserContextList));\r
 \r
-  case EFI_HII_VARSTORE_NAME_VALUE:\r
-    Link = GetFirstNode (&Src->NameValueListHead);\r
-    while (!IsNull (&Src->NameValueListHead, Link)) {\r
-      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+  Link = GetFirstNode (&gBrowserContextList);\r
+  Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
 \r
-      SetValueByName (Dst, Node->Name, Node->EditValue);\r
+  //\r
+  // Restore FormBrowser context\r
+  //\r
+  gResetRequired        = Context->ResetRequired;\r
+  gExitRequired         = Context->ExitRequired;\r
+  mCurrentHiiHandle     = Context->HiiHandle;\r
 \r
-      Link = GetNextNode (&Src->NameValueListHead, Link);\r
-    }\r
-    break;\r
+  //\r
+  // Restore the menu history data.\r
+  //\r
+  while (!IsListEmpty (&Context->FormHistoryList)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
 \r
-  case EFI_HII_VARSTORE_EFI_VARIABLE:\r
-  default:\r
-    break;\r
+    InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  //\r
+  // Remove from FormBrowser context list\r
+  //\r
+  RemoveEntryList (&Context->Link);\r
+  gBS->FreePool (Context);\r
 }\r
 \r
-\r
 /**\r
-  Get current setting of Questions.\r
+  Find the matched FormSet context in the backup maintain list based on HiiHandle.\r
+  \r
+  @param Handle  The Hii Handle.\r
+  \r
+  @return the found FormSet context. If no found, NULL will return.\r
 \r
-  @param  FormSet                FormSet data structure.\r
+**/\r
+FORM_BROWSER_FORMSET * \r
+GetFormSetFromHiiHandle (\r
+  EFI_HII_HANDLE Handle\r
+  )\r
+{\r
+  LIST_ENTRY           *Link;\r
+  FORM_BROWSER_FORMSET *FormSet;\r
+\r
+  Link = GetFirstNode (&gBrowserFormSetList);\r
+  while (!IsNull (&gBrowserFormSetList, Link)) {\r
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+    Link = GetNextNode (&gBrowserFormSetList, Link);\r
+    if (!ValidateFormSet(FormSet)) {\r
+      continue;\r
+    }\r
+    if (FormSet->HiiHandle == Handle) {\r
+      return FormSet;\r
+    }\r
+  }\r
+  \r
+  return NULL;\r
+}\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
+/**\r
+  Check whether the input HII handle is the FormSet that is being used.\r
+  \r
+  @param Handle  The Hii Handle.\r
+  \r
+  @retval TRUE   HII handle is being used.\r
+  @retval FALSE  HII handle is not being used.\r
 \r
 **/\r
-EFI_STATUS\r
-InitializeCurrentSetting (\r
-  IN OUT FORM_BROWSER_FORMSET             *FormSet\r
+BOOLEAN\r
+IsHiiHandleInBrowserContext (\r
+  EFI_HII_HANDLE Handle\r
   )\r
 {\r
-  LIST_ENTRY              *Link;\r
-  LIST_ENTRY              *Link2;\r
-  FORMSET_STORAGE         *Storage;\r
-  FORMSET_STORAGE         *StorageSrc;\r
-  FORMSET_STORAGE         *OldStorage;\r
-  FORM_BROWSER_FORM       *Form;\r
-  EFI_STATUS              Status;\r
+  LIST_ENTRY       *Link;\r
+  BROWSER_CONTEXT  *Context;\r
 \r
   //\r
-  // Extract default from IFR binary\r
+  // HiiHandle is Current FormSet.\r
   //\r
-  Link = GetFirstNode (&FormSet->FormListHead);\r
-  while (!IsNull (&FormSet->FormListHead, Link)) {\r
-    Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
-\r
-    Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD);\r
-\r
-    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  if (mCurrentHiiHandle == Handle) {\r
+    return TRUE;\r
   }\r
 \r
   //\r
-  // Request current settings from Configuration Driver\r
+  // Check whether HiiHandle is in BrowserContext.\r
   //\r
-  Link = GetFirstNode (&FormSet->StorageListHead);\r
-  while (!IsNull (&FormSet->StorageListHead, Link)) {\r
-    Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
-\r
-    OldStorage = NULL;\r
-    if (gOldFormSet != NULL) {\r
+  Link = GetFirstNode (&gBrowserContextList);\r
+  while (!IsNull (&gBrowserContextList, Link)) {\r
+    Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
+    if (Context->HiiHandle == Handle) {\r
       //\r
-      // Try to find the Storage in backup formset gOldFormSet\r
+      // HiiHandle is in BrowserContext\r
       //\r
-      Link2 = GetFirstNode (&gOldFormSet->StorageListHead);\r
-      while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {\r
-        StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);\r
-\r
-        if (StorageSrc->VarStoreId == Storage->VarStoreId) {\r
-          OldStorage = StorageSrc;\r
-          break;\r
-        }\r
-\r
-        Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);\r
-      }\r
+      return TRUE;\r
     }\r
+    Link = GetNextNode (&gBrowserContextList, Link);\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
 \r
-    if (OldStorage == NULL) {\r
-      //\r
-      // Storage is not found in backup formset, request it from ConfigDriver\r
-      //\r
-      Status = LoadStorage (FormSet, Storage);\r
+/**\r
+  Perform Password check. \r
+  Passwork may be encrypted by driver that requires the specific check.\r
+  \r
+  @param  Form             Form where Password Statement is in.\r
+  @param  Statement        Password statement\r
+  @param  PasswordString   Password string to be checked. It may be NULL.\r
+                           NULL means to restore password.\r
+                           "" string can be used to checked whether old password does exist.\r
+  \r
+  @return Status     Status of Password check.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PasswordCheck (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN EFI_STRING                    PasswordString  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  EFI_IFR_TYPE_VALUE              IfrTypeValue;\r
+  FORM_BROWSER_STATEMENT          *Question;\r
+\r
+  ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;\r
+  Question = GetBrowserStatement(Statement);\r
+  ASSERT (Question != NULL);\r
+\r
+  if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {\r
+    if (ConfigAccess == NULL) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  } else {\r
+    if (PasswordString == NULL) {\r
+      return EFI_SUCCESS;\r
+    } \r
+    \r
+    if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {\r
+      return EFI_SUCCESS;\r
     } else {\r
-      //\r
-      // Storage found in backup formset, use it\r
-      //\r
-      Status = CopyStorage (Storage, OldStorage);\r
+      return EFI_NOT_READY;\r
     }\r
+  }\r
+    \r
+  //\r
+  // Prepare password string in HII database\r
+  //\r
+  if (PasswordString != NULL) {\r
+    IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);\r
+  } else {\r
+    IfrTypeValue.string = 0;\r
+  }\r
 \r
-    //\r
-    // Now Edit Buffer is filled with default values(lower priority) and current\r
-    // settings(higher priority), sychronize it to shadow Buffer\r
-    //\r
-    if (!EFI_ERROR (Status)) {\r
-      SynchronizeStorage (Storage);\r
-    }\r
+  //\r
+  // Send password to Configuration Driver for validation\r
+  //\r
+  Status = ConfigAccess->Callback (\r
+                           ConfigAccess,\r
+                           EFI_BROWSER_ACTION_CHANGING,\r
+                           Question->QuestionId,\r
+                           Question->HiiValue.Type,\r
+                           &IfrTypeValue,\r
+                           &ActionRequest\r
+                           );\r
 \r
-    Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+  //\r
+  // Remove password string from HII database\r
+  //\r
+  if (PasswordString != NULL) {\r
+    DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
-\r
 /**\r
-  Fetch the Ifr binary data of a FormSet.\r
+  Find the registered HotKey based on KeyData.\r
+  \r
+  @param[in] KeyData     A pointer to a buffer that describes the keystroke\r
+                         information for the hot key.\r
 \r
-  @param  Handle                 PackageList Handle\r
-  @param  FormSetGuid            On input, GUID or class GUID of a formset. If not\r
-                                 specified (NULL or zero GUID), take the first\r
-                                 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
-                                 found in package list.\r
-                                 On output, GUID of the formset found(if not NULL).\r
-  @param  BinaryLength           The length of the FormSet IFR binary.\r
-  @param  BinaryData             The buffer designed to receive the FormSet.\r
+  @return The registered HotKey context. If no found, NULL will return.\r
+**/\r
+BROWSER_HOT_KEY *\r
+GetHotKeyFromRegisterList (\r
+  IN EFI_INPUT_KEY *KeyData\r
+  )\r
+{\r
+  LIST_ENTRY       *Link;\r
+  BROWSER_HOT_KEY  *HotKey;\r
 \r
-  @retval EFI_SUCCESS            Buffer filled with the requested FormSet.\r
-                                 BufferLength was updated.\r
-  @retval EFI_INVALID_PARAMETER  The handle is unknown.\r
-  @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot\r
-                                 be found with the requested FormId.\r
+  Link = GetFirstNode (&gBrowserHotKeyList);\r
+  while (!IsNull (&gBrowserHotKeyList, Link)) {\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+    if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {\r
+      return HotKey;\r
+    }\r
+    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+  }\r
+  \r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Configure what scope the hot key will impact.\r
+  All hot keys have the same scope. The mixed hot keys with the different level are not supported.\r
+  If no scope is set, the default scope will be FormSet level.\r
+  After all registered hot keys are removed, previous Scope can reset to another level.\r
+  \r
+  @param[in] Scope               Scope level to be set. \r
+  \r
+  @retval EFI_SUCCESS            Scope is set correctly.\r
+  @retval EFI_INVALID_PARAMETER  Scope is not the valid value specified in BROWSER_SETTING_SCOPE. \r
+  @retval EFI_UNSPPORTED         Scope level is different from current one that the registered hot keys have.\r
 \r
 **/\r
 EFI_STATUS\r
-GetIfrBinaryData (\r
-  IN  EFI_HII_HANDLE   Handle,\r
-  IN OUT EFI_GUID      *FormSetGuid,\r
-  OUT UINTN            *BinaryLength,\r
-  OUT UINT8            **BinaryData\r
+EFIAPI\r
+SetScope (\r
+  IN BROWSER_SETTING_SCOPE Scope\r
   )\r
 {\r
-  EFI_STATUS                   Status;\r
-  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
-  UINTN                        BufferSize;\r
-  UINT8                        *Package;\r
-  UINT8                        *OpCodeData;\r
-  UINT32                       Offset;\r
-  UINT32                       Offset2;\r
-  UINT32                       PackageListLength;\r
-  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
-  UINT8                        Index;\r
-  UINT8                        NumberOfClassGuid;\r
-  BOOLEAN                      ClassGuidMatch;\r
-  EFI_GUID                     *ClassGuid;\r
-  EFI_GUID                     *ComparingGuid;\r
+  if (Scope >= MaxLevel) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
-  OpCodeData = NULL;\r
-  Package = NULL;\r
-  ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
+  //\r
+  // When no hot key registered in system or on the first setting,\r
+  // Scope can be set.\r
+  //\r
+  if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {\r
+    gBrowserSettingScope  = Scope;\r
+    mBrowserScopeFirstSet = FALSE;\r
+  } else if (Scope != gBrowserSettingScope) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Register the hot key with its browser action, or unregistered the hot key.\r
+  Only support hot key that is not printable character (control key, function key, etc.).\r
+  If the action value is zero, the hot key will be unregistered if it has been registered.\r
+  If the same hot key has been registered, the new action and help string will override the previous ones.\r
+  \r
+  @param[in] KeyData     A pointer to a buffer that describes the keystroke\r
+                         information for the hot key. Its type is EFI_INPUT_KEY to \r
+                         be supported by all ConsoleIn devices.\r
+  @param[in] Action      Action value that describes what action will be trigged when the hot key is pressed. \r
+  @param[in] DefaultId   Specifies the type of defaults to retrieve, which is only for DEFAULT action.\r
+  @param[in] HelpString  Help string that describes the hot key information.\r
+                         Its value may be NULL for the unregistered hot key.\r
+  \r
+  @retval EFI_SUCCESS            Hot key is registered or unregistered.\r
+  @retval EFI_INVALID_PARAMETER  KeyData is NULL or HelpString is NULL on register.\r
+  @retval EFI_NOT_FOUND          KeyData is not found to be unregistered.\r
+  @retval EFI_UNSUPPORTED        Key represents a printable character. It is conflicted with Browser.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterHotKey (\r
+  IN EFI_INPUT_KEY *KeyData,\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId,\r
+  IN EFI_STRING    HelpString OPTIONAL\r
+  )\r
+{\r
+  BROWSER_HOT_KEY  *HotKey;\r
 \r
   //\r
-  // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list\r
+  // Check input parameters.\r
   //\r
-  if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) {\r
-    ComparingGuid = &gEfiHiiPlatformSetupFormsetGuid;\r
-  } else {\r
-    ComparingGuid = FormSetGuid;\r
+  if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || \r
+     (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
-  // Get HII PackageList\r
+  // Check whether the input KeyData is in BrowserHotKeyList.\r
   //\r
-  BufferSize = 0;\r
-  HiiPackageList = NULL;\r
-  Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
-  if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    HiiPackageList = AllocatePool (BufferSize);\r
-    ASSERT (HiiPackageList != NULL);\r
-\r
-    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+  HotKey = GetHotKeyFromRegisterList (KeyData);\r
+  \r
+  //\r
+  // Unregister HotKey\r
+  //\r
+  if (Action == BROWSER_ACTION_UNREGISTER) {\r
+    if (HotKey != NULL) {\r
+      //\r
+      // The registered HotKey is found.  \r
+      // Remove it from List, and free its resource.\r
+      //\r
+      RemoveEntryList (&HotKey->Link);\r
+      FreePool (HotKey->KeyData);\r
+      FreePool (HotKey->HelpString);\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      //\r
+      // The registered HotKey is not found. \r
+      //\r
+      return EFI_NOT_FOUND;\r
+    }\r
   }\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  \r
+  //\r
+  // Register HotKey into List.\r
+  //\r
+  if (HotKey == NULL) {\r
+    //\r
+    // Create new Key, and add it into List.\r
+    //\r
+    HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));\r
+    ASSERT (HotKey != NULL);\r
+    HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;\r
+    HotKey->KeyData   = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);\r
+    InsertTailList (&gBrowserHotKeyList, &HotKey->Link);\r
   }\r
-  ASSERT (HiiPackageList != NULL);\r
 \r
   //\r
-  // Get Form package from this HII package List\r
+  // Fill HotKey information.\r
   //\r
-  Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
-  Offset2 = 0;\r
-  CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
-\r
-  ClassGuidMatch = FALSE;\r
-  while (Offset < PackageListLength) {\r
-    Package = ((UINT8 *) HiiPackageList) + Offset;\r
-    CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+  HotKey->Action     = Action;\r
+  HotKey->DefaultId  = DefaultId;\r
+  if (HotKey->HelpString != NULL) {\r
+    FreePool (HotKey->HelpString);\r
+  }\r
+  HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);\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
+  return EFI_SUCCESS;\r
+}\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
-            break;\r
-          }\r
+/**\r
+  Register Exit handler function. \r
+  When more than one handler function is registered, the latter one will override the previous one. \r
+  When NULL handler is specified, the previous Exit handler will be unregistered. \r
+  \r
+  @param[in] Handler      Pointer to handler function. \r
 \r
-          //\r
-          // Try to compare against formset class GUID\r
-          //\r
-          NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);\r
-          ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));\r
-          for (Index = 0; Index < NumberOfClassGuid; Index++) {\r
-            if (CompareGuid (ComparingGuid, ClassGuid + Index)) {\r
-              ClassGuidMatch = TRUE;\r
-              break;\r
-            }\r
-          }\r
-          if (ClassGuidMatch) {\r
-            break;\r
-          }\r
-        }\r
+**/\r
+VOID\r
+EFIAPI\r
+RegiserExitHandler (\r
+  IN EXIT_HANDLER Handler\r
+  )\r
+{\r
+  ExitHandlerFunction = Handler;\r
+  return;\r
+}\r
 \r
-        Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
-      }\r
+/**\r
+  Check whether the browser data has been modified.\r
 \r
-      if (Offset2 < PackageHeader.Length) {\r
-        //\r
-        // Target formset found\r
-        //\r
-        break;\r
-      }\r
-    }\r
+  @retval TRUE        Browser data is modified.\r
+  @retval FALSE       No browser data is modified.\r
 \r
-    Offset += PackageHeader.Length;\r
-  }\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsBrowserDataModified (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
 \r
-  if (Offset >= PackageListLength) {\r
-    //\r
-    // Form package not found in this Package List\r
-    //\r
-    FreePool (HiiPackageList);\r
-    return EFI_NOT_FOUND;\r
+  if (gCurrentSelection == NULL) {\r
+    return FALSE;\r
   }\r
 \r
-  if (ClassGuidMatch && (FormSetGuid != NULL)) {\r
-    //\r
-    // Return the FormSet GUID\r
-    //\r
-    CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
-  }\r
+  switch (gBrowserSettingScope) {\r
+    case FormLevel:\r
+      return IsNvUpdateRequiredForForm (gCurrentSelection->Form);\r
 \r
-  //\r
-  // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes\r
-  // in this FormSet; So, here just simply copy the data from start of a FormSet to the end\r
-  // of the Form Package.\r
-  //\r
-  *BinaryLength = PackageHeader.Length - Offset2;\r
-  *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);\r
+    case FormSetLevel:\r
+      return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);\r
 \r
-  FreePool (HiiPackageList);\r
+    case SystemLevel:\r
+      Link = GetFirstNode (&gBrowserFormSetList);\r
+      while (!IsNull (&gBrowserFormSetList, Link)) {\r
+        FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+        if (IsNvUpdateRequiredForFormSet (FormSet)) {\r
+          return TRUE;\r
+        }\r
+        Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      }\r
+      return FALSE;\r
 \r
-  if (*BinaryData == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    default:\r
+      return FALSE;\r
   }\r
-\r
-  return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
-  Initialize the internal data structure of a FormSet.\r
+  Execute the action requested by the Action parameter.\r
 \r
-  @param  Handle                 PackageList Handle\r
-  @param  FormSetGuid            On input, GUID or class GUID of a formset. If not\r
-                                 specified (NULL or zero GUID), take the first\r
-                                 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID\r
-                                 found in package list.\r
-                                 On output, GUID of the formset found(if not NULL).\r
-  @param  FormSet                FormSet data structure.\r
+  @param[in] Action     Execute the request action.\r
+  @param[in] DefaultId  The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-  @retval EFI_NOT_FOUND          The specified FormSet could not be found.\r
+  @retval EFI_SUCCESS              Execute the request action succss.\r
+  @retval EFI_INVALID_PARAMETER    The input action value is invalid.\r
 \r
 **/\r
-EFI_STATUS\r
-InitializeFormSet (\r
-  IN  EFI_HII_HANDLE                   Handle,\r
-  IN OUT EFI_GUID                      *FormSetGuid,\r
-  OUT FORM_BROWSER_FORMSET             *FormSet\r
+EFI_STATUS \r
+EFIAPI\r
+ExecuteAction (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
   )\r
 {\r
-  EFI_STATUS                Status;\r
-  EFI_HANDLE                DriverHandle;\r
-  UINT16                    Index;\r
+  EFI_STATUS Status;\r
 \r
-  Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  if (gCurrentSelection == NULL) {\r
+    return EFI_NOT_READY;\r
   }\r
 \r
-  FormSet->HiiHandle = Handle;\r
-  CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));\r
+  Status = EFI_SUCCESS;\r
 \r
   //\r
-  // Retrieve ConfigAccess Protocol associated with this HiiPackageList\r
+  // Executet the discard action.\r
   //\r
-  Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-  FormSet->DriverHandle = DriverHandle;\r
-  Status = gBS->HandleProtocol (\r
-                  DriverHandle,\r
-                  &gEfiHiiConfigAccessProtocolGuid,\r
-                  (VOID **) &FormSet->ConfigAccess\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    //\r
-    // Configuration Driver don't attach ConfigAccess protocol to its HII package\r
-    // list, then there will be no configuration action required\r
-    //\r
-    FormSet->ConfigAccess = NULL;\r
+  if ((Action & BROWSER_ACTION_DISCARD) != 0) {\r
+    Status = DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   //\r
-  // Parse the IFR binary OpCodes\r
+  // Executet the difault action.\r
   //\r
-  Status = ParseOpCodes (FormSet);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  if ((Action & BROWSER_ACTION_DEFAULT) != 0) {\r
+    Status = ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
-  gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;\r
-  if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {\r
-    gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;\r
-    gFrontPageHandle = FormSet->HiiHandle;\r
+  //\r
+  // Executet the submit action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_SUBMIT) != 0) {\r
+    Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   //\r
-  // Match GUID to find out the function key setting. If match fail, use the default setting.\r
+  // Executet the reset action.\r
   //\r
-  for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {\r
-    if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {\r
-      //\r
-      // Update the function key setting.\r
-      //\r
-      gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;\r
-      //\r
-      // Function key prompt can not be displayed if the function key has been disabled.\r
-      //\r
-      if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) {\r
-        gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
-      }\r
+  if ((Action & BROWSER_ACTION_RESET) != 0) {\r
+    gResetRequired = TRUE;\r
+  }\r
 \r
-      if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) {\r
-        gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
+  //\r
+  // Executet the exit action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_EXIT) != 0) {\r
+    DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (gBrowserSettingScope == SystemLevel) {\r
+      if (ExitHandlerFunction != NULL) {\r
+        ExitHandlerFunction ();\r
       }\r
     }\r
+\r
+    gExitRequired = TRUE;\r
   }\r
 \r
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Save globals used by previous call to SendForm(). SendForm() may be called from \r
-  HiiConfigAccess.Callback(), this will cause SendForm() be reentried.\r
-  So, save globals of previous call to SendForm() and restore them upon exit.\r
+  Create reminder to let user to choose save or discard the changed browser data.\r
+  Caller can use it to actively check the changed browser data.\r
+\r
+  @retval BROWSER_NO_CHANGES       No browser data is changed.\r
+  @retval BROWSER_SAVE_CHANGES     The changed browser data is saved.\r
+  @retval BROWSER_DISCARD_CHANGES  The changed browser data is discard.\r
 \r
 **/\r
-VOID\r
-SaveBrowserContext (\r
+UINT32\r
+EFIAPI\r
+SaveReminder (\r
   VOID\r
   )\r
 {\r
-  BROWSER_CONTEXT  *Context;\r
-\r
-  gBrowserContextCount++;\r
-  if (gBrowserContextCount == 1) {\r
-    //\r
-    // This is not reentry of SendForm(), no context to save\r
-    //\r
-    return;\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
+  BOOLEAN                 IsDataChanged;\r
+  UINT32                  DataSavedAction;\r
+\r
+  DataSavedAction  = BROWSER_NO_CHANGES;\r
+  IsDataChanged    = FALSE;\r
+  Link = GetFirstNode (&gBrowserFormSetList);\r
+  while (!IsNull (&gBrowserFormSetList, Link)) {\r
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+    Link = GetNextNode (&gBrowserFormSetList, Link);\r
+    if (!ValidateFormSet(FormSet)) {\r
+      continue;\r
+    }\r
+    if (IsNvUpdateRequiredForFormSet (FormSet)) {\r
+      IsDataChanged = TRUE;\r
+      break;\r
+    }\r
   }\r
-\r
-  Context = AllocatePool (sizeof (BROWSER_CONTEXT));\r
-  ASSERT (Context != NULL);\r
-\r
-  Context->Signature = BROWSER_CONTEXT_SIGNATURE;\r
-\r
-  //\r
-  // Save FormBrowser context\r
-  //\r
-  Context->BannerData           = gBannerData;\r
-  Context->ClassOfVfr           = gClassOfVfr;\r
-  Context->FunctionKeySetting   = gFunctionKeySetting;\r
-  Context->ResetRequired        = gResetRequired;\r
-  Context->NvUpdateRequired     = gNvUpdateRequired;\r
-  Context->Direction            = gDirection;\r
-  Context->FunctionNineString   = gFunctionNineString;\r
-  Context->FunctionTenString    = gFunctionTenString;\r
-  Context->EnterString          = gEnterString;\r
-  Context->EnterCommitString    = gEnterCommitString;\r
-  Context->EnterEscapeString    = gEnterEscapeString;\r
-  Context->EscapeString         = gEscapeString;\r
-  Context->SaveFailed           = gSaveFailed;\r
-  Context->MoveHighlight        = gMoveHighlight;\r
-  Context->MakeSelection        = gMakeSelection;\r
-  Context->DecNumericInput      = gDecNumericInput;\r
-  Context->HexNumericInput      = gHexNumericInput;\r
-  Context->ToggleCheckBox       = gToggleCheckBox;\r
-  Context->PromptForData        = gPromptForData;\r
-  Context->PromptForPassword    = gPromptForPassword;\r
-  Context->PromptForNewPassword = gPromptForNewPassword;\r
-  Context->ConfirmPassword      = gConfirmPassword;\r
-  Context->ConfirmError         = gConfirmError;\r
-  Context->PassowordInvalid     = gPassowordInvalid;\r
-  Context->PressEnter           = gPressEnter;\r
-  Context->EmptyString          = gEmptyString;\r
-  Context->AreYouSure           = gAreYouSure;\r
-  Context->YesResponse          = gYesResponse;\r
-  Context->NoResponse           = gNoResponse;\r
-  Context->MiniString           = gMiniString;\r
-  Context->PlusString           = gPlusString;\r
-  Context->MinusString          = gMinusString;\r
-  Context->AdjustNumber         = gAdjustNumber;\r
-  Context->SaveChanges          = gSaveChanges;\r
-  Context->OptionMismatch       = gOptionMismatch;\r
-  Context->FormSuppress         = gFormSuppress;\r
-  Context->PromptBlockWidth     = gPromptBlockWidth;\r
-  Context->OptionBlockWidth     = gOptionBlockWidth;\r
-  Context->HelpBlockWidth       = gHelpBlockWidth;\r
-  Context->OldFormSet           = gOldFormSet;\r
-  Context->MenuRefreshHead      = gMenuRefreshHead;\r
-\r
-  CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));\r
-  CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));\r
-\r
+  \r
   //\r
-  // Insert to FormBrowser context list\r
+  // No data is changed. No save is required. \r
   //\r
-  InsertHeadList (&gBrowserContextList, &Context->Link);\r
-}\r
-\r
-\r
-/**\r
-  Restore globals used by previous call to SendForm().\r
-\r
-**/\r
-VOID\r
-RestoreBrowserContext (\r
-  VOID\r
-  )\r
-{\r
-  LIST_ENTRY       *Link;\r
-  BROWSER_CONTEXT  *Context;\r
-\r
-  ASSERT (gBrowserContextCount != 0);\r
-  gBrowserContextCount--;\r
-  if (gBrowserContextCount == 0) {\r
-    //\r
-    // This is not reentry of SendForm(), no context to restore\r
-    //\r
-    return;\r
+  if (!IsDataChanged) {\r
+    return DataSavedAction;\r
   }\r
-\r
-  ASSERT (!IsListEmpty (&gBrowserContextList));\r
-\r
-  Link = GetFirstNode (&gBrowserContextList);\r
-  Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
-\r
+  \r
   //\r
-  // Restore FormBrowser context\r
+  // If data is changed, prompt user to save or discard it. \r
   //\r
-  gBannerData           = Context->BannerData;\r
-  gClassOfVfr           = Context->ClassOfVfr;\r
-  gFunctionKeySetting   = Context->FunctionKeySetting;\r
-  gResetRequired        = Context->ResetRequired;\r
-  gNvUpdateRequired     = Context->NvUpdateRequired;\r
-  gDirection            = Context->Direction;\r
-  gFunctionNineString   = Context->FunctionNineString;\r
-  gFunctionTenString    = Context->FunctionTenString;\r
-  gEnterString          = Context->EnterString;\r
-  gEnterCommitString    = Context->EnterCommitString;\r
-  gEnterEscapeString    = Context->EnterEscapeString;\r
-  gEscapeString         = Context->EscapeString;\r
-  gSaveFailed           = Context->SaveFailed;\r
-  gMoveHighlight        = Context->MoveHighlight;\r
-  gMakeSelection        = Context->MakeSelection;\r
-  gDecNumericInput      = Context->DecNumericInput;\r
-  gHexNumericInput      = Context->HexNumericInput;\r
-  gToggleCheckBox       = Context->ToggleCheckBox;\r
-  gPromptForData        = Context->PromptForData;\r
-  gPromptForPassword    = Context->PromptForPassword;\r
-  gPromptForNewPassword = Context->PromptForNewPassword;\r
-  gConfirmPassword      = Context->ConfirmPassword;\r
-  gConfirmError         = Context->ConfirmError;\r
-  gPassowordInvalid     = Context->PassowordInvalid;\r
-  gPressEnter           = Context->PressEnter;\r
-  gEmptyString          = Context->EmptyString;\r
-  gAreYouSure           = Context->AreYouSure;\r
-  gYesResponse          = Context->YesResponse;\r
-  gNoResponse           = Context->NoResponse;\r
-  gMiniString           = Context->MiniString;\r
-  gPlusString           = Context->PlusString;\r
-  gMinusString          = Context->MinusString;\r
-  gAdjustNumber         = Context->AdjustNumber;\r
-  gSaveChanges          = Context->SaveChanges;\r
-  gOptionMismatch       = Context->OptionMismatch;\r
-  gFormSuppress         = Context->FormSuppress;\r
-  gPromptBlockWidth     = Context->PromptBlockWidth;\r
-  gOptionBlockWidth     = Context->OptionBlockWidth;\r
-  gHelpBlockWidth       = Context->HelpBlockWidth;\r
-  gOldFormSet           = Context->OldFormSet;\r
-  gMenuRefreshHead      = Context->MenuRefreshHead;\r
-\r
-  CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));\r
-  CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));\r
+  do {\r
+    DataSavedAction = (UINT32) mFormDisplay->ConfirmDataChange();\r
+\r
+    if (DataSavedAction == BROWSER_SAVE_CHANGES) {\r
+      SubmitForm (NULL, NULL, SystemLevel);\r
+      break;\r
+    } else if (DataSavedAction == BROWSER_DISCARD_CHANGES) {\r
+      DiscardForm (NULL, NULL, SystemLevel);\r
+      break;\r
+    }\r
+  } while (1);\r
 \r
-  //\r
-  // Remove from FormBrowser context list\r
-  //\r
-  RemoveEntryList (&Context->Link);\r
-  gBS->FreePool (Context);\r
+  return DataSavedAction;\r
 }\r