]> 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 ff857750efdcd140e4389d60bfdfb5456f9bc246..c4dd18a04fd664e4320d71ffabad670625763088 100644 (file)
-/** @file
-Copyright (c) 2007 - 2008, Intel Corporation
-All rights reserved. This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
-  Setup.c
-
-Abstract:
-
-  Entry and initialization module for the browser.
-
-
-**/
-
-#include "Setup.h"
-#include "Ui.h"
-
-
-SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {
-  SETUP_DRIVER_SIGNATURE,
-  NULL,
-  {
-    SendForm,
-    BrowserCallback
-  },
-  {
-    UnicodeVSPrint
-  }
-};
-
-EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;
-EFI_HII_STRING_PROTOCOL           *mHiiString;
-EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;
-
-BANNER_DATA           *BannerData;
-EFI_HII_HANDLE        FrontPageHandle;
-UINTN                 gClassOfVfr;
-UINTN                 gFunctionKeySetting;
-BOOLEAN               gResetRequired;
-BOOLEAN               gNvUpdateRequired;
-EFI_HII_HANDLE        gHiiHandle;
-BOOLEAN               gFirstIn;
-UINT16                gDirection;
-EFI_SCREEN_DESCRIPTOR gScreenDimensions;
-BOOLEAN               gUpArrow;
-BOOLEAN               gDownArrow;
-
-//
-// Browser Global Strings
-//
-CHAR16            *gFunctionOneString;
-CHAR16            *gFunctionTwoString;
-CHAR16            *gFunctionNineString;
-CHAR16            *gFunctionTenString;
-CHAR16            *gEnterString;
-CHAR16            *gEnterCommitString;
-CHAR16            *gEscapeString;
-CHAR16            *gSaveFailed;
-CHAR16            *gMoveHighlight;
-CHAR16            *gMakeSelection;
-CHAR16            *gDecNumericInput;
-CHAR16            *gHexNumericInput;
-CHAR16            *gToggleCheckBox;
-CHAR16            *gPromptForData;
-CHAR16            *gPromptForPassword;
-CHAR16            *gPromptForNewPassword;
-CHAR16            *gConfirmPassword;
-CHAR16            *gConfirmError;
-CHAR16            *gPassowordInvalid;
-CHAR16            *gPressEnter;
-CHAR16            *gEmptyString;
-CHAR16            *gAreYouSure;
-CHAR16            *gYesResponse;
-CHAR16            *gNoResponse;
-CHAR16            *gMiniString;
-CHAR16            *gPlusString;
-CHAR16            *gMinusString;
-CHAR16            *gAdjustNumber;
-
-CHAR16            gPromptBlockWidth;
-CHAR16            gOptionBlockWidth;
-CHAR16            gHelpBlockWidth;
-
-EFI_GUID  gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
-EFI_GUID  gSetupBrowserGuid = {
-  0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}
-};
-
-FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {
-  //
-  // Boot Manager
-  //
-  {
-    {
-      0x847bc3fe,
-      0xb974,
-      0x446d,
-      {
-        0x94,
-        0x49,
-        0x5a,
-        0xd5,
-        0x41,
-        0x2e,
-        0x99,
-        0x3b
-      }
-    },
-    NONE_FUNCTION_KEY_SETTING
-  },
-  //
-  // Device Manager
-  //
-  {
-    {
-      0x3ebfa8e6,
-      0x511d,
-      0x4b5b,
-      {
-        0xa9,
-        0x5f,
-        0xfb,
-        0x38,
-        0x26,
-        0xf,
-        0x1c,
-        0x27
-      }
-    },
-    NONE_FUNCTION_KEY_SETTING
-  },
-  //
-  // BMM FormSet.
-  //
-  {
-    {
-      0x642237c7,
-      0x35d4,
-      0x472d,
-      {
-        0x83,
-        0x65,
-        0x12,
-        0xe0,
-        0xcc,
-        0xf2,
-        0x7a,
-        0x22
-      }
-    },
-    NONE_FUNCTION_KEY_SETTING
-  },
-  //
-  // BMM File Explorer FormSet.
-  //
-  {
-    {
-      0x1f2d63e1,
-      0xfebd,
-      0x4dc7,
-      {
-        0x9c,
-        0xc5,
-        0xba,
-        0x2b,
-        0x1c,
-        0xef,
-        0x9c,
-        0x5b
-      }
-    },
-    NONE_FUNCTION_KEY_SETTING
-  },
-};
-
-EFI_STATUS
-EFIAPI
-SendForm (
-  IN  CONST EFI_FORM_BROWSER2_PROTOCOL *This,
-  IN  EFI_HII_HANDLE                   *Handles,
-  IN  UINTN                            HandleCount,
-  IN  EFI_GUID                         *FormSetGuid, OPTIONAL
-  IN  UINT16                           FormId, OPTIONAL
-  IN  CONST EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL
-  OUT EFI_BROWSER_ACTION_REQUEST       *ActionRequest  OPTIONAL
-  )
-/*++
-
-Routine Description:
-  This is the routine which an external caller uses to direct the browser
-  where to obtain it's information.
-
-Arguments:
-  This            - The Form Browser protocol instanse.
-  Handles         - A pointer to an array of Handles.  If HandleCount > 1 we
-                    display a list of the formsets for the handles specified.
-  HandleCount     - The number of Handles specified in Handle.
-  FormSetGuid     - This field points to the EFI_GUID which must match the Guid
-                    field in the EFI_IFR_FORM_SET op-code for the specified
-                    forms-based package. If FormSetGuid is NULL, then this
-                    function will display the first found forms package.
-  FormId          - This field specifies which EFI_IFR_FORM to render as the first
-                    displayable page. If this field has a value of 0x0000, then
-                    the forms browser will render the specified forms in their encoded order.
-  ScreenDimenions - This allows the browser to be called so that it occupies a
-                    portion of the physical screen instead of dynamically determining the screen dimensions.
-  ActionRequest   - Points to the action recommended by the form.
-
-Returns:
-  EFI_SUCCESS           -  The function completed successfully.
-  EFI_INVALID_PARAMETER -  One of the parameters has an invalid value.
-  EFI_NOT_FOUND         -  No valid forms could be found to display.
-
---*/
-{
-  EFI_STATUS            Status;
-  UI_MENU_SELECTION     *Selection;
-  UINTN                 Index;
-  FORM_BROWSER_FORMSET  *FormSet;
-
-  Status = EFI_SUCCESS;
-  ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
-
-  //
-  // Seed the dimensions in the global
-  //
-  gST->ConOut->QueryMode (
-                 gST->ConOut,
-                 gST->ConOut->Mode->Mode,
-                 &gScreenDimensions.RightColumn,
-                 &gScreenDimensions.BottomRow
-                 );
-
-  if (ScreenDimensions != NULL) {
-    //
-    // Check local dimension vs. global dimension.
-    //
-    if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||
-        (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)
-        ) {
-      return EFI_INVALID_PARAMETER;
-    } else {
-      //
-      // Local dimension validation.
-      //
-      if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&
-          (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&
-          ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&
-          (
-            (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
-            SCROLL_ARROW_HEIGHT *
-            2 +
-            FRONT_PAGE_HEADER_HEIGHT +
-            FOOTER_HEIGHT +
-            1
-          )
-        ) {
-        CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
-      } else {
-        return EFI_INVALID_PARAMETER;
-      }
-    }
-  }
-
-  gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
-  gHelpBlockWidth   = gOptionBlockWidth;
-  gPromptBlockWidth = gOptionBlockWidth;
-
-  //
-  // Initialize the strings for the browser, upon exit of the browser, the strings will be freed
-  //
-  InitializeBrowserStrings ();
-
-  gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING;
-  gClassOfVfr         = EFI_SETUP_APPLICATION_SUBCLASS;
-
-  //
-  // Ensure we are in Text mode
-  //
-  if (gFirstIn) {
-    gFirstIn = FALSE;
-    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-    DisableQuietBoot ();
-  }
-
-  for (Index = 0; Index < HandleCount; Index++) {
-    Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
-    ASSERT (Selection != NULL);
-
-    Selection->Handle = Handles[Index];
-    if (FormSetGuid != NULL) {
-      CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
-      Selection->FormId = FormId;
-    }
-
-    do {
-      FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
-      ASSERT (FormSet != NULL);
-
-      //
-      // Initialize internal data structures of FormSet
-      //
-      Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
-      if (EFI_ERROR (Status)) {
-        DestroyFormSet (FormSet);
-        break;
-      }
-      Selection->FormSet = FormSet;
-
-      //
-      // Initialize current settings of Questions in this FormSet
-      //
-      Status = InitializeCurrentSetting (FormSet);
-      if (EFI_ERROR (Status)) {
-        DestroyFormSet (FormSet);
-        break;
-      }
-
-      //
-      // Display this formset
-      //
-      gCurrentSelection = Selection;
-
-      Status = SetupBrowser (Selection);
-
-      gCurrentSelection = NULL;
-      DestroyFormSet (FormSet);
-
-      if (EFI_ERROR (Status)) {
-        break;
-      }
-
-    } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
-
-    gBS->FreePool (Selection);
-  }
-
-  if (ActionRequest != NULL) {
-    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
-    if (gResetRequired) {
-      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
-    }
-  }
-
-  FreeBrowserStrings ();
-
-  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-  gST->ConOut->ClearScreen (gST->ConOut);
-
-  return Status;
-}
-
-
-/**
-  This function is called by a callback handler to retrieve uncommitted state
-  data from the browser.
-
-  @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL
-                                 instance.
-  @param  ResultsDataSize        A pointer to the size of the buffer associated
-                                 with ResultsData.
-  @param  ResultsData            A string returned from an IFR browser or
-                                 equivalent. The results string will have no
-                                 routing information in them.
-  @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve
-                                 (if RetrieveData = TRUE) data from the uncommitted
-                                 browser state information or set (if RetrieveData
-                                 = FALSE) data in the uncommitted browser state
-                                 information.
-  @param  VariableGuid           An optional field to indicate the target variable
-                                 GUID name to use.
-  @param  VariableName           An optional field to indicate the target
-                                 human-readable variable name.
-
-  @retval EFI_SUCCESS            The results have been distributed or are awaiting
-                                 distribution.
-  @retval EFI_BUFFER_TOO_SMALL   The ResultsDataSize specified was too small to
-                                 contain the results data.
-
-**/
-EFI_STATUS
-EFIAPI
-BrowserCallback (
-  IN CONST EFI_FORM_BROWSER2_PROTOCOL  *This,
-  IN OUT UINTN                         *ResultsDataSize,
-  IN OUT EFI_STRING                    ResultsData,
-  IN BOOLEAN                           RetrieveData,
-  IN CONST EFI_GUID                    *VariableGuid, OPTIONAL
-  IN CONST CHAR16                      *VariableName  OPTIONAL
-  )
-{
-  EFI_STATUS            Status;
-  LIST_ENTRY            *Link;
-  FORMSET_STORAGE       *Storage;
-  FORM_BROWSER_FORMSET  *FormSet;
-  BOOLEAN               Found;
-  CHAR16                *ConfigResp;
-  CHAR16                *StrPtr;
-  UINTN                 BufferSize;
-  UINTN                 TmpSize;
-
-  if (ResultsDataSize == NULL || ResultsData == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (gCurrentSelection == NULL) {
-    return EFI_NOT_READY;
-  }
-
-  Storage = NULL;
-  ConfigResp = NULL;
-  FormSet = gCurrentSelection->FormSet;
-
-  //
-  // Find target storage
-  //
-  Link = GetFirstNode (&FormSet->StorageListHead);
-  if (IsNull (&FormSet->StorageListHead, Link)) {
-    return EFI_UNSUPPORTED;
-  }
-
-  if (VariableGuid != NULL) {
-    //
-    // Try to find target storage
-    //
-    Found = FALSE;
-    while (!IsNull (&FormSet->StorageListHead, Link)) {
-      Storage = FORMSET_STORAGE_FROM_LINK (Link);
-      Link = GetNextNode (&FormSet->StorageListHead, Link);
-
-      if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
-        if (Storage->Type == EFI_HII_VARSTORE_BUFFER) {
-          //
-          // Buffer storage require both GUID and Name
-          //
-          if (VariableName == NULL) {
-            return EFI_NOT_FOUND;
-          }
-
-          if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
-            continue;
-          }
-        }
-        Found = TRUE;
-        break;
-      }
-    }
-
-    if (!Found) {
-      return EFI_NOT_FOUND;
-    }
-  } else {
-    //
-    // GUID/Name is not specified, take the first storage in FormSet
-    //
-    Storage = FORMSET_STORAGE_FROM_LINK (Link);
-  }
-
-  if (RetrieveData) {
-    //
-    // Skip if there is no RequestElement
-    //
-    if (Storage->ElementCount == 0) {
-      return EFI_SUCCESS;
-    }
-
-    //
-    // Generate <ConfigResp>
-    //
-    Status = StorageToConfigResp (Storage, &ConfigResp);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    //
-    // Skip <ConfigHdr> and '&' to point to <ConfigBody>
-    //
-    StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;
-
-    BufferSize = StrSize (StrPtr);
-    if (*ResultsDataSize < BufferSize) {
-      *ResultsDataSize = BufferSize;
-
-      gBS->FreePool (ConfigResp);
-      return EFI_BUFFER_TOO_SMALL;
-    }
-
-    *ResultsDataSize = BufferSize;
-    CopyMem (ResultsData, StrPtr, BufferSize);
-
-    gBS->FreePool (ConfigResp);
-  } else {
-    //
-    // Prepare <ConfigResp>
-    //
-    TmpSize = StrLen (ResultsData);
-    BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);
-    ConfigResp = AllocateZeroPool (BufferSize);
-    ASSERT (ConfigResp != NULL);
-
-    StrCpy (ConfigResp, Storage->ConfigHdr);
-    StrCat (ConfigResp, L"&");
-    StrCat (ConfigResp, ResultsData);
-
-    //
-    // Update Browser uncommited data
-    //
-    Status = ConfigRespToStorage (Storage, ConfigResp);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Initialize Setup
-
-  @param  entry                  EFI_IMAGE_ENTRY_POINT)
-
-  @retval EFI_SUCCESS            Setup loaded.
-  @retval other                  Setup Error
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeSetup (
-  IN EFI_HANDLE           ImageHandle,
-  IN EFI_SYSTEM_TABLE     *SystemTable
-  )
-{
-  EFI_STATUS                  Status;
-  EFI_HANDLE                  HiiDriverHandle;
-  EFI_HII_PACKAGE_LIST_HEADER *PackageList;
-
-  //
-  // Locate required Hii relative protocols
-  //
-  Status = gBS->LocateProtocol (
-                  &gEfiHiiDatabaseProtocolGuid,
-                  NULL,
-                  (VOID **) &mHiiDatabase
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  Status = gBS->LocateProtocol (
-                  &gEfiHiiStringProtocolGuid,
-                  NULL,
-                  (VOID **) &mHiiString
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  Status = gBS->LocateProtocol (
-                  &gEfiHiiConfigRoutingProtocolGuid,
-                  NULL,
-                  (VOID **) &mHiiConfigRouting
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  //
-  // Publish our HII data
-  //
-  Status = HiiLibCreateHiiDriverHandle (&HiiDriverHandle);
-  ASSERT_EFI_ERROR (Status);
-
-  PackageList = HiiLibPreparePackageList (1, &gSetupBrowserGuid, SetupBrowserStrings);
-  ASSERT (PackageList != NULL);
-  Status = mHiiDatabase->NewPackageList (
-                           mHiiDatabase,
-                           PackageList,
-                           HiiDriverHandle,
-                           &gHiiHandle
-                           );
-  ASSERT_EFI_ERROR (Status);
-
-  //
-  // Initialize Driver private data
-  //
-  gFirstIn = TRUE;
-  BannerData = AllocateZeroPool (sizeof (BANNER_DATA));
-  ASSERT (BannerData != NULL);
-
-  //
-  // Install FormBrowser2 protocol
-  //
-  mPrivateData.Handle = NULL;
-  Status = gBS->InstallProtocolInterface (
-                  &mPrivateData.Handle,
-                  &gEfiFormBrowser2ProtocolGuid,
-                  EFI_NATIVE_INTERFACE,
-                  &mPrivateData.FormBrowser2
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  //
-  // Install Print protocol
-  //
-  Status = gBS->InstallProtocolInterface (
-                  &mPrivateData.Handle,
-                  &gEfiPrintProtocolGuid,
-                  EFI_NATIVE_INTERFACE,
-                  &mPrivateData.Print
-                  );
-
-  return Status;
-}
-
-
-/**
-  Create a new string in HII Package List.
-
-  @param  String                 The String to be added
-  @param  HiiHandle              The package list in the HII database to insert the
-                                 specified string.
-
-  @return The output string.
-
-**/
-EFI_STRING_ID
-NewString (
-  IN  CHAR16                   *String,
-  IN  EFI_HII_HANDLE           HiiHandle
-  )
-{
-  EFI_STRING_ID  StringId;
-  EFI_STATUS     Status;
-
-  StringId = 0;
-  Status = HiiLibNewString (HiiHandle, &StringId, String);
-  ASSERT_EFI_ERROR (Status);
-
-  return StringId;
-}
-
-
-/**
-  Delete a string from HII Package List.
-
-  @param  StringId               Id of the string in HII database.
-  @param  HiiHandle              The HII package list handle.
-
-  @retval EFI_SUCCESS            The string was deleted successfully.
-
-**/
-EFI_STATUS
-DeleteString (
-  IN  EFI_STRING_ID            StringId,
-  IN  EFI_HII_HANDLE           HiiHandle
-  )
-{
-  CHAR16  NullChar;
-
-  NullChar = CHAR_NULL;
-  return HiiLibSetString (HiiHandle, StringId, &NullChar);
-}
-
-
-/**
-  Get the string based on the StringId and HII Package List Handle.
-
-  @param  Token                  The String's ID.
-  @param  HiiHandle              The package list in the HII database to search for
-                                 the specified string.
-
-  @return The output string.
-
-**/
-CHAR16 *
-GetToken (
-  IN  EFI_STRING_ID                Token,
-  IN  EFI_HII_HANDLE               HiiHandle
-  )
-{
-  EFI_STATUS  Status;
-  CHAR16      *String;
-  UINTN       BufferLength;
-
-  //
-  // Set default string size assumption at no more than 256 bytes
-  //
-  BufferLength = 0x100;
-  String = AllocateZeroPool (BufferLength);
-  ASSERT (String != NULL);
-
-  Status = HiiLibGetString (HiiHandle, Token, String, &BufferLength);
-
-  if (Status == EFI_BUFFER_TOO_SMALL) {
-    gBS->FreePool (String);
-    String = AllocateZeroPool (BufferLength);
-    ASSERT (String != NULL);
-
-    Status = HiiLibGetString (HiiHandle, Token, String, &BufferLength);
-  }
-  ASSERT_EFI_ERROR (Status);
-
-  return String;
-}
-
-
-/**
-  Allocate new memory and then copy the Unicode string Source to Destination.
-
-  @param  Dest                   Location to copy string
-  @param  Src                    String to copy
-
-  @return NONE
-
-**/
-VOID
-NewStringCpy (
-  IN OUT CHAR16       **Dest,
-  IN CHAR16           *Src
-  )
-{
-  SafeFreePool (*Dest);
-  *Dest = AllocateCopyPool (StrSize (Src), Src);
-  ASSERT (*Dest != NULL);
-}
-
-
-/**
-  Allocate new memory and concatinate Source on the end of Destination.
-
-  @param  Dest                   String to added to the end of.
-  @param  Src                    String to concatinate.
-
-  @return NONE
-
-**/
-VOID
-NewStringCat (
-  IN OUT CHAR16       **Dest,
-  IN CHAR16           *Src
-  )
-{
-  CHAR16  *NewString;
-  UINTN   TmpSize;
-
-  if (*Dest == NULL) {
-    NewStringCpy (Dest, Src);
-    return;
-  }
-
-  TmpSize = StrSize (*Dest);
-  NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);
-  ASSERT (NewString != NULL);
-
-  StrCpy (NewString, *Dest);
-  StrCat (NewString, Src);
-
-  gBS->FreePool (*Dest);
-  *Dest = NewString;
-}
-
-
-/**
-  Synchronize Storage's Edit copy to Shadow copy.
-
-  @param  Storage                The Storage to be synchronized.
-
-  @return NONE
-
-**/
-VOID
-SynchronizeStorage (
-  IN FORMSET_STORAGE         *Storage
-  )
-{
-  LIST_ENTRY              *Link;
-  NAME_VALUE_NODE         *Node;
-
-  switch (Storage->Type) {
-  case EFI_HII_VARSTORE_BUFFER:
-    CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);
-    break;
-
-  case EFI_HII_VARSTORE_NAME_VALUE:
-    Link = GetFirstNode (&Storage->NameValueListHead);
-    while (!IsNull (&Storage->NameValueListHead, Link)) {
-      Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
-      NewStringCpy (&Node->Value, Node->EditValue);
-
-      Link = GetNextNode (&Storage->NameValueListHead, Link);
-    }
-    break;
-
-  case EFI_HII_VARSTORE_EFI_VARIABLE:
-  default:
-    break;
-  }
-}
-
-
-/**
-  Get Value for given Name from a NameValue Storage.
-
-  @param  Storage                The NameValue Storage.
-  @param  Name                   The Name.
-  @param  Value                  The retured Value.
-
-  @retval EFI_SUCCESS            Value found for given Name.
-  @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
-
-**/
-EFI_STATUS
-GetValueByName (
-  IN FORMSET_STORAGE         *Storage,
-  IN CHAR16                  *Name,
-  IN OUT CHAR16              **Value
-  )
-{
-  LIST_ENTRY              *Link;
-  NAME_VALUE_NODE         *Node;
-
-  *Value = NULL;
-
-  Link = GetFirstNode (&Storage->NameValueListHead);
-  while (!IsNull (&Storage->NameValueListHead, Link)) {
-    Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
-    if (StrCmp (Name, Node->Name) == 0) {
-      NewStringCpy (Value, Node->EditValue);
-      return EFI_SUCCESS;
-    }
-
-    Link = GetNextNode (&Storage->NameValueListHead, Link);
-  }
-
-  return EFI_NOT_FOUND;
-}
-
-
-/**
-  Set Value of given Name in a NameValue Storage.
-
-  @param  Storage                The NameValue Storage.
-  @param  Name                   The Name.
-  @param  Value                  The Value to set.
-
-  @retval EFI_SUCCESS            Value found for given Name.
-  @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
-
-**/
-EFI_STATUS
-SetValueByName (
-  IN FORMSET_STORAGE         *Storage,
-  IN CHAR16                  *Name,
-  IN CHAR16                  *Value
-  )
-{
-  LIST_ENTRY              *Link;
-  NAME_VALUE_NODE         *Node;
-
-  Link = GetFirstNode (&Storage->NameValueListHead);
-  while (!IsNull (&Storage->NameValueListHead, Link)) {
-    Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
-    if (StrCmp (Name, Node->Name) == 0) {
-      SafeFreePool (Node->EditValue);
-      Node->EditValue = AllocateCopyPool (StrSize (Value), Value);
-      ASSERT (Node->EditValue != NULL);
-      return EFI_SUCCESS;
-    }
-
-    Link = GetNextNode (&Storage->NameValueListHead, Link);
-  }
-
-  return EFI_NOT_FOUND;
-}
-
-
-/**
-  Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
-
-  @param  Storage                The Storage to be conveted.
-  @param  ConfigResp             The returned <ConfigResp>.
-
-  @retval EFI_SUCCESS            Convert success.
-  @retval EFI_INVALID_PARAMETER  Incorrect storage type.
-
-**/
-EFI_STATUS
-StorageToConfigResp (
-  IN FORMSET_STORAGE         *Storage,
-  IN CHAR16                  **ConfigResp
-  )
-{
-  EFI_STATUS  Status;
-  EFI_STRING  Progress;
-  LIST_ENTRY              *Link;
-  NAME_VALUE_NODE         *Node;
-
-  Status = EFI_SUCCESS;
-
-  switch (Storage->Type) {
-  case EFI_HII_VARSTORE_BUFFER:
-    Status = mHiiConfigRouting->BlockToConfig (
-                                  mHiiConfigRouting,
-                                  Storage->ConfigRequest,
-                                  Storage->EditBuffer,
-                                  Storage->Size,
-                                  ConfigResp,
-                                  &Progress
-                                  );
-    break;
-
-  case EFI_HII_VARSTORE_NAME_VALUE:
-    *ConfigResp = NULL;
-    NewStringCat (ConfigResp, Storage->ConfigHdr);
-
-    Link = GetFirstNode (&Storage->NameValueListHead);
-    while (!IsNull (&Storage->NameValueListHead, Link)) {
-      Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
-      NewStringCat (ConfigResp, L"&");
-      NewStringCat (ConfigResp, Node->Name);
-      NewStringCat (ConfigResp, L"=");
-      NewStringCat (ConfigResp, Node->EditValue);
-
-      Link = GetNextNode (&Storage->NameValueListHead, Link);
-    }
-    break;
-
-  case EFI_HII_VARSTORE_EFI_VARIABLE:
-  default:
-    Status = EFI_INVALID_PARAMETER;
-    break;
-  }
-
-  return Status;
-}
-
-
-/**
-  Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
-
-  @param  Storage                The Storage to receive the settings.
-  @param  ConfigResp             The <ConfigResp> to be converted.
-
-  @retval EFI_SUCCESS            Convert success.
-  @retval EFI_INVALID_PARAMETER  Incorrect storage type.
-
-**/
-EFI_STATUS
-ConfigRespToStorage (
-  IN FORMSET_STORAGE         *Storage,
-  IN CHAR16                  *ConfigResp
-  )
-{
-  EFI_STATUS  Status;
-  EFI_STRING  Progress;
-  UINTN       BufferSize;
-  CHAR16      *StrPtr;
-  CHAR16      *Name;
-  CHAR16      *Value;
-
-  Status = EFI_SUCCESS;
-
-  switch (Storage->Type) {
-  case EFI_HII_VARSTORE_BUFFER:
-    BufferSize = Storage->Size;
-    Status = mHiiConfigRouting->ConfigToBlock (
-                                  mHiiConfigRouting,
-                                  ConfigResp,
-                                  Storage->EditBuffer,
-                                  &BufferSize,
-                                  &Progress
-                                  );
-    break;
-
-  case EFI_HII_VARSTORE_NAME_VALUE:
-    StrPtr = StrStr (ConfigResp, L"&");
-    while (StrPtr != NULL) {
-      //
-      // Skip '&'
-      //
-      StrPtr = StrPtr + 1;
-      Name = StrPtr;
-      StrPtr = StrStr (StrPtr, L"=");
-      if (StrPtr == NULL) {
-        break;
-      }
-      *StrPtr = 0;
-
-      //
-      // Skip '='
-      //
-      StrPtr = StrPtr + 1;
-      Value = StrPtr;
-      StrPtr = StrStr (StrPtr, L"&");
-      if (StrPtr != NULL) {
-        *StrPtr = 0;
-      }
-      SetValueByName (Storage, Name, Value);
-    }
-    break;
-
-  case EFI_HII_VARSTORE_EFI_VARIABLE:
-  default:
-    Status = EFI_INVALID_PARAMETER;
-    break;
-  }
-
-  return Status;
-}
-
-
-/**
-  Get Question's current Value.
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   Form data structure.
-  @param  Question               Question to be initialized.
-  @param  Cached                 TRUE:  get from Edit copy FALSE: get from original
-                                 Storage
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-GetQuestionValue (
-  IN FORM_BROWSER_FORMSET             *FormSet,
-  IN FORM_BROWSER_FORM                *Form,
-  IN OUT FORM_BROWSER_STATEMENT       *Question,
-  IN BOOLEAN                          Cached
-  )
-{
-  EFI_STATUS          Status;
-  BOOLEAN             Enabled;
-  BOOLEAN             Pending;
-  UINT8               *Dst;
-  UINTN               StorageWidth;
-  EFI_TIME            EfiTime;
-  FORMSET_STORAGE     *Storage;
-  EFI_IFR_TYPE_VALUE  *QuestionValue;
-  CHAR16              *ConfigRequest;
-  CHAR16              *Progress;
-  CHAR16              *Result;
-  CHAR16              *Value;
-  UINTN               Length;
-  BOOLEAN             IsBufferStorage;
-  BOOLEAN             IsString;
-
-  Status = EFI_SUCCESS;
-
-  //
-  // Statement don't have storage, skip them
-  //
-  if (Question->QuestionId == 0) {
-    return Status;
-  }
-
-  //
-  // Question value is provided by an Expression, evaluate it
-  //
-  if (Question->ValueExpression != NULL) {
-    Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
-    if (!EFI_ERROR (Status)) {
-      CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE));
-    }
-    return Status;
-  }
-
-  //
-  // Question value is provided by RTC
-  //
-  Storage = Question->Storage;
-  QuestionValue = &Question->HiiValue.Value;
-  if (Storage == NULL) {
-    //
-    // It's a Question without storage, or RTC date/time
-    //
-    if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
-      //
-      // Date and time define the same Flags bit
-      //
-      switch (Question->Flags & EFI_QF_DATE_STORAGE) {
-      case QF_DATE_STORAGE_TIME:
-        Status = gRT->GetTime (&EfiTime, NULL);
-        break;
-
-      case QF_DATE_STORAGE_WAKEUP:
-        Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
-        break;
-
-      case QF_DATE_STORAGE_NORMAL:
-      default:
-        //
-        // For date/time without storage
-        //
-        return EFI_SUCCESS;
-      }
-
-      if (EFI_ERROR (Status)) {
-        return Status;
-      }
-
-      if (Question->Operand == EFI_IFR_DATE_OP) {
-        QuestionValue->date.Year  = EfiTime.Year;
-        QuestionValue->date.Month = EfiTime.Month;
-        QuestionValue->date.Day   = EfiTime.Day;
-      } else {
-        QuestionValue->time.Hour   = EfiTime.Hour;
-        QuestionValue->time.Minute = EfiTime.Minute;
-        QuestionValue->time.Second = EfiTime.Second;
-      }
-    }
-
-    return EFI_SUCCESS;
-  }
-
-  //
-  // Question value is provided by EFI variable
-  //
-  StorageWidth = Question->StorageWidth;
-  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
-    if (Question->BufferValue != NULL) {
-      Dst = Question->BufferValue;
-    } else {
-      Dst = (UINT8 *) QuestionValue;
-    }
-
-    Status = gRT->GetVariable (
-                     Question->VariableName,
-                     &Storage->Guid,
-                     NULL,
-                     &StorageWidth,
-                     Dst
-                     );
-    //
-    // Always return success, even this EFI variable doesn't exist
-    //
-    return EFI_SUCCESS;
-  }
-
-  //
-  // Question Value is provided by Buffer Storage or NameValue Storage
-  //
-  if (Question->BufferValue != NULL) {
-    //
-    // This Question is password or orderedlist
-    //
-    Dst = Question->BufferValue;
-  } else {
-    //
-    // Other type of Questions
-    //
-    Dst = (UINT8 *) &Question->HiiValue.Value;
-  }
-
-  IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
-  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
-  if (Cached) {
-    if (IsBufferStorage) {
-      //
-      // Copy from storage Edit buffer
-      //
-      CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
-    } else {
-      Status = GetValueByName (Storage, Question->VariableName, &Value);
-      if (EFI_ERROR (Status)) {
-        return Status;
-      }
-
-      if (IsString) {
-        //
-        // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
-        //
-        Length = StorageWidth + sizeof (CHAR16);
-        Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value);
-      } else {
-        Status = HexStringToBuf (Dst, &StorageWidth, Value, NULL);
-      }
-
-      gBS->FreePool (Value);
-    }
-  } else {
-    //
-    // Request current settings from Configuration Driver
-    //
-    if (FormSet->ConfigAccess == NULL) {
-      return EFI_NOT_FOUND;
-    }
-
-    //
-    // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
-    //                   <ConfigHdr> + "&" + <VariableName>
-    //
-    if (IsBufferStorage) {
-      Length = StrLen (Storage->ConfigHdr);
-      Length += StrLen (Question->BlockName);
-    } else {
-      Length = StrLen (Storage->ConfigHdr);
-      Length += StrLen (Question->VariableName) + 1;
-    }
-    ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
-    ASSERT (ConfigRequest != NULL);
-
-    StrCpy (ConfigRequest, Storage->ConfigHdr);
-    if (IsBufferStorage) {
-      StrCat (ConfigRequest, Question->BlockName);
-    } else {
-      StrCat (ConfigRequest, L"&");
-      StrCat (ConfigRequest, Question->VariableName);
-    }
-
-    Status = FormSet->ConfigAccess->ExtractConfig (
-                                      FormSet->ConfigAccess,
-                                      ConfigRequest,
-                                      &Progress,
-                                      &Result
-                                      );
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    //
-    // Skip <ConfigRequest>
-    //
-    Value = Result + Length;
-    if (IsBufferStorage) {
-      //
-      // Skip "&VALUE"
-      //
-      Value = Value + 6;
-    }
-    if (*Value != '=') {
-      gBS->FreePool (Result);
-      return EFI_NOT_FOUND;
-    }
-    //
-    // Skip '=', point to value
-    //
-    Value = Value + 1;
-    if (!IsBufferStorage && IsString) {
-      //
-      // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
-      //
-      Length = StorageWidth + sizeof (CHAR16);
-      Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value);
-    } else {
-      Status = HexStringToBuf (Dst, &StorageWidth, Value, NULL);
-      if (EFI_ERROR (Status)) {
-        gBS->FreePool (Result);
-        return Status;
-      }
-    }
-
-    //
-    // Synchronize Edit Buffer
-    //
-    if (IsBufferStorage) {
-      CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
-    } else {
-      SetValueByName (Storage, Question->VariableName, Value);
-    }
-    gBS->FreePool (Result);
-  }
-
-  return Status;
-}
-
-
-/**
-  Save Question Value to edit copy(cached) or Storage(uncached).
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   Form data structure.
-  @param  Question               Pointer to the Question.
-  @param  Cached                 TRUE:  set to Edit copy FALSE: set to original
-                                 Storage
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-SetQuestionValue (
-  IN FORM_BROWSER_FORMSET             *FormSet,
-  IN FORM_BROWSER_FORM                *Form,
-  IN OUT FORM_BROWSER_STATEMENT       *Question,
-  IN BOOLEAN                          Cached
-  )
-{
-  EFI_STATUS          Status;
-  BOOLEAN             Enabled;
-  BOOLEAN             Pending;
-  UINT8               *Src;
-  EFI_TIME            EfiTime;
-  UINTN               BufferLen;
-  UINTN               StorageWidth;
-  FORMSET_STORAGE     *Storage;
-  EFI_IFR_TYPE_VALUE  *QuestionValue;
-  CHAR16              *ConfigResp;
-  CHAR16              *Progress;
-  CHAR16              *Value;
-  UINTN               Length;
-  BOOLEAN             IsBufferStorage;
-  BOOLEAN             IsString;
-
-  Status = EFI_SUCCESS;
-
-  //
-  // Statement don't have storage, skip them
-  //
-  if (Question->QuestionId == 0) {
-    return Status;
-  }
-
-  //
-  // If Question value is provided by an Expression, then it is read only
-  //
-  if (Question->ValueExpression != NULL) {
-    return Status;
-  }
-
-  //
-  // Question value is provided by RTC
-  //
-  Storage = Question->Storage;
-  QuestionValue = &Question->HiiValue.Value;
-  if (Storage == NULL) {
-    //
-    // It's a Question without storage, or RTC date/time
-    //
-    if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
-      //
-      // Date and time define the same Flags bit
-      //
-      switch (Question->Flags & EFI_QF_DATE_STORAGE) {
-      case QF_DATE_STORAGE_TIME:
-        Status = gRT->GetTime (&EfiTime, NULL);
-        break;
-
-      case QF_DATE_STORAGE_WAKEUP:
-        Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
-        break;
-
-      case QF_DATE_STORAGE_NORMAL:
-      default:
-        //
-        // For date/time without storage
-        //
-        return EFI_SUCCESS;
-      }
-
-      if (EFI_ERROR (Status)) {
-        return Status;
-      }
-
-      if (Question->Operand == EFI_IFR_DATE_OP) {
-        EfiTime.Year  = QuestionValue->date.Year;
-        EfiTime.Month = QuestionValue->date.Month;
-        EfiTime.Day   = QuestionValue->date.Day;
-      } else {
-        EfiTime.Hour   = QuestionValue->time.Hour;
-        EfiTime.Minute = QuestionValue->time.Minute;
-        EfiTime.Second = QuestionValue->time.Second;
-      }
-
-      if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
-        Status = gRT->SetTime (&EfiTime);
-      } else {
-        Status = gRT->SetWakeupTime (TRUE, &EfiTime);
-      }
-    }
-
-    return Status;
-  }
-
-  //
-  // Question value is provided by EFI variable
-  //
-  StorageWidth = Question->StorageWidth;
-  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
-    if (Question->BufferValue != NULL) {
-      Src = Question->BufferValue;
-    } else {
-      Src = (UINT8 *) QuestionValue;
-    }
-
-    Status = gRT->SetVariable (
-                     Question->VariableName,
-                     &Storage->Guid,
-                     Storage->Attributes,
-                     StorageWidth,
-                     Src
-                     );
-    return Status;
-  }
-
-  //
-  // Question Value is provided by Buffer Storage or NameValue Storage
-  //
-  if (Question->BufferValue != NULL) {
-    Src = Question->BufferValue;
-  } else {
-    Src = (UINT8 *) &Question->HiiValue.Value;
-  }
-
-  IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
-  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
-  if (IsBufferStorage) {
-    //
-    // Copy to storage edit buffer
-    //
-    CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
-  } else {
-    if (IsString) {
-      //
-      // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
-      //
-      Value = NULL;
-      BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
-      Value = AllocateZeroPool (BufferLen);
-      ASSERT (Value != NULL);
-      Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src);
-      ASSERT_EFI_ERROR (Status);
-    } else {
-      BufferLen = StorageWidth * 2 + 1;
-      Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
-      ASSERT (Value != NULL);
-      BufToHexString (Value, &BufferLen, Src, StorageWidth);
-      ToLower (Value);
-    }
-
-    Status = SetValueByName (Storage, Question->VariableName, Value);
-    gBS->FreePool (Value);
-  }
-
-  if (!Cached) {
-    //
-    // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
-    //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
-    //
-    if (IsBufferStorage) {
-      Length = StrLen (Question->BlockName) + 7;
-    } else {
-      Length = StrLen (Question->VariableName) + 2;
-    }
-    if (!IsBufferStorage && IsString) {
-      Length += (StrLen ((CHAR16 *) Src) * 4);
-    } else {
-      Length += (StorageWidth * 2);
-    }
-    ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
-    ASSERT (ConfigResp != NULL);
-
-    StrCpy (ConfigResp, Storage->ConfigHdr);
-    if (IsBufferStorage) {
-      StrCat (ConfigResp, Question->BlockName);
-      StrCat (ConfigResp, L"&VALUE=");
-    } else {
-      StrCat (ConfigResp, L"&");
-      StrCat (ConfigResp, Question->VariableName);
-      StrCat (ConfigResp, L"=");
-    }
-
-    Value = ConfigResp + StrLen (ConfigResp);
-    if (!IsBufferStorage && IsString) {
-      //
-      // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
-      //
-      BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
-      Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src);
-      ASSERT_EFI_ERROR (Status);
-    } else {
-      BufferLen = StorageWidth * 2 + 1;
-      BufToHexString (Value, &BufferLen, Src, StorageWidth);
-      ToLower (Value);
-    }
-
-    //
-    // Submit Question Value to Configuration Driver
-    //
-    if (FormSet->ConfigAccess != NULL) {
-      Status = FormSet->ConfigAccess->RouteConfig (
-                                        FormSet->ConfigAccess,
-                                        ConfigResp,
-                                        &Progress
-                                        );
-      if (EFI_ERROR (Status)) {
-        gBS->FreePool (ConfigResp);
-        return Status;
-      }
-    }
-    gBS->FreePool (ConfigResp);
-
-    //
-    // Synchronize shadow Buffer
-    //
-    SynchronizeStorage (Storage);
-  }
-
-  return Status;
-}
-
-
-/**
-  Perform inconsistent check for a Form.
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   Form data structure.
-  @param  Question               The Question to be validated.
-  @param  Type                   Validation type: InConsistent or NoSubmit
-
-  @retval EFI_SUCCESS            Form validation pass.
-  @retval other                  Form validation failed.
-
-**/
-EFI_STATUS
-ValidateQuestion (
-  IN  FORM_BROWSER_FORMSET            *FormSet,
-  IN  FORM_BROWSER_FORM               *Form,
-  IN  FORM_BROWSER_STATEMENT          *Question,
-  IN  UINTN                           Type
-  )
-{
-  EFI_STATUS              Status;
-  LIST_ENTRY              *Link;
-  LIST_ENTRY              *ListHead;
-  EFI_STRING              PopUp;
-  EFI_INPUT_KEY           Key;
-  FORM_EXPRESSION         *Expression;
-
-  if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {
-    ListHead = &Question->InconsistentListHead;
-  } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
-    ListHead = &Question->NoSubmitListHead;
-  } else {
-    return EFI_UNSUPPORTED;
-  }
-
-  Link = GetFirstNode (ListHead);
-  while (!IsNull (ListHead, Link)) {
-    Expression = FORM_EXPRESSION_FROM_LINK (Link);
-
-    //
-    // Evaluate the expression
-    //
-    Status = EvaluateExpression (FormSet, Form, Expression);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    if (Expression->Result.Value.b) {
-      //
-      // Condition meet, show up error message
-      //
-      if (Expression->Error != 0) {
-        PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
-        do {
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-        gBS->FreePool (PopUp);
-      }
-
-      return EFI_NOT_READY;
-    }
-
-    Link = GetNextNode (ListHead, Link);
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Perform NoSubmit check for a Form.
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   Form data structure.
-
-  @retval EFI_SUCCESS            Form validation pass.
-  @retval other                  Form validation failed.
-
-**/
-EFI_STATUS
-NoSubmitCheck (
-  IN  FORM_BROWSER_FORMSET            *FormSet,
-  IN  FORM_BROWSER_FORM               *Form
-  )
-{
-  EFI_STATUS              Status;
-  LIST_ENTRY              *Link;
-  FORM_BROWSER_STATEMENT  *Question;
-
-  Link = GetFirstNode (&Form->StatementListHead);
-  while (!IsNull (&Form->StatementListHead, Link)) {
-    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-
-    Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    Link = GetNextNode (&Form->StatementListHead, Link);
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Submit a Form.
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   Form data structure.
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-SubmitForm (
-  IN FORM_BROWSER_FORMSET             *FormSet,
-  IN FORM_BROWSER_FORM                *Form
-  )
-{
-  EFI_STATUS              Status;
-  LIST_ENTRY              *Link;
-  EFI_STRING              ConfigResp;
-  EFI_STRING              Progress;
-  FORMSET_STORAGE         *Storage;
-
-  //
-  // Validate the Form by NoSubmit check
-  //
-  Status = NoSubmitCheck (FormSet, Form);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Submit Buffer storage or Name/Value storage
-  //
-  Link = GetFirstNode (&FormSet->StorageListHead);
-  while (!IsNull (&FormSet->StorageListHead, Link)) {
-    Storage = FORMSET_STORAGE_FROM_LINK (Link);
-    Link = GetNextNode (&FormSet->StorageListHead, Link);
-
-    if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
-      continue;
-    }
-
-    //
-    // Skip if there is no RequestElement
-    //
-    if (Storage->ElementCount == 0) {
-      continue;
-    }
-
-    //
-    // Prepare <ConfigResp>
-    //
-    Status = StorageToConfigResp (Storage, &ConfigResp);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    //
-    // Send <ConfigResp> to Configuration Driver
-    //
-    if (FormSet->ConfigAccess != NULL) {
-      Status = FormSet->ConfigAccess->RouteConfig (
-                                        FormSet->ConfigAccess,
-                                        ConfigResp,
-                                        &Progress
-                                        );
-      if (EFI_ERROR (Status)) {
-        gBS->FreePool (ConfigResp);
-        return Status;
-      }
-    }
-    gBS->FreePool (ConfigResp);
-
-    //
-    // Config success, update storage shadow Buffer
-    //
-    SynchronizeStorage (Storage);
-  }
-
-  gNvUpdateRequired = FALSE;
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Reset Question to its default value.
-
-  @param  FormSet                FormSet data structure.
-  @param  DefaultId              The Class of the default.
-
-  @retval EFI_SUCCESS            Question is reset to default value.
-
-**/
-EFI_STATUS
-GetQuestionDefault (
-  IN FORM_BROWSER_FORMSET             *FormSet,
-  IN FORM_BROWSER_FORM                *Form,
-  IN FORM_BROWSER_STATEMENT           *Question,
-  IN UINT16                           DefaultId
-  )
-{
-  EFI_STATUS              Status;
-  LIST_ENTRY              *Link;
-  QUESTION_DEFAULT        *Default;
-  QUESTION_OPTION         *Option;
-  EFI_HII_VALUE           *HiiValue;
-  UINT8                   Index;
-
-  Status = EFI_SUCCESS;
-
-  //
-  // Statement don't have storage, skip them
-  //
-  if (Question->QuestionId == 0) {
-    return Status;
-  }
-
-  //
-  // There are three ways to specify default value for a Question:
-  //  1, use nested EFI_IFR_DEFAULT (highest priority)
-  //  2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
-  //  3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
-  //
-  HiiValue = &Question->HiiValue;
-
-  //
-  // EFI_IFR_DEFAULT has highest priority
-  //
-  if (!IsListEmpty (&Question->DefaultListHead)) {
-    Link = GetFirstNode (&Question->DefaultListHead);
-    while (!IsNull (&Question->DefaultListHead, Link)) {
-      Default = QUESTION_DEFAULT_FROM_LINK (Link);
-
-      if (Default->DefaultId == DefaultId) {
-        if (Default->ValueExpression != NULL) {
-          //
-          // Default is provided by an Expression, evaluate it
-          //
-          Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
-          if (EFI_ERROR (Status)) {
-            return Status;
-          }
-
-          CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE));
-        } else {
-          //
-          // Default value is embedded in EFI_IFR_DEFAULT
-          //
-          CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
-        }
-
-        return EFI_SUCCESS;
-      }
-
-      Link = GetNextNode (&Question->DefaultListHead, Link);
-    }
-  }
-
-  //
-  // EFI_ONE_OF_OPTION
-  //
-  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
-    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
-      //
-      // OneOfOption could only provide Standard and Manufacturing default
-      //
-      Link = GetFirstNode (&Question->OptionListHead);
-      while (!IsNull (&Question->OptionListHead, Link)) {
-        Option = QUESTION_OPTION_FROM_LINK (Link);
-
-        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Option->Flags & EFI_IFR_OPTION_DEFAULT)) ||
-            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG))
-           ) {
-          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
-
-          return EFI_SUCCESS;
-        }
-
-        Link = GetNextNode (&Question->OptionListHead, Link);
-      }
-    }
-  }
-
-  //
-  // EFI_IFR_CHECKBOX - lowest priority
-  //
-  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
-    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
-      //
-      // Checkbox could only provide Standard and Manufacturing default
-      //
-      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT)) ||
-          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG))
-         ) {
-        HiiValue->Value.b = TRUE;
-      } else {
-        HiiValue->Value.b = FALSE;
-      }
-
-      return EFI_SUCCESS;
-    }
-  }
-
-  //
-  // For Questions without default
-  //
-  switch (Question->Operand) {
-  case EFI_IFR_NUMERIC_OP:
-    //
-    // Take minimal value as numeric's default value
-    //
-    HiiValue->Value.u64 = Question->Minimum;
-    break;
-
-  case EFI_IFR_ONE_OF_OP:
-    //
-    // Take first oneof option as oneof's default value
-    //
-    Link = GetFirstNode (&Question->OptionListHead);
-    if (!IsNull (&Question->OptionListHead, Link)) {
-      Option = QUESTION_OPTION_FROM_LINK (Link);
-      CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
-    }
-    break;
-
-  case EFI_IFR_ORDERED_LIST_OP:
-    //
-    // Take option sequence in IFR as ordered list's default value
-    //
-    Index = 0;
-    Link = GetFirstNode (&Question->OptionListHead);
-    while (!IsNull (&Question->OptionListHead, Link)) {
-      Option = QUESTION_OPTION_FROM_LINK (Link);
-
-      Question->BufferValue[Index] = Option->Value.Value.u8;
-
-      Index++;
-      if (Index >= Question->MaxContainers) {
-        break;
-      }
-
-      Link = GetNextNode (&Question->OptionListHead, Link);
-    }
-    break;
-
-  default:
-    Status = EFI_NOT_FOUND;
-    break;
-  }
-
-  return Status;
-}
-
-
-/**
-  Reset Questions in a Form to their default value.
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   The Form which to be reset.
-  @param  DefaultId              The Class of the default.
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-ExtractFormDefault (
-  IN FORM_BROWSER_FORMSET             *FormSet,
-  IN FORM_BROWSER_FORM                *Form,
-  IN UINT16                           DefaultId
-  )
-{
-  EFI_STATUS              Status;
-  LIST_ENTRY              *Link;
-  FORM_BROWSER_STATEMENT  *Question;
-
-  Link = GetFirstNode (&Form->StatementListHead);
-  while (!IsNull (&Form->StatementListHead, Link)) {
-    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-    Link = GetNextNode (&Form->StatementListHead, Link);
-
-    //
-    // Reset Question to its default value
-    //
-    Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
-    if (EFI_ERROR (Status)) {
-      continue;
-    }
-
-    //
-    // Synchronize Buffer storage's Edit buffer
-    //
-    if ((Question->Storage != NULL) &&
-        (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
-      SetQuestionValue (FormSet, Form, Question, TRUE);
-    }
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Initialize Question's Edit copy from Storage.
-
-  @param  FormSet                FormSet data structure.
-  @param  Form                   Form data structure.
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-LoadFormConfig (
-  IN FORM_BROWSER_FORMSET             *FormSet,
-  IN FORM_BROWSER_FORM                *Form
-  )
-{
-  EFI_STATUS              Status;
-  LIST_ENTRY              *Link;
-  FORM_BROWSER_STATEMENT  *Question;
-
-  Link = GetFirstNode (&Form->StatementListHead);
-  while (!IsNull (&Form->StatementListHead, Link)) {
-    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
-
-    //
-    // Initialize local copy of Value for each Question
-    //
-    Status = GetQuestionValue (FormSet, Form, Question, TRUE);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    Link = GetNextNode (&Form->StatementListHead, Link);
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Fill storage's edit copy with settings requested from Configuration Driver.
-
-  @param  FormSet                FormSet data structure.
-  @param  Storage                Buffer Storage.
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-LoadStorage (
-  IN FORM_BROWSER_FORMSET    *FormSet,
-  IN FORMSET_STORAGE         *Storage
-  )
-{
-  EFI_STATUS  Status;
-  EFI_STRING  Progress;
-  EFI_STRING  Result;
-  CHAR16      *StrPtr;
-
-  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
-    return EFI_SUCCESS;
-  }
-
-  if (FormSet->ConfigAccess == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  if (Storage->ElementCount == 0) {
-    //
-    // Skip if there is no RequestElement
-    //
-    return EFI_SUCCESS;
-  }
-
-  //
-  // Request current settings from Configuration Driver
-  //
-  Status = FormSet->ConfigAccess->ExtractConfig (
-                                    FormSet->ConfigAccess,
-                                    Storage->ConfigRequest,
-                                    &Progress,
-                                    &Result
-                                    );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Convert Result from <ConfigAltResp> to <ConfigResp>
-  //
-  StrPtr = StrStr (Result, L"ALTCFG");
-  if (StrPtr != NULL) {
-    *StrPtr = L'\0';
-  }
-
-  Status = ConfigRespToStorage (Storage, Result);
-  gBS->FreePool (Result);
-  return Status;
-}
-
-
-/**
-  Get current setting of Questions.
-
-  @param  FormSet                FormSet data structure.
-
-  @retval EFI_SUCCESS            The function completed successfully.
-
-**/
-EFI_STATUS
-InitializeCurrentSetting (
-  IN OUT FORM_BROWSER_FORMSET             *FormSet
-  )
-{
-  LIST_ENTRY              *Link;
-  FORMSET_STORAGE         *Storage;
-  FORM_BROWSER_FORM       *Form;
-  EFI_STATUS              Status;
-
-  //
-  // Extract default from IFR binary
-  //
-  Link = GetFirstNode (&FormSet->FormListHead);
-  while (!IsNull (&FormSet->FormListHead, Link)) {
-    Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
-    Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD);
-
-    Link = GetNextNode (&FormSet->FormListHead, Link);
-  }
-
-  //
-  // Request current settings from Configuration Driver
-  //
-  Link = GetFirstNode (&FormSet->StorageListHead);
-  while (!IsNull (&FormSet->StorageListHead, Link)) {
-    Storage = FORMSET_STORAGE_FROM_LINK (Link);
-
-    Status = LoadStorage (FormSet, Storage);
-
-    //
-    // Now Edit Buffer is filled with default values(lower priority) and current
-    // settings(higher priority), sychronize it to shadow Buffer
-    //
-    if (!EFI_ERROR (Status)) {
-      SynchronizeStorage (Storage);
-    }
-
-    Link = GetNextNode (&FormSet->StorageListHead, Link);
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Fetch the Ifr binary data of a FormSet.
-
-  @param  Handle                 PackageList Handle
-  @param  FormSetGuid            GUID of a formset. If not specified (NULL or zero
-                                 GUID), take the first FormSet found in package
-                                 list.
-  @param  BinaryLength           The length of the FormSet IFR binary.
-  @param  BinaryData             The buffer designed to receive the FormSet.
-
-  @retval EFI_SUCCESS            Buffer filled with the requested FormSet.
-                                 BufferLength was updated.
-  @retval EFI_INVALID_PARAMETER  The handle is unknown.
-  @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot
-                                 be found with the requested FormId.
-
-**/
-EFI_STATUS
-GetIfrBinaryData (
-  IN  EFI_HII_HANDLE   Handle,
-  IN OUT EFI_GUID      *FormSetGuid,
-  OUT UINTN            *BinaryLength,
-  OUT UINT8            **BinaryData
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
-  UINTN                        BufferSize;
-  UINT8                        *Package;
-  UINT8                        *OpCodeData;
-  UINT32                       Offset;
-  UINT32                       Offset2;
-  BOOLEAN                      ReturnDefault;
-  UINT32                       PackageListLength;
-  EFI_HII_PACKAGE_HEADER       PackageHeader;
-
-  OpCodeData = NULL;
-  Package = NULL;
-  ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));;
-
-  //
-  // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list
-  //
-  if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) {
-    ReturnDefault = TRUE;
-  } else {
-    ReturnDefault = FALSE;
-  }
-
-  //
-  // Get HII PackageList
-  //
-  BufferSize = 0;
-  HiiPackageList = NULL;
-  Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
-  if (Status == EFI_BUFFER_TOO_SMALL) {
-    HiiPackageList = AllocatePool (BufferSize);
-    ASSERT (HiiPackageList != NULL);
-
-    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
-  }
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Get Form package from this HII package List
-  //
-  Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
-  Offset2 = 0;
-  CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
-
-  while (Offset < PackageListLength) {
-    Package = ((UINT8 *) HiiPackageList) + Offset;
-    CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
-
-    if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) {
-      //
-      // Search FormSet in this Form Package
-      //
-      Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
-      while (Offset2 < PackageHeader.Length) {
-        OpCodeData = Package + Offset2;
-
-        if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
-          //
-          // Check whether return default FormSet
-          //
-          if (ReturnDefault) {
-            break;
-          }
-
-          //
-          // FormSet GUID is specified, check it
-          //
-          if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
-            break;
-          }
-        }
-
-        Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
-      }
-
-      if (Offset2 < PackageHeader.Length) {
-        //
-        // Target formset found
-        //
-        break;
-      }
-    }
-
-    Offset += PackageHeader.Length;
-  }
-
-  if (Offset >= PackageListLength) {
-    //
-    // Form package not found in this Package List
-    //
-    gBS->FreePool (HiiPackageList);
-    return EFI_NOT_FOUND;
-  }
-
-  if (ReturnDefault && FormSetGuid != NULL) {
-    //
-    // Return the default FormSet GUID
-    //
-    CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
-  }
-
-  //
-  // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
-  // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
-  // of the Form Package.
-  //
-  *BinaryLength = PackageHeader.Length - Offset2;
-  *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
-
-  gBS->FreePool (HiiPackageList);
-
-  if (*BinaryData == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Initialize the internal data structure of a FormSet.
-
-  @param  Handle                 PackageList Handle
-  @param  FormSetGuid            GUID of a formset. If not specified (NULL or zero
-                                 GUID), take the first FormSet found in package
-                                 list.
-  @param  FormSet                FormSet data structure.
-
-  @retval EFI_SUCCESS            The function completed successfully.
-  @retval EFI_NOT_FOUND          The specified FormSet could not be found.
-
-**/
-EFI_STATUS
-InitializeFormSet (
-  IN  EFI_HII_HANDLE                   Handle,
-  IN OUT EFI_GUID                      *FormSetGuid,
-  OUT FORM_BROWSER_FORMSET             *FormSet
-  )
-{
-  EFI_STATUS                Status;
-  EFI_HANDLE                DriverHandle;
-  UINT16                    Index;
-
-  Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  FormSet->HiiHandle = Handle;
-  CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
-
-  //
-  // Retrieve ConfigAccess Protocol associated with this HiiPackageList
-  //
-  Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-  FormSet->DriverHandle = DriverHandle;
-  Status = gBS->HandleProtocol (
-                  DriverHandle,
-                  &gEfiHiiConfigAccessProtocolGuid,
-                  (VOID **) &FormSet->ConfigAccess
-                  );
-  if (EFI_ERROR (Status)) {
-    //
-    // Configuration Driver don't attach ConfigAccess protocol to its HII package
-    // list, then there will be no configuration action required
-    //
-    FormSet->ConfigAccess = NULL;
-  }
-
-  //
-  // Parse the IFR binary OpCodes
-  //
-  Status = ParseOpCodes (FormSet);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  gClassOfVfr = FormSet->SubClass;
-  if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
-    FrontPageHandle = FormSet->HiiHandle;
-  }
-
-  //
-  // Match GUID to find out the function key setting. If match fail, use the default setting.
-  //
-  for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
-    if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
-      //
-      // Update the function key setting.
-      //
-      gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
-      //
-      // Function key prompt can not be displayed if the function key has been disabled.
-      //
-      if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) {
-        gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
-      }
-
-      if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) {
-        gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
-      }
-
-      if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) {
-        gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
-      }
-
-      if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) {
-        gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
-      }
-    }
-  }
-
-  return Status;
-}
+/** @file\r
+Entry and initialization module for the browser.\r
+\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
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Setup.h"\r
+\r
+SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {\r
+  SETUP_DRIVER_SIGNATURE,\r
+  NULL,\r
+  {\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_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
+BOOLEAN               gResetRequired;\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            *gEmptyString;\r
+\r
+CHAR16            *mUnknownString = L"!";\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 = 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
+  //\r
+  // If parent is not specified, it is the root Form of a Formset\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
+  // Get all the Hii handles\r
+  //\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
+  //\r
+  // Search for formset of each class type\r
+  //\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    //\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
+  // Free resources, and restore gOldFormSet and gClassOfVfr\r
+  //\r
+  FreePool (HiiHandles);\r
+}\r
+\r
+/**\r
+  This is the routine which an external caller uses to direct the browser\r
+  where to obtain it's information.\r
+\r
+\r
+  @param This            The Form Browser protocol instanse.\r
+  @param Handles         A pointer to an array of Handles.  If HandleCount > 1 we\r
+                         display a list of the formsets for the handles specified.\r
+  @param HandleCount     The number of Handles specified in Handle.\r
+  @param FormSetGuid     This field points to the EFI_GUID which must match the Guid\r
+                         field in the EFI_IFR_FORM_SET op-code for the specified\r
+                         forms-based package. If FormSetGuid is NULL, then this\r
+                         function will display the first found forms package.\r
+  @param FormId          This field specifies which EFI_IFR_FORM to render as the first\r
+                         displayable page. If this field has a value of 0x0000, then\r
+                         the forms browser will render the specified forms in their encoded order.\r
+  @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in\r
+                          characters.\r
+  @param ActionRequest   Points to the action recommended by the form.\r
+\r
+  @retval  EFI_SUCCESS            The function completed successfully.\r
+  @retval  EFI_INVALID_PARAMETER  One of the parameters has an invalid value.\r
+  @retval  EFI_NOT_FOUND          No valid forms could be found to display.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SendForm (\r
+  IN  CONST EFI_FORM_BROWSER2_PROTOCOL *This,\r
+  IN  EFI_HII_HANDLE                   *Handles,\r
+  IN  UINTN                            HandleCount,\r
+  IN  EFI_GUID                         *FormSetGuid, OPTIONAL\r
+  IN  UINT16                           FormId, OPTIONAL\r
+  IN  CONST EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL\r
+  OUT EFI_BROWSER_ACTION_REQUEST       *ActionRequest  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UI_MENU_SELECTION             *Selection;\r
+  UINTN                         Index;\r
+  FORM_BROWSER_FORMSET          *FormSet;\r
+  FORM_ENTRY_INFO               *MenuList;\r
+\r
+  //\r
+  // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.\r
+  //\r
+  if (mFormDisplay == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Save globals used by SendForm()\r
+  //\r
+  SaveBrowserContext ();\r
+\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
+    ASSERT (Selection != NULL);\r
+\r
+    Selection->Handle = Handles[Index];\r
+    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
+    do {\r
+      FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
+      ASSERT (FormSet != NULL);\r
+\r
+      //\r
+      // Initialize internal data structures of FormSet\r
+      //\r
+      Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);\r
+      if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {\r
+        DestroyFormSet (FormSet);\r
+        break;\r
+      }\r
+      Selection->FormSet = FormSet;\r
+\r
+      //\r
+      // Display this formset\r
+      //\r
+      gCurrentSelection = Selection;\r
+\r
+      Status = SetupBrowser (Selection);\r
+\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
+    } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);\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
+      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;\r
+    }\r
+  }\r
+\r
+  mFormDisplay->ExitDisplay();\r
+\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
+  //\r
+  // Restore globals used by SendForm()\r
+  //\r
+  RestoreBrowserContext ();\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get or set data to the storage.\r
+\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
+  @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  Storage                The pointer to the storage.\r
+\r
+  @retval EFI_SUCCESS            The results have been distributed or are awaiting\r
+                                 distribution.\r
+\r
+**/\r
+EFI_STATUS \r
+ProcessStorage (\r
+  IN OUT UINTN                         *ResultsDataSize,\r
+  IN OUT EFI_STRING                    *ResultsData,\r
+  IN BOOLEAN                           RetrieveData,\r
+  IN BROWSER_STORAGE                   *Storage\r
+  )\r
+{\r
+  CHAR16                *ConfigResp;\r
+  EFI_STATUS            Status;\r
+  CHAR16                *StrPtr;\r
+  UINTN                 BufferSize;\r
+  UINTN                 TmpSize;\r
+\r
+  if (RetrieveData) {\r
+    //\r
+    // Generate <ConfigResp>\r
+    //\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> when first copy the configbody.\r
+    // Also need to consider add "\0" at first time.\r
+    //\r
+    StrPtr     = ConfigResp + StrLen (Storage->ConfigHdr) + 1;\r
+    BufferSize = StrSize (StrPtr);\r
+\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
+    FreePool (ConfigResp);\r
+  } else {\r
+    //\r
+    // Prepare <ConfigResp>\r
+    //\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
+\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
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\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
+  @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
+  // 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
+                  &gEdkiiFormDisplayEngineProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mFormDisplay\r
+                  );\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
+                  &gEfiHiiDatabaseProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mHiiDatabase\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiHiiConfigRoutingProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mHiiConfigRouting\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDevicePathFromTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mPathFromText\r
+                  );\r
+\r
+  //\r
+  // Install FormBrowser2 protocol\r
+  //\r
+  mPrivateData.Handle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mPrivateData.Handle,\r
+                  &gEfiFormBrowser2ProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mPrivateData.FormBrowser2\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\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
+/**\r
+  Create a new string in HII Package List.\r
+\r
+  @param  String                 The String to be added\r
+  @param  HiiHandle              The package list in the HII database to insert the\r
+                                 specified string.\r
+\r
+  @return The output string.\r
+\r
+**/\r
+EFI_STRING_ID\r
+NewString (\r
+  IN  CHAR16                   *String,\r
+  IN  EFI_HII_HANDLE           HiiHandle\r
+  )\r
+{\r
+  EFI_STRING_ID  StringId;\r
+\r
+  StringId = HiiSetString (HiiHandle, 0, String, NULL);\r
+  ASSERT (StringId != 0);\r
+\r
+  return StringId;\r
+}\r
+\r
+\r
+/**\r
+  Delete a string from HII Package List.\r
+\r
+  @param  StringId               Id of the string in HII database.\r
+  @param  HiiHandle              The HII package list handle.\r
+\r
+  @retval EFI_SUCCESS            The string was deleted successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DeleteString (\r
+  IN  EFI_STRING_ID            StringId,\r
+  IN  EFI_HII_HANDLE           HiiHandle\r
+  )\r
+{\r
+  CHAR16  NullChar;\r
+\r
+  NullChar = CHAR_NULL;\r
+  HiiSetString (HiiHandle, StringId, &NullChar, NULL);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Get the string based on the StringId and HII Package List Handle.\r
+\r
+  @param  Token                  The String's ID.\r
+  @param  HiiHandle              The package list in the HII database to search for\r
+                                 the specified string.\r
+\r
+  @return The output string.\r
+\r
+**/\r
+CHAR16 *\r
+GetToken (\r
+  IN  EFI_STRING_ID                Token,\r
+  IN  EFI_HII_HANDLE               HiiHandle\r
+  )\r
+{\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 (StrSize (mUnknownString), mUnknownString);\r
+    ASSERT (String != NULL);\r
+  }\r
+  return (CHAR16 *) String;\r
+}\r
+\r
+\r
+/**\r
+  Allocate new memory and then copy the Unicode string Source to Destination.\r
+\r
+  @param  Dest                   Location to copy string\r
+  @param  Src                    String to copy\r
+\r
+**/\r
+VOID\r
+NewStringCpy (\r
+  IN OUT CHAR16       **Dest,\r
+  IN CHAR16           *Src\r
+  )\r
+{\r
+  if (*Dest != NULL) {\r
+    FreePool (*Dest);\r
+  }\r
+  *Dest = AllocateCopyPool (StrSize (Src), Src);\r
+  ASSERT (*Dest != NULL);\r
+}\r
+\r
+\r
+/**\r
+  Allocate new memory and concatinate Source on the end of Destination.\r
+\r
+  @param  Dest                   String to added to the end of.\r
+  @param  Src                    String to concatinate.\r
+\r
+**/\r
+VOID\r
+NewStringCat (\r
+  IN OUT CHAR16       **Dest,\r
+  IN CHAR16           *Src\r
+  )\r
+{\r
+  CHAR16  *NewString;\r
+  UINTN   TmpSize;\r
+\r
+  if (*Dest == NULL) {\r
+    NewStringCpy (Dest, Src);\r
+    return;\r
+  }\r
+\r
+  TmpSize = StrSize (*Dest);\r
+  NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);\r
+  ASSERT (NewString != NULL);\r
+\r
+  StrCpy (NewString, *Dest);\r
+  StrCat (NewString, Src);\r
+\r
+  FreePool (*Dest);\r
+  *Dest = NewString;\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
+\r
+**/\r
+EFI_STATUS\r
+GetValueByName (\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
+  while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+    Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+\r
+    if (StrCmp (Name, Node->Name) == 0) {\r
+      if (GetValueFrom == GetSetValueWithEditBuffer) {\r
+        NewStringCpy (Value, Node->EditValue);\r
+      } else {\r
+        NewStringCpy (Value, Node->Value);\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Set Value of given Name in a NameValue Storage.\r
+\r
+  @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
+\r
+**/\r
+EFI_STATUS\r
+SetValueByName (\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 (SetValueTo == GetSetValueWithEditBuffer) {\r
+        Buffer = Node->EditValue;\r
+      } else {\r
+        Buffer = Node->Value;\r
+      }\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
+    Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.\r
+\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
+\r
+**/\r
+EFI_STATUS\r
+StorageToConfigResp (\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
+  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
+                                  ConfigRequest,\r
+                                  SourceBuf,\r
+                                  Storage->Size,\r
+                                  ConfigResp,\r
+                                  &Progress\r
+                                  );\r
+    break;\r
+\r
+  case EFI_HII_VARSTORE_NAME_VALUE:\r
+    *ConfigResp = NULL;\r
+    NewStringCat (ConfigResp, Storage->ConfigHdr);\r
+\r
+    Link = GetFirstNode (&Storage->NameValueListHead);\r
+    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\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
+\r
+  case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.\r
+\r
+  @param  Storage                The Storage to receive the settings.\r
+  @param  ConfigResp             The <ConfigResp> to be converted.\r
+\r
+  @retval EFI_SUCCESS            Convert success.\r
+  @retval EFI_INVALID_PARAMETER  Incorrect storage type.\r
+\r
+**/\r
+EFI_STATUS\r
+ConfigRespToStorage (\r
+  IN BROWSER_STORAGE         *Storage,\r
+  IN CHAR16                  *ConfigResp\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_STRING  Progress;\r
+  UINTN       BufferSize;\r
+  CHAR16      *StrPtr;\r
+  CHAR16      *Name;\r
+  CHAR16      *Value;\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
+    BufferSize = Storage->Size;\r
+    Status = mHiiConfigRouting->ConfigToBlock (\r
+                                  mHiiConfigRouting,\r
+                                  ConfigResp,\r
+                                  Storage->EditBuffer,\r
+                                  &BufferSize,\r
+                                  &Progress\r
+                                  );\r
+    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
+      // Skip '&'\r
+      //\r
+      StrPtr = StrPtr + 1;\r
+      Name = StrPtr;\r
+      StrPtr = StrStr (StrPtr, L"=");\r
+      if (StrPtr == NULL) {\r
+        break;\r
+      }\r
+      *StrPtr = 0;\r
+\r
+      //\r
+      // Skip '='\r
+      //\r
+      StrPtr = StrPtr + 1;\r
+      Value = StrPtr;\r
+      StrPtr = StrStr (StrPtr, L"&");\r
+      if (StrPtr != NULL) {\r
+        *StrPtr = 0;\r
+      }\r
+      SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);\r
+    }\r
+    break;\r
+\r
+  case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get Question's current Value.\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 EFI_SUCCESS            The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetQuestionValue (\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_STATUS          Status;\r
+  BOOLEAN             Enabled;\r
+  BOOLEAN             Pending;\r
+  UINT8               *Dst;\r
+  UINTN               StorageWidth;\r
+  EFI_TIME            EfiTime;\r
+  BROWSER_STORAGE     *Storage;\r
+  EFI_IFR_TYPE_VALUE  *QuestionValue;\r
+  CHAR16              *ConfigRequest;\r
+  CHAR16              *Progress;\r
+  CHAR16              *Result;\r
+  CHAR16              *Value;\r
+  CHAR16              *StringPtr;\r
+  UINTN               Length;\r
+  UINTN               Index;\r
+  UINTN               LengthStr;\r
+  BOOLEAN             IsBufferStorage;\r
+  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
+  //\r
+  if (Question->QuestionId == 0) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Question value is provided by an Expression, evaluate it\r
+  //\r
+  if (Question->ValueExpression != NULL) {\r
+    Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);\r
+    if (!EFI_ERROR (Status)) {\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
+  //\r
+  Storage = Question->Storage;\r
+  QuestionValue = &Question->HiiValue.Value;\r
+  if (Storage == NULL) {\r
+    //\r
+    // It's a Question without storage, or RTC date/time\r
+    //\r
+    if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+      //\r
+      // Date and time define the same Flags bit\r
+      //\r
+      switch (Question->Flags & EFI_QF_DATE_STORAGE) {\r
+      case QF_DATE_STORAGE_TIME:\r
+        Status = gRT->GetTime (&EfiTime, NULL);\r
+        break;\r
+\r
+      case QF_DATE_STORAGE_WAKEUP:\r
+        Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);\r
+        break;\r
+\r
+      case QF_DATE_STORAGE_NORMAL:\r
+      default:\r
+        //\r
+        // For date/time without storage\r
+        //\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (Question->Operand == EFI_IFR_DATE_OP) {\r
+        QuestionValue->date.Year  = EfiTime.Year;\r
+        QuestionValue->date.Month = EfiTime.Month;\r
+        QuestionValue->date.Day   = EfiTime.Day;\r
+      } else {\r
+        QuestionValue->time.Hour   = EfiTime.Hour;\r
+        QuestionValue->time.Minute = EfiTime.Minute;\r
+        QuestionValue->time.Second = EfiTime.Second;\r
+      }\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Question value is provided by EFI variable\r
+  //\r
+  StorageWidth = Question->StorageWidth;\r
+  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+    if (Question->BufferValue != NULL) {\r
+      Dst = Question->BufferValue;\r
+    } else {\r
+      Dst = (UINT8 *) QuestionValue;\r
+    }\r
+\r
+    Status = gRT->GetVariable (\r
+                     Question->VariableName,\r
+                     &Storage->Guid,\r
+                     NULL,\r
+                     &StorageWidth,\r
+                     Dst\r
+                     );\r
+    //\r
+    // Always return success, even this EFI variable doesn't exist\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Question Value is provided by Buffer Storage or NameValue Storage\r
+  //\r
+  if (Question->BufferValue != NULL) {\r
+    //\r
+    // This Question is password or orderedlist\r
+    //\r
+    Dst = Question->BufferValue;\r
+  } else {\r
+    //\r
+    // Other type of Questions\r
+    //\r
+    Dst = (UINT8 *) &Question->HiiValue.Value;\r
+  }\r
+\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 (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {\r
+    if (IsBufferStorage) {\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
+        //\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
+        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
+      FreePool (Value);\r
+    }\r
+  } else {\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
+      // <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
+      FreePool (ConfigRequest);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Skip <ConfigRequest>\r
+      //\r
+      if (IsBufferStorage) {\r
+        Value = StrStr (Result, L"&VALUE");\r
+        if (Value == NULL) {\r
+          FreePool (Result);\r
+          return EFI_NOT_FOUND;\r
+        }\r
+        //\r
+        // Skip "&VALUE"\r
+        //\r
+        Value = Value + 6;\r
+      } else {\r
+        Value = Result + Length;\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
+\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
+        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
+      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
+    // Synchronize Edit Buffer\r
+    //\r
+    if (IsBufferStorage) {\r
+      CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);\r
+    } else {\r
+      SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);\r
+    }\r
+\r
+    if (Result != NULL) {\r
+      FreePool (Result);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Save Question Value to edit copy(cached) or Storage(uncached).\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  Question               Pointer to the Question.\r
+  @param  SetValueTo             Update the question value to editbuffer , buffer or hii driver.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SetQuestionValue (\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      SetValueTo\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  BOOLEAN             Enabled;\r
+  BOOLEAN             Pending;\r
+  UINT8               *Src;\r
+  EFI_TIME            EfiTime;\r
+  UINTN               BufferLen;\r
+  UINTN               StorageWidth;\r
+  BROWSER_STORAGE     *Storage;\r
+  EFI_IFR_TYPE_VALUE  *QuestionValue;\r
+  CHAR16              *ConfigResp;\r
+  CHAR16              *Progress;\r
+  CHAR16              *Value;\r
+  UINTN               Length;\r
+  BOOLEAN             IsBufferStorage;\r
+  BOOLEAN             IsString;\r
+  UINT8               *TemBuffer;\r
+  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
+  //\r
+  if (Question->QuestionId == 0) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // If Question value is provided by an Expression, then it is read only\r
+  //\r
+  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
+  //\r
+  Storage = Question->Storage;\r
+  QuestionValue = &Question->HiiValue.Value;\r
+  if (Storage == NULL) {\r
+    //\r
+    // It's a Question without storage, or RTC date/time\r
+    //\r
+    if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+      //\r
+      // Date and time define the same Flags bit\r
+      //\r
+      switch (Question->Flags & EFI_QF_DATE_STORAGE) {\r
+      case QF_DATE_STORAGE_TIME:\r
+        Status = gRT->GetTime (&EfiTime, NULL);\r
+        break;\r
+\r
+      case QF_DATE_STORAGE_WAKEUP:\r
+        Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);\r
+        break;\r
+\r
+      case QF_DATE_STORAGE_NORMAL:\r
+      default:\r
+        //\r
+        // For date/time without storage\r
+        //\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (Question->Operand == EFI_IFR_DATE_OP) {\r
+        EfiTime.Year  = QuestionValue->date.Year;\r
+        EfiTime.Month = QuestionValue->date.Month;\r
+        EfiTime.Day   = QuestionValue->date.Day;\r
+      } else {\r
+        EfiTime.Hour   = QuestionValue->time.Hour;\r
+        EfiTime.Minute = QuestionValue->time.Minute;\r
+        EfiTime.Second = QuestionValue->time.Second;\r
+      }\r
+\r
+      if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {\r
+        Status = gRT->SetTime (&EfiTime);\r
+      } else {\r
+        Status = gRT->SetWakeupTime (TRUE, &EfiTime);\r
+      }\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Question value is provided by EFI variable\r
+  //\r
+  StorageWidth = Question->StorageWidth;\r
+  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+    if (Question->BufferValue != NULL) {\r
+      Src = Question->BufferValue;\r
+    } else {\r
+      Src = (UINT8 *) QuestionValue;\r
+    }\r
+\r
+    Status = gRT->SetVariable (\r
+                     Question->VariableName,\r
+                     &Storage->Guid,\r
+                     Storage->Attributes,\r
+                     StorageWidth,\r
+                     Src\r
+                     );\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Question Value is provided by Buffer Storage or NameValue Storage\r
+  //\r
+  if (Question->BufferValue != NULL) {\r
+    Src = Question->BufferValue;\r
+  } else {\r
+    Src = (UINT8 *) &Question->HiiValue.Value;\r
+  }\r
+\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
+\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
+      // Check whether question value has been changed.\r
+      //\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
+      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
+      // Check whether question value has been changed.\r
+      //\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
+      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
+      Value = ConfigResp + StrLen (ConfigResp);\r
+\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
+      //\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
+        }\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
+          return Status;\r
+        }\r
+      }\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
+      Length = Storage->Size;\r
+      Status = gRT->GetVariable (\r
+                       Storage->Name,\r
+                       &Storage->Guid,\r
+                       NULL,\r
+                       &Length,\r
+                       TemBuffer\r
+                       );\r
+\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
+    //\r
+    // Sync storage, from editbuffer to buffer.\r
+    //\r
+    CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\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: NoSubmit\r
+\r
+  @retval EFI_SUCCESS            Form validation pass.\r
+  @retval other                  Form validation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+ValidateQuestion (\r
+  IN  FORM_BROWSER_FORMSET            *FormSet,\r
+  IN  FORM_BROWSER_FORM               *Form,\r
+  IN  FORM_BROWSER_STATEMENT          *Question,\r
+  IN  UINTN                           Type\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  LIST_ENTRY              *Link;\r
+  LIST_ENTRY              *ListHead;\r
+  EFI_STRING              PopUp;\r
+  FORM_EXPRESSION         *Expression;\r
+\r
+  if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
+    ListHead = &Question->NoSubmitListHead;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Link = GetFirstNode (ListHead);\r
+  while (!IsNull (ListHead, Link)) {\r
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
+\r
+    //\r
+    // Evaluate the expression\r
+    //\r
+    Status = EvaluateExpression (FormSet, Form, Expression);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\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
+        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
+    }\r
+\r
+    Link = GetNextNode (ListHead, Link);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Perform NoSubmit check for each Form in FormSet.\r
+\r
+  @param  FormSet                FormSet 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
+\r
+**/\r
+EFI_STATUS\r
+NoSubmitCheck (\r
+  IN  FORM_BROWSER_FORMSET            *FormSet,\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
+  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
+    if (CurrentForm != NULL && CurrentForm != Form) {\r
+      continue;\r
+    }\r
+\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
+  Fill storage's edit copy with settings requested from Configuration Driver.\r
+\r
+  @param  FormSet                FormSet 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
+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
+  EFI_STRING              Progress;\r
+  EFI_STRING              Result;\r
+  UINTN                   BufferSize;\r
+  LIST_ENTRY              *Link;\r
+  NAME_VALUE_NODE         *Node;\r
+  UINT8                   *Src;\r
+  UINT8                   *Dst;\r
+\r
+  Status = EFI_SUCCESS;\r
+  Result = NULL;\r
+\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    BufferSize = Storage->Size;\r
+\r
+    if (SyncOrRestore) {\r
+      Src = Storage->EditBuffer;\r
+      Dst = Storage->Buffer;\r
+    } else {\r
+      Src = Storage->Buffer;\r
+      Dst = Storage->EditBuffer;\r
+    }\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
+        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
+  } 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
+      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
+      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  When discard the question value, call the callback function with Changed type\r
+  to inform the hii driver.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+\r
+**/\r
+VOID\r
+SendDiscardInfoToDriver (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form\r
+  )\r
+{\r
+  LIST_ENTRY                  *Link;\r
+  FORM_BROWSER_STATEMENT      *Question;\r
+  EFI_IFR_TYPE_VALUE          *TypeValue;\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
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+    if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+      continue;\r
+    }\r
+\r
+    if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
+      continue;\r
+    }\r
+\r
+    if (!Question->ValueChanged) {\r
+      continue;\r
+    }\r
+\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
+  Validate the FormSet. If the formset is not validate, remove it from the list.\r
+\r
+  @param  FormSet                The input FormSet which need to validate.\r
+\r
+  @retval TRUE                   The handle is validate.\r
+  @retval FALSE                  The handle is invalidate.\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
+  // Get all the Hii handles\r
+  //\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
+  //\r
+  // Search for formset of each class type\r
+  //\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    if (HiiHandles[Index] == FormSet->HiiHandle) {\r
+      Find = TRUE;\r
+      break;\r
+    }\r
+  }\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
+  Check whether need to enable the reset flag in form level.\r
+  Also clean all ValueChanged flag in question.\r
+\r
+  @param  SetFlag                Whether need to set the Reset Flag.\r
+  @param  Form                   Form data structure.\r
+\r
+**/\r
+VOID\r
+UpdateFlagForForm (\r
+  IN BOOLEAN                          SetFlag,\r
+  IN FORM_BROWSER_FORM                *Form\r
+  )\r
+{\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
+  \r
+    if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {\r
+      gResetRequired = TRUE;\r
+    } \r
+\r
+    if (Question->ValueChanged) {\r
+      Question->ValueChanged = FALSE;\r
+    }\r
+  \r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether need to enable the reset flag.\r
+  Also clean ValueChanged flag for all statements.\r
+\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
+**/\r
+VOID\r
+ValueChangeResetFlagUpdate (\r
+  IN BOOLEAN                          SetFlag,\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form  \r
+  )\r
+{\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
+    // Discard 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->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
+    // Discard 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
+      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
+      // Skip if there is no RequestElement\r
+      //\r
+      if (ConfigInfo->ElementCount == 0) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // 1. Prepare <ConfigResp>\r
+      //\r
+      Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\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
+        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
+        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
+    //\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
+      if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip if there is no RequestElement\r
+      //\r
+      if (FormSetStorage->ElementCount == 0) {\r
+        continue;\r
+      }\r
+\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
+    //\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
+  Get Question default value from AltCfg string.\r
+\r
+  @param  FormSet                The form set.\r
+  @param  Question               The question.\r
+  @param  DefaultId              The default Id.\r
+\r
+  @retval EFI_SUCCESS            Question is reset to default value.\r
+\r
+**/\r
+EFI_STATUS\r
+GetDefaultValueFromAltCfg (\r
+  IN     FORM_BROWSER_FORMSET             *FormSet,\r
+  IN OUT FORM_BROWSER_STATEMENT           *Question,\r
+  IN     UINT16                           DefaultId\r
+  )\r
+{\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
+  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
+    // This Question is password or orderedlist\r
+    //\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
+  //\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
+  //\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
+/**\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
+VOID\r
+SaveBrowserContext (\r
+  VOID\r
+  )\r
+{\r
+  BROWSER_CONTEXT  *Context;\r
+  FORM_ENTRY_INFO     *MenuList;\r
+\r
+  gBrowserContextCount++;\r
+  if (gBrowserContextCount == 1) {\r
+    //\r
+    // This is not reentry of SendForm(), no context to save\r
+    //\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Not support SendForm nest in another SendForm, assert here.\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
+  // Save the menu history data.\r
+  //\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
+  //\r
+  // Insert to FormBrowser context list\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
+  FORM_ENTRY_INFO     *MenuList;\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
+  }\r
+\r
+  ASSERT (!IsListEmpty (&gBrowserContextList));\r
+\r
+  Link = GetFirstNode (&gBrowserContextList);\r
+  Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
+\r
+  //\r
+  // Restore FormBrowser context\r
+  //\r
+  gResetRequired        = Context->ResetRequired;\r
+  gExitRequired         = Context->ExitRequired;\r
+  mCurrentHiiHandle     = Context->HiiHandle;\r
+\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
+    InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
+  }\r
+\r
+  //\r
+  // Remove from FormBrowser context list\r
+  //\r
+  RemoveEntryList (&Context->Link);\r
+  gBS->FreePool (Context);\r
+}\r
+\r
+/**\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
+**/\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
+/**\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
+BOOLEAN\r
+IsHiiHandleInBrowserContext (\r
+  EFI_HII_HANDLE Handle\r
+  )\r
+{\r
+  LIST_ENTRY       *Link;\r
+  BROWSER_CONTEXT  *Context;\r
+\r
+  //\r
+  // HiiHandle is Current FormSet.\r
+  //\r
+  if (mCurrentHiiHandle == Handle) {\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // Check whether HiiHandle is in BrowserContext.\r
+  //\r
+  Link = GetFirstNode (&gBrowserContextList);\r
+  while (!IsNull (&gBrowserContextList, Link)) {\r
+    Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
+    if (Context->HiiHandle == Handle) {\r
+      //\r
+      // HiiHandle is in BrowserContext\r
+      //\r
+      return TRUE;\r
+    }\r
+    Link = GetNextNode (&gBrowserContextList, Link);\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
+\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
+      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
+  // 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
+  //\r
+  // Remove password string from HII database\r
+  //\r
+  if (PasswordString != NULL) {\r
+    DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\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
+  @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
+  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
+EFIAPI\r
+SetScope (\r
+  IN BROWSER_SETTING_SCOPE Scope\r
+  )\r
+{\r
+  if (Scope >= MaxLevel) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\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
+  // Check input parameters.\r
+  //\r
+  if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || \r
+     (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether the input KeyData is in BrowserHotKeyList.\r
+  //\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
+  \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
+\r
+  //\r
+  // Fill HotKey information.\r
+  //\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
+  return EFI_SUCCESS;\r
+}\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
+VOID\r
+EFIAPI\r
+RegiserExitHandler (\r
+  IN EXIT_HANDLER Handler\r
+  )\r
+{\r
+  ExitHandlerFunction = Handler;\r
+  return;\r
+}\r
+\r
+/**\r
+  Check whether the browser data has been modified.\r
+\r
+  @retval TRUE        Browser data is modified.\r
+  @retval FALSE       No browser data is modified.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsBrowserDataModified (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
+\r
+  if (gCurrentSelection == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  switch (gBrowserSettingScope) {\r
+    case FormLevel:\r
+      return IsNvUpdateRequiredForForm (gCurrentSelection->Form);\r
+\r
+    case FormSetLevel:\r
+      return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);\r
+\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
+    default:\r
+      return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Execute the action requested by the Action parameter.\r
+\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              Execute the request action succss.\r
+  @retval EFI_INVALID_PARAMETER    The input action value is invalid.\r
+\r
+**/\r
+EFI_STATUS \r
+EFIAPI\r
+ExecuteAction (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  if (gCurrentSelection == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Executet the discard action.\r
+  //\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
+  // Executet the difault action.\r
+  //\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
+  //\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
+  // Executet the reset action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_RESET) != 0) {\r
+    gResetRequired = TRUE;\r
+  }\r
+\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
+  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
+UINT32\r
+EFIAPI\r
+SaveReminder (\r
+  VOID\r
+  )\r
+{\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
+  //\r
+  // No data is changed. No save is required. \r
+  //\r
+  if (!IsDataChanged) {\r
+    return DataSavedAction;\r
+  }\r
+  \r
+  //\r
+  // If data is changed, prompt user to save or discard it. \r
+  //\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
+  return DataSavedAction;\r
+}\r