hikey: Add UEFI sources for reference

UEFI needs to be built outside Android build system.
Please follow the instructions in README.

The sources correspond to:
https://github.com/96boards/edk2/commit/14eae0c12e71fd33c4c0fc51e4475e8db02566cf
https://github.com/96boards/arm-trusted-firmware/commit/e9b4909dcd75fc4ae7041cfb83d28ab9adb7afdf
https://github.com/96boards/l-loader/commit/6b784ad5c4ab00e2b1c6f53cd5f74054e5d00a78
https://git.linaro.org/uefi/uefi-tools.git/commit/abe618f8ab72034fff1ce46c9c006a2c6bd40a7e

Change-Id: Ieeefdb63e673e0c8e64e0a1f02c7bddc63b2c7fb
Signed-off-by: Vishal Bhoj <vishal.bhoj@linaro.org>
diff --git a/uefi/linaro-edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/uefi/linaro-edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
new file mode 100644
index 0000000..9646823
--- /dev/null
+++ b/uefi/linaro-edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
@@ -0,0 +1,6122 @@
+/** @file

+Entry and initialization module for the browser.

+

+Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

+This program and the accompanying materials

+are licensed and made available under the terms and conditions of the BSD License

+which accompanies this distribution.  The full text of the license may be found at

+http://opensource.org/licenses/bsd-license.php

+

+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include "Setup.h"

+

+SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {

+  SETUP_DRIVER_SIGNATURE,

+  NULL,

+  {

+    SendForm,

+    BrowserCallback

+  },

+  {

+    SetScope,

+    RegisterHotKey,

+    RegiserExitHandler,

+    SaveReminder

+  },

+  {

+    BROWSER_EXTENSION2_VERSION_1_1,

+    SetScope,

+    RegisterHotKey,

+    RegiserExitHandler,

+    IsBrowserDataModified,

+    ExecuteAction,

+    {NULL,NULL},

+    {NULL,NULL},

+    IsResetRequired

+  }

+};

+

+EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;

+EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;

+EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;

+EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;

+

+UINTN           gBrowserContextCount = 0;

+LIST_ENTRY      gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);

+LIST_ENTRY      gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);

+LIST_ENTRY      gBrowserHotKeyList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);

+LIST_ENTRY      gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);

+LIST_ENTRY      gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList);

+

+BOOLEAN               mSystemSubmit = FALSE;

+BOOLEAN               gResetRequired;

+BOOLEAN               gExitRequired;

+BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;

+BOOLEAN               mBrowserScopeFirstSet = TRUE;

+EXIT_HANDLER          ExitHandlerFunction = NULL;

+FORM_BROWSER_FORMSET  *mSystemLevelFormSet;

+

+//

+// Browser Global Strings

+//

+CHAR16            *gEmptyString;

+CHAR16            *mUnknownString = L"!";

+

+EFI_GUID  gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};

+

+extern EFI_GUID        mCurrentFormSetGuid;

+extern EFI_HII_HANDLE  mCurrentHiiHandle;

+extern UINT16          mCurrentFormId;

+extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;

+

+/**

+  Create a menu with specified formset GUID and form ID, and add it as a child

+  of the given parent menu.

+

+  @param  HiiHandle              Hii handle related to this formset.

+  @param  FormSetGuid            The Formset Guid of menu to be added.

+  @param  FormId                 The Form ID of menu to be added.

+  @param  QuestionId             The question id of this menu to be added.

+

+  @return A pointer to the newly added menu or NULL if memory is insufficient.

+

+**/

+FORM_ENTRY_INFO *

+UiAddMenuList (

+  IN EFI_HII_HANDLE       HiiHandle,

+  IN EFI_GUID             *FormSetGuid,

+  IN UINT16               FormId,

+  IN UINT16               QuestionId

+  )

+{

+  FORM_ENTRY_INFO  *MenuList;

+

+  MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));

+  if (MenuList == NULL) {

+    return NULL;

+  }

+

+  MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;

+

+  MenuList->HiiHandle  = HiiHandle;

+  CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));

+  MenuList->FormId     = FormId;

+  MenuList->QuestionId = QuestionId;

+

+  //

+  // If parent is not specified, it is the root Form of a Formset

+  //

+  InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);

+

+  return MenuList;

+}

+

+/**

+  Return the form id for the input hiihandle and formset.

+

+  @param  HiiHandle              HiiHandle for FormSet.

+  @param  FormSetGuid            The Formset GUID of the menu to search.

+

+  @return First form's id for this form set.

+

+**/

+EFI_FORM_ID

+GetFirstFormId (

+  IN EFI_HII_HANDLE       HiiHandle,

+  IN EFI_GUID             *FormSetGuid

+  )

+{

+  LIST_ENTRY         *Link;

+  FORM_BROWSER_FORM  *Form;

+

+  Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);

+  Form = FORM_BROWSER_FORM_FROM_LINK (Link);

+

+  return Form->FormId;

+}

+

+/**

+  Search Menu with given FormSetGuid and FormId in all cached menu list.

+

+  @param  HiiHandle              HiiHandle for FormSet.

+  @param  FormSetGuid            The Formset GUID of the menu to search.

+  @param  FormId                 The Form ID of menu to search.

+

+  @return A pointer to menu found or NULL if not found.

+

+**/

+FORM_ENTRY_INFO *

+UiFindMenuList (

+  IN EFI_HII_HANDLE       HiiHandle, 

+  IN EFI_GUID             *FormSetGuid,

+  IN UINT16               FormId

+  )

+{

+  LIST_ENTRY         *Link;

+  FORM_ENTRY_INFO    *MenuList;

+  FORM_ENTRY_INFO    *RetMenu;

+  EFI_FORM_ID        FirstFormId;

+

+  RetMenu = NULL;

+

+  Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);

+  while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {

+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);

+    Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);

+    

+    //

+    // If already find the menu, free the menus behind it.

+    //

+    if (RetMenu != NULL) {

+      RemoveEntryList (&MenuList->Link);

+      FreePool (MenuList);

+      continue;

+    }

+

+    //

+    // Find the same FromSet.

+    //

+    if (MenuList->HiiHandle == HiiHandle) {

+      if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) {

+        //

+        // FormSetGuid is not specified.

+        //

+        RetMenu = MenuList;

+      } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {

+        if (MenuList->FormId == FormId) {

+          RetMenu = MenuList;

+        } else if (FormId == 0 || MenuList->FormId == 0 ) {

+          FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);

+          if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {

+            RetMenu = MenuList;

+          }

+        }

+      }

+    }

+  }

+

+  return RetMenu;

+}

+

+/**

+  Find parent menu for current menu.

+

+  @param  CurrentMenu    Current Menu

+  @param  SettingLevel   Whether find parent menu in Form Level or Formset level.

+                         In form level, just find the parent menu; 

+                         In formset level, find the parent menu which has different

+                         formset guid value.

+

+  @retval   The parent menu for current menu.

+**/

+FORM_ENTRY_INFO *

+UiFindParentMenu (

+  IN FORM_ENTRY_INFO          *CurrentMenu,

+  IN BROWSER_SETTING_SCOPE    SettingLevel

+  )

+{

+  FORM_ENTRY_INFO    *ParentMenu;

+  LIST_ENTRY         *Link;

+

+  ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel);

+

+  if (CurrentMenu == NULL) {

+    return NULL;

+  }

+  

+  ParentMenu = NULL;

+  Link       = &CurrentMenu->Link;

+

+  while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {

+    ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink);

+

+    if (SettingLevel == FormLevel) {

+      //

+      // For FormLevel, just find the parent menu, return.

+      //

+      break;

+    }

+

+    if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {

+      //

+      // For SystemLevel, must find the menu which has different formset.

+      //

+      break;

+    }

+

+    Link = Link->BackLink;

+  }

+

+  //

+  // Not find the parent menu, just return NULL.

+  //

+  if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {

+    return NULL;

+  }

+

+  return ParentMenu;

+}

+

+/**

+  Free Menu list linked list.

+

+  @param  MenuListHead    One Menu list point in the menu list.

+

+**/

+VOID

+UiFreeMenuList (

+  LIST_ENTRY   *MenuListHead

+  )

+{

+  FORM_ENTRY_INFO    *MenuList;

+

+  while (!IsListEmpty (MenuListHead)) {

+    MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);

+    RemoveEntryList (&MenuList->Link);

+

+    FreePool (MenuList);

+  }

+}

+

+/**

+  Copy current Menu list to the new menu list.

+  

+  @param  NewMenuListHead        New create Menu list.

+  @param  CurrentMenuListHead    Current Menu list.

+

+**/

+VOID

+UiCopyMenuList (

+  OUT LIST_ENTRY   *NewMenuListHead,

+  IN  LIST_ENTRY   *CurrentMenuListHead

+  )

+{

+  LIST_ENTRY         *Link;

+  FORM_ENTRY_INFO    *MenuList;

+  FORM_ENTRY_INFO    *NewMenuEntry;

+

+  //

+  // If new menu list not empty, free it first.

+  //

+  UiFreeMenuList (NewMenuListHead);

+

+  Link = GetFirstNode (CurrentMenuListHead);

+  while (!IsNull (CurrentMenuListHead, Link)) {

+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);

+    Link = GetNextNode (CurrentMenuListHead, Link);

+

+    NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));

+    ASSERT (NewMenuEntry != NULL);

+    NewMenuEntry->Signature  = FORM_ENTRY_INFO_SIGNATURE;

+    NewMenuEntry->HiiHandle  = MenuList->HiiHandle;

+    CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID));

+    NewMenuEntry->FormId     = MenuList->FormId;

+    NewMenuEntry->QuestionId = MenuList->QuestionId;

+

+    InsertTailList (NewMenuListHead, &NewMenuEntry->Link);

+  }

+}

+

+/**

+  Load all hii formset to the browser.

+

+**/

+VOID

+LoadAllHiiFormset (

+  VOID

+  )

+{

+  FORM_BROWSER_FORMSET    *LocalFormSet;

+  EFI_HII_HANDLE          *HiiHandles;

+  UINTN                   Index;

+  EFI_GUID                ZeroGuid;

+  EFI_STATUS              Status;

+  FORM_BROWSER_FORMSET    *OldFormset;

+

+  OldFormset = mSystemLevelFormSet;

+

+  //

+  // Get all the Hii handles

+  //

+  HiiHandles = HiiGetHiiHandles (NULL);

+  ASSERT (HiiHandles != NULL);

+

+  //

+  // Search for formset of each class type

+  //

+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {

+    //

+    // Check HiiHandles[Index] does exist in global maintain list.

+    //

+    if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {

+      continue;

+    }

+

+    //

+    // Initilize FormSet Setting

+    //

+    LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));

+    ASSERT (LocalFormSet != NULL);

+    mSystemLevelFormSet = LocalFormSet;

+

+    ZeroMem (&ZeroGuid, sizeof (ZeroGuid));

+    Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);

+    if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {

+      DestroyFormSet (LocalFormSet);

+      continue;

+    }

+    InitializeCurrentSetting (LocalFormSet);

+

+    //

+    // Initilize Questions' Value

+    //

+    Status = LoadFormSetConfig (NULL, LocalFormSet);

+    if (EFI_ERROR (Status)) {

+      DestroyFormSet (LocalFormSet);

+      continue;

+    }

+  }

+

+  //

+  // Free resources, and restore gOldFormSet and gClassOfVfr

+  //

+  FreePool (HiiHandles);

+

+  mSystemLevelFormSet = OldFormset;

+}

+

+/**

+  Pop up the error info.

+

+  @param      BrowserStatus    The input browser status.

+  @param      HiiHandle        The Hiihandle for this opcode.

+  @param      OpCode           The opcode use to get the erro info and timeout value.

+  @param      ErrorString      Error string used by BROWSER_NO_SUBMIT_IF.

+

+**/

+UINT32

+PopupErrorMessage (

+  IN UINT32                BrowserStatus,

+  IN EFI_HII_HANDLE        HiiHandle,

+  IN EFI_IFR_OP_HEADER     *OpCode, OPTIONAL

+  IN CHAR16                *ErrorString

+  )

+{

+  FORM_DISPLAY_ENGINE_STATEMENT *Statement;

+  USER_INPUT                    UserInputData;

+

+  Statement = NULL;

+

+  if (OpCode != NULL) {

+    Statement = AllocateZeroPool (sizeof(FORM_DISPLAY_ENGINE_STATEMENT));

+    ASSERT (Statement != NULL);

+    Statement->OpCode = OpCode;

+    gDisplayFormData.HighLightedStatement = Statement;

+  }

+

+  //

+  // Used to compatible with old display engine.

+  // New display engine not use this field.

+  //

+  gDisplayFormData.ErrorString   = ErrorString;

+  gDisplayFormData.BrowserStatus = BrowserStatus;

+

+  if (HiiHandle != NULL) {

+    gDisplayFormData.HiiHandle     = HiiHandle;

+  }

+

+  mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData);

+

+  gDisplayFormData.BrowserStatus = BROWSER_SUCCESS;

+  gDisplayFormData.ErrorString   = NULL;

+

+  if (OpCode != NULL) {

+    FreePool (Statement);

+  }

+

+  return UserInputData.Action;

+}

+

+/**

+  This is the routine which an external caller uses to direct the browser

+  where to obtain it's information.

+

+

+  @param This            The Form Browser protocol instanse.

+  @param Handles         A pointer to an array of Handles.  If HandleCount > 1 we

+                         display a list of the formsets for the handles specified.

+  @param HandleCount     The number of Handles specified in Handle.

+  @param FormSetGuid     This field points to the EFI_GUID which must match the Guid

+                         field in the EFI_IFR_FORM_SET op-code for the specified

+                         forms-based package. If FormSetGuid is NULL, then this

+                         function will display the first found forms package.

+  @param FormId          This field specifies which EFI_IFR_FORM to render as the first

+                         displayable page. If this field has a value of 0x0000, then

+                         the forms browser will render the specified forms in their encoded order.

+  @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in

+                          characters.

+  @param ActionRequest   Points to the action recommended by the form.

+

+  @retval  EFI_SUCCESS            The function completed successfully.

+  @retval  EFI_INVALID_PARAMETER  One of the parameters has an invalid value.

+  @retval  EFI_NOT_FOUND          No valid forms could be found to display.

+

+**/

+EFI_STATUS

+EFIAPI

+SendForm (

+  IN  CONST EFI_FORM_BROWSER2_PROTOCOL *This,

+  IN  EFI_HII_HANDLE                   *Handles,

+  IN  UINTN                            HandleCount,

+  IN  EFI_GUID                         *FormSetGuid, OPTIONAL

+  IN  UINT16                           FormId, OPTIONAL

+  IN  CONST EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL

+  OUT EFI_BROWSER_ACTION_REQUEST       *ActionRequest  OPTIONAL

+  )

+{

+  EFI_STATUS                    Status;

+  UI_MENU_SELECTION             *Selection;

+  UINTN                         Index;

+  FORM_BROWSER_FORMSET          *FormSet;

+  FORM_ENTRY_INFO               *MenuList;

+

+  //

+  // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.

+  //

+  if (mFormDisplay == NULL) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Save globals used by SendForm()

+  //

+  SaveBrowserContext ();

+

+  gResetRequired = FALSE;

+  gExitRequired  = FALSE;

+  Status         = EFI_SUCCESS;

+  gEmptyString   = L"";

+  gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;

+

+  for (Index = 0; Index < HandleCount; Index++) {

+    Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));

+    ASSERT (Selection != NULL);

+

+    Selection->Handle = Handles[Index];

+    if (FormSetGuid != NULL) {

+      CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));

+      Selection->FormId = FormId;

+    } else {

+      CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));

+    }

+

+    do {

+      FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));

+      ASSERT (FormSet != NULL);

+

+      //

+      // Validate the HiiHandle

+      // if validate failed, find the first validate parent HiiHandle.

+      //

+      if (!ValidateHiiHandle(Selection->Handle)) {

+        FindNextMenu (Selection, FormSetLevel);

+      }

+

+      //

+      // Initialize internal data structures of FormSet

+      //

+      Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);

+      if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {

+        DestroyFormSet (FormSet);

+        break;

+      }

+      Selection->FormSet = FormSet;

+      mSystemLevelFormSet = FormSet;

+

+      //

+      // Display this formset

+      //

+      gCurrentSelection = Selection;

+

+      Status = SetupBrowser (Selection);

+

+      gCurrentSelection = NULL;

+      mSystemLevelFormSet = NULL;

+

+      //

+      // If no data is changed, don't need to save current FormSet into the maintain list.

+      //

+      if (!IsNvUpdateRequiredForFormSet (FormSet)) {

+        CleanBrowserStorage(FormSet);

+        RemoveEntryList (&FormSet->Link);

+        DestroyFormSet (FormSet);

+      }

+

+      if (EFI_ERROR (Status)) {

+        break;

+      }

+    } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);

+

+    FreePool (Selection);

+  }

+

+  if (ActionRequest != NULL) {

+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;

+    if (gResetRequired) {

+      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;

+    }

+  }

+

+  mFormDisplay->ExitDisplay();

+

+  //

+  // Clear the menu history data.

+  //

+  while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {

+    MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);

+    RemoveEntryList (&MenuList->Link);

+    FreePool (MenuList);

+  }

+

+  //

+  // Restore globals used by SendForm()

+  //

+  RestoreBrowserContext ();

+

+  return Status;

+}

+

+/**

+  Get or set data to the storage.

+

+  @param  ResultsDataSize        The size of the buffer associatedwith ResultsData.

+  @param  ResultsData            A string returned from an IFR browser or

+                                 equivalent. The results string will have no

+                                 routing information in them.

+  @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve

+                                 (if RetrieveData = TRUE) data from the uncommitted

+                                 browser state information or set (if RetrieveData

+                                 = FALSE) data in the uncommitted browser state

+                                 information.

+  @param  Storage                The pointer to the storage.

+

+  @retval EFI_SUCCESS            The results have been distributed or are awaiting

+                                 distribution.

+

+**/

+EFI_STATUS 

+ProcessStorage (

+  IN OUT UINTN                         *ResultsDataSize,

+  IN OUT EFI_STRING                    *ResultsData,

+  IN BOOLEAN                           RetrieveData,

+  IN BROWSER_STORAGE                   *Storage

+  )

+{

+  CHAR16                *ConfigResp;

+  EFI_STATUS            Status;

+  CHAR16                *StrPtr;

+  UINTN                 BufferSize;

+  UINTN                 TmpSize;

+  FORMSET_STORAGE       *BrowserStorage;

+

+  if (RetrieveData) {

+    //

+    // Generate <ConfigResp>

+    //

+    Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    //

+    // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.

+    // Also need to consider add "\0" at first time.

+    //

+    StrPtr = StrStr (ConfigResp, L"PATH");

+    ASSERT (StrPtr != NULL);

+    StrPtr = StrStr (StrPtr, L"&");

+    StrPtr += 1;

+    BufferSize = StrSize (StrPtr);

+

+    //

+    // Copy the data if the input buffer is bigger enough.

+    //

+    if (*ResultsDataSize >= BufferSize) {

+      StrCpy (*ResultsData, StrPtr);

+    }

+

+    *ResultsDataSize = BufferSize;

+    FreePool (ConfigResp);

+  } else {

+    //

+    // Prepare <ConfigResp>

+    //

+    BrowserStorage = GetFstStgFromBrsStg (Storage);

+    ASSERT (BrowserStorage != NULL);

+    TmpSize = StrLen (*ResultsData);

+    BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);

+    ConfigResp = AllocateZeroPool (BufferSize);

+    ASSERT (ConfigResp != NULL);

+

+    StrCpy (ConfigResp, BrowserStorage->ConfigHdr);

+    StrCat (ConfigResp, L"&");

+    StrCat (ConfigResp, *ResultsData);

+

+    //

+    // Update Browser uncommited data

+    //

+    Status = ConfigRespToStorage (Storage, ConfigResp);

+    FreePool (ConfigResp);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  This routine called this service in the browser to retrieve or set certain uncommitted 

+  state information that resides in the open formsets. 

+

+  @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL

+                                 instance.

+  @param  ResultsDataSize        A pointer to the size of the buffer associated

+                                 with ResultsData.

+  @param  ResultsData            A string returned from an IFR browser or

+                                 equivalent. The results string will have no

+                                 routing information in them.

+  @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve

+                                 (if RetrieveData = TRUE) data from the uncommitted

+                                 browser state information or set (if RetrieveData

+                                 = FALSE) data in the uncommitted browser state

+                                 information.

+  @param  VariableGuid           An optional field to indicate the target variable

+                                 GUID name to use.

+  @param  VariableName           An optional field to indicate the target

+                                 human-readable variable name.

+

+  @retval EFI_SUCCESS            The results have been distributed or are awaiting

+                                 distribution.

+  @retval EFI_BUFFER_TOO_SMALL   The ResultsDataSize specified was too small to

+                                 contain the results data.

+

+**/

+EFI_STATUS

+EFIAPI

+BrowserCallback (

+  IN CONST EFI_FORM_BROWSER2_PROTOCOL  *This,

+  IN OUT UINTN                         *ResultsDataSize,

+  IN OUT EFI_STRING                    ResultsData,

+  IN BOOLEAN                           RetrieveData,

+  IN CONST EFI_GUID                    *VariableGuid, OPTIONAL

+  IN CONST CHAR16                      *VariableName  OPTIONAL

+  )

+{

+  EFI_STATUS            Status;

+  LIST_ENTRY            *Link;

+  BROWSER_STORAGE       *Storage;

+  FORMSET_STORAGE       *FormsetStorage;

+  UINTN                 TotalSize;

+  BOOLEAN               Found;

+

+  if (ResultsDataSize == NULL || ResultsData == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  TotalSize = *ResultsDataSize;

+  Storage   = NULL;

+  Found     = FALSE;

+  Status    = EFI_SUCCESS;

+

+  if (VariableGuid != NULL) {

+    //

+    // Try to find target storage in the current formset.

+    //

+    Link = GetFirstNode (&gBrowserStorageList);

+    while (!IsNull (&gBrowserStorageList, Link)) {

+      Storage = BROWSER_STORAGE_FROM_LINK (Link);

+      Link = GetNextNode (&gBrowserStorageList, Link);

+      //

+      // Check the current storage.

+      //

+      if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {

+        continue;

+      }

+

+      if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||

+          Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {

+        //

+        // Buffer storage require both GUID and Name

+        //

+        if (VariableName == NULL) {

+          return EFI_NOT_FOUND;

+        }

+

+        if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {

+          continue;

+        }

+      }

+

+      if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE ||

+          Storage->Type == EFI_HII_VARSTORE_BUFFER) {

+        if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) {

+          return EFI_NOT_FOUND;

+        }

+

+        if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {

+          continue;

+        }

+      }

+

+      Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+

+      if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {

+        ConfigRequestAdjust (Storage, ResultsData, TRUE);

+      }

+

+      //

+      // Different formsets may have same varstore, so here just set the flag

+      // not exit the circle.

+      // 

+      Found = TRUE;

+      break;

+    }

+

+    if (!Found) {

+      return EFI_NOT_FOUND;

+    }

+  } else {

+    //

+    // GUID/Name is not specified, take the first storage in FormSet

+    //

+    if (mSystemLevelFormSet == NULL) {

+      return EFI_NOT_READY;

+    }

+

+    //

+    // Generate <ConfigResp>

+    //

+    Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);

+    if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {

+      return EFI_UNSUPPORTED;

+    }

+

+    FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);

+    

+    Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  if (RetrieveData) {

+    Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;

+    *ResultsDataSize = TotalSize;

+  }

+   

+  return Status;

+

+}

+

+

+/**

+  Callback function for SimpleTextInEx protocol install events

+

+  @param Event           the event that is signaled.

+  @param Context         not used here.

+

+**/

+VOID

+EFIAPI

+FormDisplayCallback (

+  IN EFI_EVENT    Event,

+  IN VOID         *Context

+  )

+{

+  if (mFormDisplay != NULL) {

+    return;

+  }

+

+  gBS->LocateProtocol (

+                  &gEdkiiFormDisplayEngineProtocolGuid,

+                  NULL,

+                  (VOID **) &mFormDisplay

+                  );

+}

+

+/**

+  Initialize Setup Browser driver.

+

+  @param ImageHandle     The image handle.

+  @param SystemTable     The system table.

+

+  @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..

+  @return Other value if failed to initialize the Setup Browser module.

+

+**/

+EFI_STATUS

+EFIAPI

+InitializeSetup (

+  IN EFI_HANDLE           ImageHandle,

+  IN EFI_SYSTEM_TABLE     *SystemTable

+  )

+{

+  EFI_STATUS                  Status;

+  VOID                        *Registration;

+

+  //

+  // Locate required Hii relative protocols

+  //

+  Status = gBS->LocateProtocol (

+                  &gEfiHiiDatabaseProtocolGuid,

+                  NULL,

+                  (VOID **) &mHiiDatabase

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  Status = gBS->LocateProtocol (

+                  &gEfiHiiConfigRoutingProtocolGuid,

+                  NULL,

+                  (VOID **) &mHiiConfigRouting

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  Status = gBS->LocateProtocol (

+                  &gEfiDevicePathFromTextProtocolGuid,

+                  NULL,

+                  (VOID **) &mPathFromText

+                  );

+

+  //

+  // Install FormBrowser2 protocol

+  //

+  mPrivateData.Handle = NULL;

+  Status = gBS->InstallProtocolInterface (

+                  &mPrivateData.Handle,

+                  &gEfiFormBrowser2ProtocolGuid,

+                  EFI_NATIVE_INTERFACE,

+                  &mPrivateData.FormBrowser2

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  //

+  // Install FormBrowserEx2 protocol

+  //

+  InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);

+  InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);

+  mPrivateData.Handle = NULL;

+  Status = gBS->InstallProtocolInterface (

+                  &mPrivateData.Handle,

+                  &gEdkiiFormBrowserEx2ProtocolGuid,

+                  EFI_NATIVE_INTERFACE,

+                  &mPrivateData.FormBrowserEx2

+                  );

+  ASSERT_EFI_ERROR (Status);

+  

+  Status = gBS->InstallProtocolInterface (

+                  &mPrivateData.Handle,

+                  &gEfiFormBrowserExProtocolGuid,

+                  EFI_NATIVE_INTERFACE,

+                  &mPrivateData.FormBrowserEx

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  InitializeDisplayFormData ();

+

+  Status = gBS->LocateProtocol (

+                  &gEdkiiFormDisplayEngineProtocolGuid,

+                  NULL,

+                  (VOID **) &mFormDisplay

+                  );

+

+  if (EFI_ERROR (Status)) {

+    EfiCreateProtocolNotifyEvent (

+      &gEdkiiFormDisplayEngineProtocolGuid,

+      TPL_CALLBACK,

+      FormDisplayCallback,

+      NULL,

+      &Registration

+      );

+  }

+  

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Create a new string in HII Package List.

+

+  @param  String                 The String to be added

+  @param  HiiHandle              The package list in the HII database to insert the

+                                 specified string.

+

+  @return The output string.

+

+**/

+EFI_STRING_ID

+NewString (

+  IN  CHAR16                   *String,

+  IN  EFI_HII_HANDLE           HiiHandle

+  )

+{

+  EFI_STRING_ID  StringId;

+

+  StringId = HiiSetString (HiiHandle, 0, String, NULL);

+  ASSERT (StringId != 0);

+

+  return StringId;

+}

+

+

+/**

+  Delete a string from HII Package List.

+

+  @param  StringId               Id of the string in HII database.

+  @param  HiiHandle              The HII package list handle.

+

+  @retval EFI_SUCCESS            The string was deleted successfully.

+

+**/

+EFI_STATUS

+DeleteString (

+  IN  EFI_STRING_ID            StringId,

+  IN  EFI_HII_HANDLE           HiiHandle

+  )

+{

+  CHAR16  NullChar;

+

+  NullChar = CHAR_NULL;

+  HiiSetString (HiiHandle, StringId, &NullChar, NULL);

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Get the string based on the StringId and HII Package List Handle.

+

+  @param  Token                  The String's ID.

+  @param  HiiHandle              The package list in the HII database to search for

+                                 the specified string.

+

+  @return The output string.

+

+**/

+CHAR16 *

+GetToken (

+  IN  EFI_STRING_ID                Token,

+  IN  EFI_HII_HANDLE               HiiHandle

+  )

+{

+  EFI_STRING  String;

+

+  if (HiiHandle == NULL) {

+    return NULL;

+  }

+

+  String = HiiGetString (HiiHandle, Token, NULL);

+  if (String == NULL) {

+    String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);

+    ASSERT (String != NULL);

+  }

+  return (CHAR16 *) String;

+}

+

+

+/**

+  Allocate new memory and then copy the Unicode string Source to Destination.

+

+  @param  Dest                   Location to copy string

+  @param  Src                    String to copy

+

+**/

+VOID

+NewStringCpy (

+  IN OUT CHAR16       **Dest,

+  IN CHAR16           *Src

+  )

+{

+  if (*Dest != NULL) {

+    FreePool (*Dest);

+  }

+  *Dest = AllocateCopyPool (StrSize (Src), Src);

+  ASSERT (*Dest != NULL);

+}

+

+

+/**

+  Allocate new memory and concatinate Source on the end of Destination.

+

+  @param  Dest                   String to added to the end of.

+  @param  Src                    String to concatinate.

+

+**/

+VOID

+NewStringCat (

+  IN OUT CHAR16       **Dest,

+  IN CHAR16           *Src

+  )

+{

+  CHAR16  *NewString;

+  UINTN   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);

+

+  FreePool (*Dest);

+  *Dest = NewString;

+}

+

+/**

+  Get Value for given Name from a NameValue Storage.

+

+  @param  Storage                The NameValue Storage.

+  @param  Name                   The Name.

+  @param  Value                  The retured Value.

+  @param  GetValueFrom           Where to get source value, from EditValue or Value.

+

+  @retval EFI_SUCCESS            Value found for given Name.

+  @retval EFI_NOT_FOUND          No such Name found in NameValue storage.

+

+**/

+EFI_STATUS

+GetValueByName (

+  IN BROWSER_STORAGE             *Storage,

+  IN CHAR16                      *Name,

+  IN OUT CHAR16                  **Value,

+  IN GET_SET_QUESTION_VALUE_WITH GetValueFrom

+  )

+{

+  LIST_ENTRY              *Link;

+  NAME_VALUE_NODE         *Node;

+

+  if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  *Value = NULL;

+

+  Link = GetFirstNode (&Storage->NameValueListHead);

+  while (!IsNull (&Storage->NameValueListHead, Link)) {

+    Node = NAME_VALUE_NODE_FROM_LINK (Link);

+

+    if (StrCmp (Name, Node->Name) == 0) {

+      if (GetValueFrom == GetSetValueWithEditBuffer) {

+        NewStringCpy (Value, Node->EditValue);

+      } else {

+        NewStringCpy (Value, Node->Value);

+      }

+      return EFI_SUCCESS;

+    }

+

+    Link = GetNextNode (&Storage->NameValueListHead, Link);

+  }

+

+  return EFI_NOT_FOUND;

+}

+

+

+/**

+  Set Value of given Name in a NameValue Storage.

+

+  @param  Storage                The NameValue Storage.

+  @param  Name                   The Name.

+  @param  Value                  The Value to set.

+  @param  SetValueTo             Whether update editValue or Value.

+  @param  ReturnNode             The node use the input name.

+

+  @retval EFI_SUCCESS            Value found for given Name.

+  @retval EFI_NOT_FOUND          No such Name found in NameValue storage.

+

+**/

+EFI_STATUS

+SetValueByName (

+  IN  BROWSER_STORAGE             *Storage,

+  IN  CHAR16                      *Name,

+  IN  CHAR16                      *Value,

+  IN  GET_SET_QUESTION_VALUE_WITH SetValueTo,

+  OUT NAME_VALUE_NODE             **ReturnNode

+  )

+{

+  LIST_ENTRY              *Link;

+  NAME_VALUE_NODE         *Node;

+  CHAR16                  *Buffer;

+

+  if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  Link = GetFirstNode (&Storage->NameValueListHead);

+  while (!IsNull (&Storage->NameValueListHead, Link)) {

+    Node = NAME_VALUE_NODE_FROM_LINK (Link);

+

+    if (StrCmp (Name, Node->Name) == 0) {

+      if (SetValueTo == GetSetValueWithEditBuffer) {

+        Buffer = Node->EditValue;

+      } else {

+        Buffer = Node->Value;

+      }

+      if (Buffer != NULL) {

+        FreePool (Buffer);

+      }

+      Buffer = AllocateCopyPool (StrSize (Value), Value);

+      ASSERT (Buffer != NULL);

+      if (SetValueTo == GetSetValueWithEditBuffer) {

+        Node->EditValue = Buffer;

+      } else {

+        Node->Value = Buffer;

+      }

+

+      if (ReturnNode != NULL) {

+        *ReturnNode = Node;

+      }

+

+      return EFI_SUCCESS;

+    }

+

+    Link = GetNextNode (&Storage->NameValueListHead, Link);

+  }

+

+  return EFI_NOT_FOUND;

+}

+

+

+/**

+  Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.

+

+  @param  Storage                The Storage to be conveted.

+  @param  ConfigResp             The returned <ConfigResp>.

+  @param  ConfigRequest          The ConfigRequest string.

+  @param  GetEditBuf             Get the data from editbuffer or buffer.

+

+  @retval EFI_SUCCESS            Convert success.

+  @retval EFI_INVALID_PARAMETER  Incorrect storage type.

+

+**/

+EFI_STATUS

+StorageToConfigResp (

+  IN BROWSER_STORAGE         *Storage,

+  IN CHAR16                  **ConfigResp,

+  IN CHAR16                  *ConfigRequest,

+  IN BOOLEAN                 GetEditBuf

+  )

+{

+  EFI_STATUS              Status;

+  EFI_STRING              Progress;

+  LIST_ENTRY              *Link;

+  NAME_VALUE_NODE         *Node;

+  UINT8                   *SourceBuf;

+  FORMSET_STORAGE         *FormsetStorage;

+

+  Status = EFI_SUCCESS;

+

+  switch (Storage->Type) {

+  case EFI_HII_VARSTORE_BUFFER:

+  case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:

+    SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;

+    Status = mHiiConfigRouting->BlockToConfig (

+                                  mHiiConfigRouting,

+                                  ConfigRequest,

+                                  SourceBuf,

+                                  Storage->Size,

+                                  ConfigResp,

+                                  &Progress

+                                  );

+    break;

+

+  case EFI_HII_VARSTORE_NAME_VALUE:

+    *ConfigResp = NULL;

+    FormsetStorage = GetFstStgFromBrsStg(Storage);

+    ASSERT (FormsetStorage != NULL);

+    NewStringCat (ConfigResp, FormsetStorage->ConfigHdr);

+

+    Link = GetFirstNode (&Storage->NameValueListHead);

+    while (!IsNull (&Storage->NameValueListHead, Link)) {

+      Node = NAME_VALUE_NODE_FROM_LINK (Link);

+

+      if (StrStr (ConfigRequest, Node->Name) != NULL) {

+        NewStringCat (ConfigResp, L"&");

+        NewStringCat (ConfigResp, Node->Name);

+        NewStringCat (ConfigResp, L"=");

+        if (GetEditBuf) {

+          NewStringCat (ConfigResp, Node->EditValue);

+        } else {

+          NewStringCat (ConfigResp, Node->Value);

+        }

+      }

+      Link = GetNextNode (&Storage->NameValueListHead, Link);

+    }

+    break;

+

+  case EFI_HII_VARSTORE_EFI_VARIABLE:

+  default:

+    Status = EFI_INVALID_PARAMETER;

+    break;

+  }

+

+  return Status;

+}

+

+

+/**

+  Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.

+

+  @param  Storage                The Storage to receive the settings.

+  @param  ConfigResp             The <ConfigResp> to be converted.

+

+  @retval EFI_SUCCESS            Convert success.

+  @retval EFI_INVALID_PARAMETER  Incorrect storage type.

+

+**/

+EFI_STATUS

+ConfigRespToStorage (

+  IN BROWSER_STORAGE         *Storage,

+  IN CHAR16                  *ConfigResp

+  )

+{

+  EFI_STATUS  Status;

+  EFI_STRING  Progress;

+  UINTN       BufferSize;

+  CHAR16      *StrPtr;

+  CHAR16      *Name;

+  CHAR16      *Value;

+

+  Status = EFI_SUCCESS;

+

+  switch (Storage->Type) {

+  case EFI_HII_VARSTORE_BUFFER:

+  case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:

+    BufferSize = Storage->Size;

+    Status = mHiiConfigRouting->ConfigToBlock (

+                                  mHiiConfigRouting,

+                                  ConfigResp,

+                                  Storage->EditBuffer,

+                                  &BufferSize,

+                                  &Progress

+                                  );

+    break;

+

+  case EFI_HII_VARSTORE_NAME_VALUE:

+    StrPtr = StrStr (ConfigResp, L"PATH");

+    if (StrPtr == NULL) {

+      break;

+    }

+    StrPtr = StrStr (ConfigResp, L"&");

+    while (StrPtr != NULL) {

+      //

+      // Skip '&'

+      //

+      StrPtr = StrPtr + 1;

+      Name = StrPtr;

+      StrPtr = StrStr (StrPtr, L"=");

+      if (StrPtr == NULL) {

+        break;

+      }

+      *StrPtr = 0;

+

+      //

+      // Skip '='

+      //

+      StrPtr = StrPtr + 1;

+      Value = StrPtr;

+      StrPtr = StrStr (StrPtr, L"&");

+      if (StrPtr != NULL) {

+        *StrPtr = 0;

+      }

+      SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);

+    }

+    break;

+

+  case EFI_HII_VARSTORE_EFI_VARIABLE:

+  default:

+    Status = EFI_INVALID_PARAMETER;

+    break;

+  }

+

+  return Status;

+}

+

+/**

+  Convert the buffer value to HiiValue.

+

+  @param  Question               The question.

+  @param  Value                  Unicode buffer save the question value.

+

+  @retval  Status whether convert the value success.

+

+**/

+EFI_STATUS

+BufferToValue (

+  IN OUT FORM_BROWSER_STATEMENT           *Question,

+  IN     CHAR16                           *Value

+  )

+{

+  CHAR16                       *StringPtr;

+  BOOLEAN                      IsBufferStorage;

+  CHAR16                       *DstBuf;

+  CHAR16                       TempChar;

+  UINTN                        LengthStr;

+  UINT8                        *Dst;

+  CHAR16                       TemStr[5];

+  UINTN                        Index;

+  UINT8                        DigitUint8;

+  BOOLEAN                      IsString;

+  UINTN                        Length;

+  EFI_STATUS                   Status;

+

+  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);

+  if (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER || 

+      Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {

+    IsBufferStorage = TRUE;

+  } else {

+    IsBufferStorage = FALSE;

+  }

+

+  //

+  // Question Value is provided by Buffer Storage or NameValue Storage

+  //

+  if (Question->BufferValue != NULL) {

+    //

+    // This Question is password or orderedlist

+    //

+    Dst = Question->BufferValue;

+  } else {

+    //

+    // Other type of Questions

+    //

+    Dst = (UINT8 *) &Question->HiiValue.Value;

+  }

+

+  //

+  // Temp cut at the end of this section, end with '\0' or '&'.

+  //

+  StringPtr = Value;

+  while (*StringPtr != L'\0' && *StringPtr != L'&') {

+    StringPtr++;

+  }

+  TempChar = *StringPtr;

+  *StringPtr = L'\0';

+

+  LengthStr = StrLen (Value);

+  Status    = EFI_SUCCESS;

+  if (!IsBufferStorage && IsString) {

+    //

+    // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"

+    // Add string tail char L'\0' into Length

+    //

+    Length    = Question->StorageWidth + sizeof (CHAR16);

+    if (Length < ((LengthStr / 4 + 1) * 2)) {

+      Status = EFI_BUFFER_TOO_SMALL;

+    } else {

+      DstBuf = (CHAR16 *) Dst;

+      ZeroMem (TemStr, sizeof (TemStr));

+      for (Index = 0; Index < LengthStr; Index += 4) {

+        StrnCpy (TemStr, Value + Index, 4);

+        DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr);

+      }

+      //

+      // Add tailing L'\0' character

+      //

+      DstBuf[Index/4] = L'\0';

+    }

+  } else {

+    if (Question->StorageWidth < ((LengthStr + 1) / 2)) {

+      Status = EFI_BUFFER_TOO_SMALL;

+    } else {

+      ZeroMem (TemStr, sizeof (TemStr));

+      for (Index = 0; Index < LengthStr; Index ++) {

+        TemStr[0] = Value[LengthStr - Index - 1];

+        DigitUint8 = (UINT8) StrHexToUint64 (TemStr);

+        if ((Index & 1) == 0) {

+          Dst [Index/2] = DigitUint8;

+        } else {

+          Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);

+        }

+      }

+    }

+  }

+

+  *StringPtr = TempChar;

+

+  return Status;

+}

+

+/**

+  Get Question's current Value.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  Question               Question to be initialized.

+  @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+

+**/

+EFI_STATUS

+GetQuestionValue (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN OUT FORM_BROWSER_STATEMENT       *Question,

+  IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom

+  )

+{

+  EFI_STATUS          Status;

+  BOOLEAN             Enabled;

+  BOOLEAN             Pending;

+  UINT8               *Dst;

+  UINTN               StorageWidth;

+  EFI_TIME            EfiTime;

+  BROWSER_STORAGE     *Storage;

+  FORMSET_STORAGE     *FormsetStorage;

+  EFI_IFR_TYPE_VALUE  *QuestionValue;

+  CHAR16              *ConfigRequest;

+  CHAR16              *Progress;

+  CHAR16              *Result;

+  CHAR16              *Value;

+  UINTN               Length;

+  BOOLEAN             IsBufferStorage;

+

+  Status = EFI_SUCCESS;

+  Value  = NULL;

+  Result = NULL;

+

+  if (GetValueFrom >= GetSetValueWithMax) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Question value is provided by an Expression, evaluate it

+  //

+  if (Question->ValueExpression != NULL) {

+    Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);

+    if (!EFI_ERROR (Status)) {

+      if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {

+        ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);

+        if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {

+          CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);

+          Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;

+        } else {

+          CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);

+          Question->HiiValue.BufferLen = Question->StorageWidth;

+        }

+        FreePool (Question->ValueExpression->Result.Buffer);

+      }

+      Question->HiiValue.Type = Question->ValueExpression->Result.Type;

+      CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));      

+    }

+    return Status;

+  }

+  

+  //

+  // Get question value by read expression.

+  //

+  if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {

+    Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);

+    if (!EFI_ERROR (Status) && 

+      ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {

+      //

+      // Only update question value to the valid result.

+      //

+      if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {

+        ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);

+        if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {

+          CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);

+          Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;

+        } else {

+          CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);

+          Question->HiiValue.BufferLen = Question->StorageWidth;

+        }

+        FreePool (Question->ReadExpression->Result.Buffer);

+      }

+      Question->HiiValue.Type = Question->ReadExpression->Result.Type;

+      CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));       

+      return EFI_SUCCESS;

+    }

+  }

+

+  //

+  // Question value is provided by RTC

+  //

+  Storage = Question->Storage;

+  QuestionValue = &Question->HiiValue.Value;

+  if (Storage == NULL) {

+    //

+    // It's a Question without storage, or RTC date/time

+    //

+    if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {

+      //

+      // Date and time define the same Flags bit

+      //

+      switch (Question->Flags & EFI_QF_DATE_STORAGE) {

+      case QF_DATE_STORAGE_TIME:

+        Status = gRT->GetTime (&EfiTime, NULL);

+        break;

+

+      case QF_DATE_STORAGE_WAKEUP:

+        Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);

+        break;

+

+      case QF_DATE_STORAGE_NORMAL:

+      default:

+        //

+        // For date/time without storage

+        //

+        return EFI_SUCCESS;

+      }

+

+      if (EFI_ERROR (Status)) {

+        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;

+  }

+

+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 

+      Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {

+    IsBufferStorage = TRUE;

+  } else {

+    IsBufferStorage = FALSE;

+  }

+  if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {

+    if (IsBufferStorage) {

+      if (GetValueFrom == GetSetValueWithEditBuffer) {

+        //

+        // Copy from storage Edit buffer

+        //

+        CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);

+      } else {

+        //

+        // Copy from storage Edit buffer

+        //

+        CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);

+      }

+    } else {

+      Value = NULL;

+      Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+

+      ASSERT (Value != NULL);

+      Status = BufferToValue (Question, Value);

+      FreePool (Value);

+    }

+  } else {

+    FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);

+    ASSERT (FormsetStorage != NULL);

+    //

+    // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||

+    //                   <ConfigHdr> + "&" + <VariableName>

+    //

+    if (IsBufferStorage) {

+      Length = StrLen (FormsetStorage->ConfigHdr);

+      Length += StrLen (Question->BlockName);

+    } else {

+      Length = StrLen (FormsetStorage->ConfigHdr);

+      Length += StrLen (Question->VariableName) + 1;

+    }

+    ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));

+    ASSERT (ConfigRequest != NULL);

+

+    StrCpy (ConfigRequest, FormsetStorage->ConfigHdr);

+    if (IsBufferStorage) {

+      StrCat (ConfigRequest, Question->BlockName);

+    } else {

+      StrCat (ConfigRequest, L"&");

+      StrCat (ConfigRequest, Question->VariableName);

+    }

+

+    //

+    // Request current settings from Configuration Driver

+    //

+    Status = mHiiConfigRouting->ExtractConfig (

+                                      mHiiConfigRouting,

+                                      ConfigRequest,

+                                      &Progress,

+                                      &Result

+                                      );

+    FreePool (ConfigRequest);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    //

+    // Skip <ConfigRequest>

+    //

+    if (IsBufferStorage) {

+      Value = StrStr (Result, L"&VALUE");

+      if (Value == NULL) {

+        FreePool (Result);

+        return EFI_NOT_FOUND;

+      }

+      //

+      // Skip "&VALUE"

+      //

+      Value = Value + 6;

+    } else {

+      Value = Result + Length;

+    }

+    if (*Value != '=') {

+      FreePool (Result);

+      return EFI_NOT_FOUND;

+    }

+    //

+    // Skip '=', point to value

+    //

+    Value = Value + 1;

+

+    Status = BufferToValue (Question, Value);

+    if (EFI_ERROR (Status)) {

+      FreePool (Result);

+      return Status;

+    }

+

+    //

+    // Synchronize Edit Buffer

+    //

+    if (IsBufferStorage) {

+      CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);

+    } else {

+      SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);

+    }

+

+    if (Result != NULL) {

+      FreePool (Result);

+    }

+  }

+

+  return Status;

+}

+

+

+/**

+  Save Question Value to edit copy(cached) or Storage(uncached).

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  Question               Pointer to the Question.

+  @param  SetValueTo             Update the question value to editbuffer , buffer or hii driver.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+

+**/

+EFI_STATUS

+SetQuestionValue (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN OUT FORM_BROWSER_STATEMENT       *Question,

+  IN GET_SET_QUESTION_VALUE_WITH      SetValueTo

+  )

+{

+  EFI_STATUS          Status;

+  BOOLEAN             Enabled;

+  BOOLEAN             Pending;

+  UINT8               *Src;

+  EFI_TIME            EfiTime;

+  UINTN               BufferLen;

+  UINTN               StorageWidth;

+  BROWSER_STORAGE     *Storage;

+  FORMSET_STORAGE     *FormsetStorage;

+  EFI_IFR_TYPE_VALUE  *QuestionValue;

+  CHAR16              *ConfigResp;

+  CHAR16              *Progress;

+  CHAR16              *Value;

+  UINTN               Length;

+  BOOLEAN             IsBufferStorage;

+  BOOLEAN             IsString;

+  UINT8               *TemBuffer;

+  CHAR16              *TemName;

+  CHAR16              *TemString;

+  UINTN               Index;

+  NAME_VALUE_NODE     *Node;

+

+  Status = EFI_SUCCESS;

+  Node   = NULL;

+

+  if (SetValueTo >= GetSetValueWithMax) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // If Question value is provided by an Expression, then it is read only

+  //

+  if (Question->ValueExpression != NULL) {

+    return Status;

+  }

+  

+  //

+  // Before set question value, evaluate its write expression.

+  //

+  if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {

+    Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  //

+  // Question value is provided by RTC

+  //

+  Storage = Question->Storage;

+  QuestionValue = &Question->HiiValue.Value;

+  if (Storage == NULL) {

+    //

+    // It's a Question without storage, or RTC date/time

+    //

+    if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {

+      //

+      // Date and time define the same Flags bit

+      //

+      switch (Question->Flags & EFI_QF_DATE_STORAGE) {

+      case QF_DATE_STORAGE_TIME:

+        Status = gRT->GetTime (&EfiTime, NULL);

+        break;

+

+      case QF_DATE_STORAGE_WAKEUP:

+        Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);

+        break;

+

+      case QF_DATE_STORAGE_NORMAL:

+      default:

+        //

+        // For date/time without storage

+        //

+        return EFI_SUCCESS;

+      }

+

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+

+      if (Question->Operand == EFI_IFR_DATE_OP) {

+        EfiTime.Year  = QuestionValue->date.Year;

+        EfiTime.Month = QuestionValue->date.Month;

+        EfiTime.Day   = QuestionValue->date.Day;

+      } else {

+        EfiTime.Hour   = QuestionValue->time.Hour;

+        EfiTime.Minute = QuestionValue->time.Minute;

+        EfiTime.Second = QuestionValue->time.Second;

+      }

+

+      if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {

+        Status = gRT->SetTime (&EfiTime);

+      } else {

+        Status = gRT->SetWakeupTime (TRUE, &EfiTime);

+      }

+    }

+

+    return Status;

+  }

+

+  //

+  // Question value is provided by EFI variable

+  //

+  StorageWidth = Question->StorageWidth;

+  if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+    if (Question->BufferValue != NULL) {

+      Src = Question->BufferValue;

+    } else {

+      Src = (UINT8 *) QuestionValue;

+    }

+

+    Status = gRT->SetVariable (

+                     Question->VariableName,

+                     &Storage->Guid,

+                     Storage->Attributes,

+                     StorageWidth,

+                     Src

+                     );

+    return Status;

+  }

+

+  //

+  // Question Value is provided by Buffer Storage or NameValue Storage

+  //

+  if (Question->BufferValue != NULL) {

+    Src = Question->BufferValue;

+  } else {

+    Src = (UINT8 *) &Question->HiiValue.Value;

+  }

+

+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 

+      Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {

+    IsBufferStorage = TRUE;

+  } else {

+    IsBufferStorage = FALSE;

+  }

+  IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);

+

+  if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {

+    if (IsBufferStorage) {

+      if (SetValueTo == GetSetValueWithEditBuffer) {

+        //

+        // Copy to storage edit buffer

+        //      

+        CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);

+      } else if (SetValueTo == GetSetValueWithBuffer) {

+        //

+        // Copy to storage edit buffer

+        //     

+        CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);

+      }

+    } else {

+      if (IsString) {

+        //

+        // Allocate enough string buffer.

+        //

+        Value = NULL;

+        BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);

+        Value = AllocateZeroPool (BufferLen);

+        ASSERT (Value != NULL);

+        //

+        // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"

+        //

+        TemName = (CHAR16 *) Src;

+        TemString = Value;

+        for (; *TemName != L'\0'; TemName++) {

+          TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);

+        }

+      } else {

+        BufferLen = StorageWidth * 2 + 1;

+        Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));

+        ASSERT (Value != NULL);

+        //

+        // Convert Buffer to Hex String

+        //

+        TemBuffer = Src + StorageWidth - 1;

+        TemString = Value;

+        for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {

+          TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);

+        }

+      }

+

+      Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);

+      FreePool (Value);

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+    }

+  } else if (SetValueTo == GetSetValueWithHiiDriver) {

+    //

+    // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||

+    //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"

+    //

+    if (IsBufferStorage) {

+      Length = StrLen (Question->BlockName) + 7;

+    } else {

+      Length = StrLen (Question->VariableName) + 2;

+    }

+    if (!IsBufferStorage && IsString) {

+      Length += (StrLen ((CHAR16 *) Src) * 4);

+    } else {

+      Length += (StorageWidth * 2);

+    }

+    FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);

+    ASSERT (FormsetStorage != NULL);

+    ConfigResp = AllocateZeroPool ((StrLen (FormsetStorage->ConfigHdr) + Length + 1) * sizeof (CHAR16));

+    ASSERT (ConfigResp != NULL);

+

+    StrCpy (ConfigResp, FormsetStorage->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"

+      //

+      TemName = (CHAR16 *) Src;

+      TemString = Value;

+      for (; *TemName != L'\0'; TemName++) {

+        TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);

+      }

+    } else {

+      //

+      // Convert Buffer to Hex String

+      //

+      TemBuffer = Src + StorageWidth - 1;

+      TemString = Value;

+      for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {

+        TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);

+      }

+    }

+

+    //

+    // Convert to lower char.

+    //

+    for (TemString = Value; *Value != L'\0'; Value++) {

+      if (*Value >= L'A' && *Value <= L'Z') {

+        *Value = (CHAR16) (*Value - L'A' + L'a');

+      }

+    }

+

+    //

+    // Submit Question Value to Configuration Driver

+    //

+    Status = mHiiConfigRouting->RouteConfig (

+                                      mHiiConfigRouting,

+                                      ConfigResp,

+                                      &Progress

+                                      );

+    if (EFI_ERROR (Status)) {

+      FreePool (ConfigResp);

+      return Status;

+    }

+    FreePool (ConfigResp);

+    

+    //

+    // Sync storage, from editbuffer to buffer.

+    //

+    CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);

+  }

+

+  return Status;

+}

+

+

+/**

+  Perform nosubmitif check for a Form.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  Question               The Question to be validated.

+  @param  Type                   Validation type: NoSubmit

+

+  @retval EFI_SUCCESS            Form validation pass.

+  @retval other                  Form validation failed.

+

+**/

+EFI_STATUS

+ValidateQuestion (

+  IN  FORM_BROWSER_FORMSET            *FormSet,

+  IN  FORM_BROWSER_FORM               *Form,

+  IN  FORM_BROWSER_STATEMENT          *Question,

+  IN  UINTN                           Type

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  LIST_ENTRY              *ListHead;

+  FORM_EXPRESSION         *Expression;

+  UINT32                  BrowserStatus;

+  CHAR16                  *ErrorStr;

+

+  BrowserStatus = BROWSER_SUCCESS;

+  ErrorStr      = NULL;

+

+  switch (Type) {

+  case EFI_HII_EXPRESSION_INCONSISTENT_IF:

+    ListHead = &Question->InconsistentListHead;

+    break;

+

+  case EFI_HII_EXPRESSION_WARNING_IF:

+    ListHead = &Question->WarningListHead;

+    break;

+

+  case EFI_HII_EXPRESSION_NO_SUBMIT_IF:

+    ListHead = &Question->NoSubmitListHead;

+    break;

+

+  default:

+    ASSERT (FALSE);

+    return EFI_UNSUPPORTED;

+  }

+

+  Link = GetFirstNode (ListHead);

+  while (!IsNull (ListHead, Link)) {

+    Expression = FORM_EXPRESSION_FROM_LINK (Link);

+

+    //

+    // Evaluate the expression

+    //

+    Status = EvaluateExpression (FormSet, Form, Expression);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    if (IsTrue (&Expression->Result)) {

+      switch (Type) {

+      case EFI_HII_EXPRESSION_INCONSISTENT_IF:

+        BrowserStatus = BROWSER_INCONSISTENT_IF;

+        break;

+

+      case EFI_HII_EXPRESSION_WARNING_IF:

+        BrowserStatus = BROWSER_WARNING_IF;

+        break;

+

+      case EFI_HII_EXPRESSION_NO_SUBMIT_IF:

+        BrowserStatus = BROWSER_NO_SUBMIT_IF;

+        //

+        // This code only used to compatible with old display engine,

+        // New display engine will not use this field.

+        //

+        if (Expression->Error != 0) {

+          ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);

+        }

+        break;

+

+      default:

+        ASSERT (FALSE);

+        break;

+      }

+

+      if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {

+        //

+        // If in system submit process and for no_submit_if check, not popup this error message.

+        // Will process this fail again later in not system submit process.

+        //

+        PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);

+      }

+

+      if (ErrorStr != NULL) {

+        FreePool (ErrorStr);

+      }

+

+      if (Type == EFI_HII_EXPRESSION_WARNING_IF) {

+        return EFI_SUCCESS;

+      } else {

+        return EFI_NOT_READY;

+      }

+    }

+

+    Link = GetNextNode (ListHead, Link);

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Perform question check. 

+  

+  If one question has more than one check, process form high priority to low. 

+  Only one error info will be popup.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  Question               The Question to be validated.

+

+  @retval EFI_SUCCESS            Form validation pass.

+  @retval other                  Form validation failed.

+

+**/

+EFI_STATUS

+ValueChangedValidation (

+  IN  FORM_BROWSER_FORMSET            *FormSet,

+  IN  FORM_BROWSER_FORM               *Form,

+  IN  FORM_BROWSER_STATEMENT          *Question

+  )

+{

+  EFI_STATUS   Status;

+

+  Status = EFI_SUCCESS;

+

+  //

+  // Do the inconsistentif check.

+  //

+  if (!IsListEmpty (&Question->InconsistentListHead)) {

+    Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  //

+  // Do the warningif check.

+  //

+  if (!IsListEmpty (&Question->WarningListHead)) {

+    Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);

+  }

+

+  return Status;

+}

+

+/**

+  Perform NoSubmit check for each Form in FormSet.

+

+  @param  FormSet                FormSet data structure.

+  @param  CurrentForm            Current input form data structure.

+  @param  Statement              The statement for this check.

+

+  @retval EFI_SUCCESS            Form validation pass.

+  @retval other                  Form validation failed.

+

+**/

+EFI_STATUS

+NoSubmitCheck (

+  IN      FORM_BROWSER_FORMSET            *FormSet,

+  IN OUT  FORM_BROWSER_FORM               **CurrentForm,

+  OUT     FORM_BROWSER_STATEMENT          **Statement

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  FORM_BROWSER_STATEMENT  *Question;

+  FORM_BROWSER_FORM       *Form;

+  LIST_ENTRY              *LinkForm;

+

+  LinkForm = GetFirstNode (&FormSet->FormListHead);

+  while (!IsNull (&FormSet->FormListHead, LinkForm)) {

+    Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);

+    LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);

+

+    if (*CurrentForm != NULL && *CurrentForm != Form) {

+      continue;

+    }

+

+    Link = GetFirstNode (&Form->StatementListHead);

+    while (!IsNull (&Form->StatementListHead, Link)) {

+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);

+      Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);

+      if (EFI_ERROR (Status)) {

+        if (*CurrentForm == NULL) {

+          *CurrentForm = Form;

+        }

+        if (Statement != NULL) {

+          *Statement = Question;

+        }

+        return Status;

+      }

+

+      Link = GetNextNode (&Form->StatementListHead, Link);

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Fill storage's edit copy with settings requested from Configuration Driver.

+

+  @param  Storage                The storage which need to sync.

+  @param  ConfigRequest          The config request string which used to sync storage.

+  @param  SyncOrRestore          Sync the buffer to editbuffer or Restore  the 

+                                 editbuffer to buffer

+                                 if TRUE, copy the editbuffer to the buffer.

+                                 if FALSE, copy the buffer to the editbuffer.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+

+**/

+EFI_STATUS

+SynchronizeStorage (

+  OUT BROWSER_STORAGE             *Storage,

+  IN  CHAR16                      *ConfigRequest,

+  IN  BOOLEAN                     SyncOrRestore

+  )

+{

+  EFI_STATUS              Status;

+  EFI_STRING              Progress;

+  EFI_STRING              Result;

+  UINTN                   BufferSize;

+  LIST_ENTRY              *Link;

+  NAME_VALUE_NODE         *Node;

+  UINT8                   *Src;

+  UINT8                   *Dst;

+

+  Status = EFI_SUCCESS;

+  Result = NULL;

+

+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 

+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {

+    BufferSize = Storage->Size;

+

+    if (SyncOrRestore) {

+      Src = Storage->EditBuffer;

+      Dst = Storage->Buffer;

+    } else {

+      Src = Storage->Buffer;

+      Dst = Storage->EditBuffer;

+    }

+

+    if (ConfigRequest != NULL) {

+      Status = mHiiConfigRouting->BlockToConfig(

+                                    mHiiConfigRouting,

+                                    ConfigRequest,

+                                    Src,

+                                    BufferSize,

+                                    &Result,

+                                    &Progress

+                                    );

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+

+      Status = mHiiConfigRouting->ConfigToBlock (

+                                    mHiiConfigRouting,

+                                    Result,

+                                    Dst,

+                                    &BufferSize,

+                                    &Progress

+                                    );

+      if (Result != NULL) {

+        FreePool (Result);

+      }

+    } else {

+      CopyMem (Dst, Src, BufferSize);

+    }

+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    Link = GetFirstNode (&Storage->NameValueListHead);

+    while (!IsNull (&Storage->NameValueListHead, Link)) {

+      Node = NAME_VALUE_NODE_FROM_LINK (Link);

+

+      if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||

+          (ConfigRequest == NULL)) {

+        if (SyncOrRestore) {

+          NewStringCpy (&Node->Value, Node->EditValue);

+        } else {

+          NewStringCpy (&Node->EditValue, Node->Value);

+        }

+      }

+

+      Link = GetNextNode (&Storage->NameValueListHead, Link);

+    }

+  }

+

+  return Status;

+}

+

+/**

+  When discard the question value, call the callback function with Changed type

+  to inform the hii driver.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+

+**/

+VOID

+SendDiscardInfoToDriver (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form

+  )

+{

+  LIST_ENTRY                  *Link;

+  FORM_BROWSER_STATEMENT      *Question;

+  EFI_IFR_TYPE_VALUE          *TypeValue;

+  EFI_BROWSER_ACTION_REQUEST  ActionRequest;

+

+  if (FormSet->ConfigAccess == NULL) {

+    return;

+  }

+

+  Link = GetFirstNode (&Form->StatementListHead);

+  while (!IsNull (&Form->StatementListHead, Link)) {

+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);

+    Link = GetNextNode (&Form->StatementListHead, Link);

+

+    if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+      continue;

+    }

+

+    if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {

+      continue;

+    }

+

+    if (Question->Operand == EFI_IFR_PASSWORD_OP) {

+      continue;

+    }

+

+    if (!Question->ValueChanged) {

+      continue;

+    }

+

+    //

+    // Restore the question value before call the CHANGED callback type.

+    //

+    GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);

+

+    if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {

+      TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;

+    } else {

+      TypeValue = &Question->HiiValue.Value;

+    }

+

+    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;

+    FormSet->ConfigAccess->Callback (

+                             FormSet->ConfigAccess,

+                             EFI_BROWSER_ACTION_CHANGED,

+                             Question->QuestionId,

+                             Question->HiiValue.Type,

+                             TypeValue,

+                             &ActionRequest

+                             );

+  }

+}

+

+/**

+  Validate the HiiHandle.

+

+  @param  HiiHandle              The input HiiHandle which need to validate.

+

+  @retval TRUE                   The handle is validate.

+  @retval FALSE                  The handle is invalidate.

+

+**/

+BOOLEAN

+ValidateHiiHandle (

+  EFI_HII_HANDLE          HiiHandle

+  )

+{

+  EFI_HII_HANDLE          *HiiHandles;

+  UINTN                   Index;

+  BOOLEAN                 Find;

+

+  if (HiiHandle == NULL) {

+    return FALSE;

+  }

+

+  Find = FALSE;

+

+  HiiHandles = HiiGetHiiHandles (NULL);

+  ASSERT (HiiHandles != NULL);

+

+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {

+    if (HiiHandles[Index] == HiiHandle) {

+      Find = TRUE;

+      break;

+    }

+  }

+

+  FreePool (HiiHandles);

+

+  return Find;

+}

+

+/**

+  Validate the FormSet. If the formset is not validate, remove it from the list.

+

+  @param  FormSet                The input FormSet which need to validate.

+

+  @retval TRUE                   The handle is validate.

+  @retval FALSE                  The handle is invalidate.

+

+**/

+BOOLEAN

+ValidateFormSet (

+  FORM_BROWSER_FORMSET    *FormSet

+  )

+{

+  BOOLEAN  Find;

+

+  ASSERT (FormSet != NULL);

+

+  Find = ValidateHiiHandle(FormSet->HiiHandle);

+  //

+  // Should not remove the formset which is being used.

+  //

+  if (!Find && (FormSet != gCurrentSelection->FormSet)) {

+    CleanBrowserStorage(FormSet);

+    RemoveEntryList (&FormSet->Link);

+    DestroyFormSet (FormSet);

+  }

+

+  return Find;

+}

+/**

+  Check whether need to enable the reset flag in form level.

+  Also clean all ValueChanged flag in question.

+

+  @param  SetFlag                Whether need to set the Reset Flag.

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+

+**/

+VOID

+UpdateFlagForForm (

+  IN BOOLEAN                          SetFlag,

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form

+  )

+{

+  LIST_ENTRY              *Link;

+  FORM_BROWSER_STATEMENT  *Question;

+  BOOLEAN                 OldValue;

+

+  Link = GetFirstNode (&Form->StatementListHead);

+  while (!IsNull (&Form->StatementListHead, Link)) {

+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);

+    Link = GetNextNode (&Form->StatementListHead, Link);

+

+    if (!Question->ValueChanged) {

+      continue;

+    }

+

+    OldValue = Question->ValueChanged;

+

+    //

+    // Compare the buffer and editbuffer data to see whether the data has been saved.

+    //

+    Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);

+

+    //

+    // Only the changed data has been saved, then need to set the reset flag.

+    //

+    if (SetFlag && OldValue && !Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {

+      gResetRequired = TRUE;

+    } 

+  }

+}

+

+/**

+  Check whether need to enable the reset flag.

+  Also clean ValueChanged flag for all statements.

+

+  Form level or formset level, only one.

+  

+  @param  SetFlag                Whether need to set the Reset Flag.

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+

+**/

+VOID

+ValueChangeResetFlagUpdate (

+  IN BOOLEAN                          SetFlag,

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form  

+  )

+{

+  FORM_BROWSER_FORM       *CurrentForm;

+  LIST_ENTRY              *Link;

+

+  if (Form != NULL) {

+    UpdateFlagForForm(SetFlag, FormSet, Form);

+    return;

+  }

+

+  Link = GetFirstNode (&FormSet->FormListHead);

+  while (!IsNull (&FormSet->FormListHead, Link)) {

+    CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);

+    Link = GetNextNode (&FormSet->FormListHead, Link);

+

+    UpdateFlagForForm(SetFlag, FormSet, CurrentForm);

+  }

+}

+

+/**

+  Base on the return Progress string to find the form. 

+  

+  Base on the first return Offset/Width (Name) string to find the form

+  which keep this string.

+

+  @param  FormSet                FormSet data structure.

+  @param  Storage                Storage which has this Progress string.

+  @param  Progress               The Progress string which has the first fail string.

+  @param  RetForm                The return form for this progress string.

+  @param  RetQuestion            The return question for the error progress string.

+

+  @retval TRUE                   Find the error form and statement for this error progress string.

+  @retval FALSE                  Not find the error form.

+

+**/

+BOOLEAN

+FindQuestionFromProgress (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN BROWSER_STORAGE                  *Storage,

+  IN EFI_STRING                       Progress,

+  OUT FORM_BROWSER_FORM               **RetForm,

+  OUT FORM_BROWSER_STATEMENT          **RetQuestion

+  )

+{

+  LIST_ENTRY                   *Link;

+  LIST_ENTRY                   *LinkStorage;

+  LIST_ENTRY                   *LinkStatement;

+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;

+  FORM_BROWSER_FORM            *Form;

+  EFI_STRING                   EndStr;

+  FORM_BROWSER_STATEMENT       *Statement;

+

+  ASSERT ((*Progress == '&') || (*Progress == 'G'));

+

+  ConfigInfo   = NULL;

+  *RetForm     = NULL;

+  *RetQuestion = NULL;

+

+  //

+  // Skip the first "&" or the ConfigHdr part.

+  //

+  if (*Progress == '&') {

+    Progress++;

+  } else {

+    //

+    // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.

+    //

+    if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+      //

+      // For Name/Value type, Skip the ConfigHdr part.

+      //

+      EndStr = StrStr (Progress, L"PATH=");

+      ASSERT (EndStr != NULL);

+      while (*EndStr != '&') {

+        EndStr++;

+      }

+

+      *EndStr = '\0';

+    } else {

+      //

+      // For Buffer type, Skip the ConfigHdr part.

+      //

+      EndStr = StrStr (Progress, L"&OFFSET=");

+      ASSERT (EndStr != NULL);

+      *EndStr = '\0';

+    }

+

+    Progress = EndStr + 1;

+  }

+

+  //

+  // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.

+  //

+  if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    //

+    // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,

+    // here, just keep the "Fred" string.

+    //

+    EndStr = StrStr (Progress, L"=");

+    ASSERT (EndStr != NULL);

+    *EndStr = '\0';

+  } else {

+    //

+    // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",

+    // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.

+    //

+    EndStr = StrStr (Progress, L"&VALUE=");

+    ASSERT (EndStr != NULL);

+    *EndStr = '\0';

+  }

+

+  //

+  // Search in the form list.

+  //

+  Link = GetFirstNode (&FormSet->FormListHead);

+  while (!IsNull (&FormSet->FormListHead, Link)) {

+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);

+    Link = GetNextNode (&FormSet->FormListHead, Link);

+

+    //

+    // Search in the ConfigReqeust list in this form.

+    //

+    LinkStorage = GetFirstNode (&Form->ConfigRequestHead);

+    while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {

+      ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);

+      LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);

+

+      if (Storage != ConfigInfo->Storage) {

+        continue;

+      }

+

+      if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {

+        //

+        // Find the OffsetWidth string in this form.

+        //

+        *RetForm = Form;

+        break;

+      }

+    }

+

+    if (*RetForm != NULL) {

+      LinkStatement = GetFirstNode (&Form->StatementListHead);

+      while (!IsNull (&Form->StatementListHead, LinkStatement)) {

+        Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);

+        LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);

+

+        if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {

+          *RetQuestion = Statement;

+          break;

+        }

+

+        if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) {

+          *RetQuestion = Statement;

+          break;

+        }

+      }

+    }

+

+    if (*RetForm != NULL) {

+      break;

+    }

+  }

+

+  //

+  // restore the OffsetWidth string to the original format.

+  //

+  if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    *EndStr = '=';

+  } else {

+    *EndStr = '&';

+  }

+

+  return (BOOLEAN) (*RetForm != NULL);

+}

+

+/**

+  Popup an save error info and get user input.

+

+  @param  TitleId                The form title id.

+  @param  HiiHandle              The hii handle for this package.

+

+  @retval UINT32                 The user select option for the save fail.

+                                 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET

+**/

+UINT32

+ConfirmSaveFail (

+  IN EFI_STRING_ID    TitleId,

+  IN EFI_HII_HANDLE   HiiHandle

+  )

+{

+  CHAR16                  *FormTitle;

+  CHAR16                  *StringBuffer;

+  UINT32                  RetVal;

+

+  FormTitle = GetToken (TitleId, HiiHandle);

+

+  StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));

+  ASSERT (StringBuffer != NULL);

+

+  UnicodeSPrint (

+    StringBuffer, 

+    24 * sizeof (CHAR16) + StrSize (FormTitle), 

+    L"Submit Fail For Form: %s.", 

+    FormTitle

+    );

+

+  RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);

+

+  FreePool (StringBuffer);

+  FreePool (FormTitle);

+

+  return RetVal;

+}

+

+/**

+  Popup an NO_SUBMIT_IF error info and get user input.

+

+  @param  TitleId                The form title id.

+  @param  HiiHandle              The hii handle for this package.

+

+  @retval UINT32                 The user select option for the save fail.

+                                 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET

+**/

+UINT32

+ConfirmNoSubmitFail (

+  IN EFI_STRING_ID    TitleId,

+  IN EFI_HII_HANDLE   HiiHandle

+  )

+{

+  CHAR16                  *FormTitle;

+  CHAR16                  *StringBuffer;

+  UINT32                  RetVal;

+

+  FormTitle = GetToken (TitleId, HiiHandle);

+

+  StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));

+  ASSERT (StringBuffer != NULL);

+

+  UnicodeSPrint (

+    StringBuffer, 

+    24 * sizeof (CHAR16) + StrSize (FormTitle), 

+    L"NO_SUBMIT_IF error For Form: %s.", 

+    FormTitle

+    );

+

+  RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);

+

+  FreePool (StringBuffer);

+  FreePool (FormTitle);

+

+  return RetVal;

+}

+

+/**

+  Discard data based on the input setting scope (Form, FormSet or System).

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  SettingScope           Setting Scope for Discard action.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

+

+**/

+EFI_STATUS

+DiscardForm (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN BROWSER_SETTING_SCOPE            SettingScope

+  )

+{

+  LIST_ENTRY                   *Link;

+  FORMSET_STORAGE              *Storage;

+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;

+  FORM_BROWSER_FORMSET         *LocalFormSet;

+  FORM_BROWSER_FORMSET         *OldFormSet;

+

+  //

+  // Check the supported setting level.

+  //

+  if (SettingScope >= MaxLevel) {

+    return EFI_UNSUPPORTED;

+  }

+

+  if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {

+    ConfigInfo = NULL;

+    Link = GetFirstNode (&Form->ConfigRequestHead);

+    while (!IsNull (&Form->ConfigRequestHead, Link)) {

+      ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);

+      Link = GetNextNode (&Form->ConfigRequestHead, Link);

+

+      if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+        continue;

+      }

+

+      //

+      // Skip if there is no RequestElement

+      //

+      if (ConfigInfo->ElementCount == 0) {

+        continue;

+      }

+

+      //

+      // Prepare <ConfigResp>

+      //

+      SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);

+

+      //

+      // Call callback with Changed type to inform the driver.

+      //

+      SendDiscardInfoToDriver (FormSet, Form);

+    }

+

+    ValueChangeResetFlagUpdate (FALSE, FormSet, Form);

+  } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {

+

+    //

+    // Discard Buffer storage or Name/Value storage

+    //

+    Link = GetFirstNode (&FormSet->StorageListHead);

+    while (!IsNull (&FormSet->StorageListHead, Link)) {

+      Storage = FORMSET_STORAGE_FROM_LINK (Link);

+      Link = GetNextNode (&FormSet->StorageListHead, Link);

+

+      if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+        continue;

+      }

+

+      //

+      // Skip if there is no RequestElement

+      //

+      if (Storage->ElementCount == 0) {

+        continue;

+      }

+

+      SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);

+    }

+

+    Link = GetFirstNode (&FormSet->FormListHead);

+    while (!IsNull (&FormSet->FormListHead, Link)) {

+      Form = FORM_BROWSER_FORM_FROM_LINK (Link);

+      Link = GetNextNode (&FormSet->FormListHead, Link);

+      

+      //

+      // Call callback with Changed type to inform the driver.

+      //

+      SendDiscardInfoToDriver (FormSet, Form);

+    }

+

+    ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);

+  } else if (SettingScope == SystemLevel) {

+    //

+    // System Level Discard.

+    //

+    OldFormSet = mSystemLevelFormSet;

+

+    //

+    // Discard changed value for each FormSet in the maintain list.

+    //

+    Link = GetFirstNode (&gBrowserFormSetList);

+    while (!IsNull (&gBrowserFormSetList, Link)) {

+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);

+      Link = GetNextNode (&gBrowserFormSetList, Link);

+      if (!ValidateFormSet(LocalFormSet)) {

+        continue;

+      }

+

+      mSystemLevelFormSet = LocalFormSet;

+

+      DiscardForm (LocalFormSet, NULL, FormSetLevel);

+      if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {

+        //

+        // Remove maintain backup list after discard except for the current using FormSet.

+        //

+        CleanBrowserStorage(LocalFormSet);

+        RemoveEntryList (&LocalFormSet->Link);

+        DestroyFormSet (LocalFormSet);

+      }

+    }

+

+    mSystemLevelFormSet = OldFormSet;

+  }

+

+  return EFI_SUCCESS;  

+}

+

+/**

+  Submit data for a form.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

+

+**/

+EFI_STATUS

+SubmitForForm (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  EFI_STRING              ConfigResp;

+  EFI_STRING              Progress;

+  BROWSER_STORAGE         *Storage;

+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;

+

+  if (!IsNvUpdateRequiredForForm (Form)) {

+    return EFI_SUCCESS;

+  }

+

+  Status = NoSubmitCheck (FormSet, &Form, NULL);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Link = GetFirstNode (&Form->ConfigRequestHead);

+  while (!IsNull (&Form->ConfigRequestHead, Link)) {

+    ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);

+    Link = GetNextNode (&Form->ConfigRequestHead, Link);

+

+    Storage = ConfigInfo->Storage;

+    if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+      continue;

+    }

+

+    //

+    // Skip if there is no RequestElement

+    //

+    if (ConfigInfo->ElementCount == 0) {

+      continue;

+    }

+

+    //

+    // 1. Prepare <ConfigResp>

+    //

+    Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    //

+    // 2. Set value to hii config routine protocol.

+    //

+    Status = mHiiConfigRouting->RouteConfig (

+                                      mHiiConfigRouting,

+                                      ConfigResp,

+                                      &Progress

+                                      );

+    FreePool (ConfigResp);

+

+    if (EFI_ERROR (Status)) {

+      InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);

+      continue;

+    }

+

+    //

+    // 3. Config success, update storage shadow Buffer, only update the data belong to this form.

+    //

+    SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);

+  }

+

+  //

+  // 4. Process the save failed storage.

+  //

+  if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {

+    if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {

+      Link = GetFirstNode (&gBrowserSaveFailFormSetList);

+      while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {

+        ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);

+        Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);

+

+        SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);

+

+        Status = EFI_SUCCESS;

+      }

+    } else {

+      Status = EFI_UNSUPPORTED;

+    }

+

+    //

+    // Free Form save fail list.

+    //

+    while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {

+      Link = GetFirstNode (&gBrowserSaveFailFormSetList);

+      ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);

+      RemoveEntryList (&ConfigInfo->SaveFailLink);

+    }

+  }

+

+  //

+  // 5. Update the NV flag.

+  //

+  ValueChangeResetFlagUpdate(TRUE, FormSet, Form);

+

+  return Status;

+}

+

+/**

+  Submit data for a formset.

+

+  @param  FormSet                FormSet data structure.

+  @param  SkipProcessFail        Whether skip to process the save failed storage.

+                                 If submit formset is called when do system level save, 

+                                 set this value to true and process the failed formset 

+                                 together. 

+                                 if submit formset is called when do formset level save,

+                                 set the value to false and process the failed storage

+                                 right after process all storages for this formset.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

+

+**/

+EFI_STATUS

+SubmitForFormSet (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN BOOLEAN                          SkipProcessFail

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  EFI_STRING              ConfigResp;

+  EFI_STRING              Progress;

+  BROWSER_STORAGE         *Storage;

+  FORMSET_STORAGE         *FormSetStorage;

+  FORM_BROWSER_FORM       *Form;

+  BOOLEAN                 HasInserted;

+  FORM_BROWSER_STATEMENT  *Question;

+

+  HasInserted = FALSE;

+

+  if (!IsNvUpdateRequiredForFormSet (FormSet)) {

+    return EFI_SUCCESS;

+  }

+

+  Form = NULL; 

+  Status = NoSubmitCheck (FormSet, &Form, &Question);

+  if (EFI_ERROR (Status)) {

+    if (SkipProcessFail) {

+      //

+      // Process NO_SUBMIT check first, so insert it at head.

+      //

+      FormSet->SaveFailForm = Form;

+      FormSet->SaveFailStatement = Question;

+      InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);

+    }

+

+    return Status;

+  }

+

+  Form = NULL;

+  Question = NULL;

+  //

+  // Submit Buffer storage or Name/Value storage

+  //

+  Link = GetFirstNode (&FormSet->StorageListHead);

+  while (!IsNull (&FormSet->StorageListHead, Link)) {

+    FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);

+    Storage        = FormSetStorage->BrowserStorage;

+    Link = GetNextNode (&FormSet->StorageListHead, Link);

+

+    if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+      continue;

+    }

+

+    //

+    // Skip if there is no RequestElement

+    //

+    if (FormSetStorage->ElementCount == 0) {

+      continue;

+    }

+

+    //

+    // 1. Prepare <ConfigResp>

+    //

+    Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    //

+    // 2. Send <ConfigResp> to Routine config Protocol.

+    //

+    Status = mHiiConfigRouting->RouteConfig (

+                                      mHiiConfigRouting,

+                                      ConfigResp,

+                                      &Progress

+                                      );

+    if (EFI_ERROR (Status)) {

+      InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);

+      if (!HasInserted) {

+        //

+        // Call submit formset for system level, save the formset info

+        // and process later.

+        //

+        FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);

+        ASSERT (Form != NULL && Question != NULL);

+        FormSet->SaveFailForm = Form;

+        FormSet->SaveFailStatement = Question;

+        if (SkipProcessFail) {

+          InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);

+        }

+        HasInserted = TRUE;

+      }

+

+      FreePool (ConfigResp);

+      continue;

+    }

+

+    FreePool (ConfigResp);

+    //

+    // 3. Config success, update storage shadow Buffer

+    //

+    SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);

+  }

+

+  //

+  // 4. Has save fail storage need to handle.

+  //

+  if (Form != NULL) {

+    if (!SkipProcessFail) {

+      //

+      // If not in system level, just handl the save failed storage here.

+      //

+      if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {

+        Link = GetFirstNode (&FormSet->SaveFailStorageListHead);

+        while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {

+          FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);

+          Storage        = FormSetStorage->BrowserStorage;

+          Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);

+

+          SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);

+

+          Status = EFI_SUCCESS;

+        }

+      } else {

+        UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);

+

+        gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;

+        gCurrentSelection->Handle = FormSet->HiiHandle;

+        CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);

+        gCurrentSelection->FormId = Form->FormId;

+        gCurrentSelection->QuestionId = Question->QuestionId;

+

+        Status = EFI_UNSUPPORTED;

+      }

+

+      //

+      // Free FormSet save fail list.

+      //

+      while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {

+        Link = GetFirstNode (&FormSet->SaveFailStorageListHead);

+        FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);

+        RemoveEntryList (&FormSetStorage->SaveFailLink);

+      }

+    } else {

+      //

+      // If in system level, just return error and handle the failed formset later.

+      //

+      Status = EFI_UNSUPPORTED;

+    }

+  }

+

+  //

+  // 5. Update the NV flag.

+  // 

+  ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);

+

+  return Status;

+}

+

+/**

+  Submit data for all formsets.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

+

+**/

+EFI_STATUS

+SubmitForSystem (

+  VOID

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  LIST_ENTRY              *StorageLink;

+  FORMSET_STORAGE         *FormSetStorage;

+  FORM_BROWSER_FORM       *Form;

+  FORM_BROWSER_FORMSET    *LocalFormSet;

+  UINT32                  UserSelection;

+  FORM_BROWSER_STATEMENT  *Question;

+

+  mSystemSubmit = TRUE;

+  Link = GetFirstNode (&gBrowserFormSetList);

+  while (!IsNull (&gBrowserFormSetList, Link)) {

+    LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);

+    Link = GetNextNode (&gBrowserFormSetList, Link);

+    if (!ValidateFormSet(LocalFormSet)) {

+      continue;

+    }

+

+    Status = SubmitForFormSet (LocalFormSet, TRUE);

+    if (EFI_ERROR (Status)) {

+      continue;

+    }

+

+    //

+    // Remove maintain backup list after save except for the current using FormSet.

+    //  

+    if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {

+      CleanBrowserStorage(LocalFormSet);

+      RemoveEntryList (&LocalFormSet->Link);

+      DestroyFormSet (LocalFormSet);

+    }

+  }

+  mSystemSubmit = FALSE;

+

+  Status = EFI_SUCCESS;

+

+  //

+  // Process the save failed formsets.

+  //

+  Link = GetFirstNode (&gBrowserSaveFailFormSetList);

+  while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {

+    LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);

+    Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);

+

+    if (!ValidateFormSet(LocalFormSet)) {

+      continue;

+    }

+

+    Form = LocalFormSet->SaveFailForm;

+    Question= LocalFormSet->SaveFailStatement;

+

+    //

+    // Confirm with user, get user input.

+    //

+    if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {

+      //

+      // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.

+      //

+      UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);

+    } else {

+      UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);

+    }

+

+    if (UserSelection == BROWSER_ACTION_DISCARD) {

+      if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {

+        StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);

+        while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {

+          FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);

+          StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);

+

+          SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);

+        }

+      } else {

+        StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);

+        while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {

+          FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);

+          StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);

+

+          SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);

+        }

+      }

+

+      if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {

+        CleanBrowserStorage(LocalFormSet);

+        RemoveEntryList (&LocalFormSet->Link);

+        RemoveEntryList (&LocalFormSet->SaveFailLink);

+        DestroyFormSet (LocalFormSet);

+      } else {

+        ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);

+      }

+    } else {

+      if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {

+        NoSubmitCheck (LocalFormSet, &Form, &Question);

+      }

+

+      UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);

+

+      gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;

+      gCurrentSelection->Handle = LocalFormSet->HiiHandle;

+      CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);

+      gCurrentSelection->FormId = Form->FormId;

+      gCurrentSelection->QuestionId = Question->QuestionId;

+

+      Status = EFI_UNSUPPORTED;

+      break;

+    }

+  }

+

+  //

+  // Clean the list which will not process.

+  //

+  while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {

+    Link = GetFirstNode (&gBrowserSaveFailFormSetList);

+    LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);

+    RemoveEntryList (&LocalFormSet->SaveFailLink);

+

+    while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {

+      StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);

+      FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);

+      RemoveEntryList (&FormSetStorage->SaveFailLink);

+    }

+  }

+

+  return Status;

+}

+

+/**

+  Submit data based on the input Setting level (Form, FormSet or System).

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  SettingScope           Setting Scope for Submit action.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

+

+**/

+EFI_STATUS

+SubmitForm (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN BROWSER_SETTING_SCOPE            SettingScope

+  )

+{

+  EFI_STATUS              Status;

+

+  switch (SettingScope) {

+  case FormLevel:

+    Status = SubmitForForm(FormSet, Form);

+    break;

+

+  case FormSetLevel:

+    Status = SubmitForFormSet (FormSet, FALSE);

+    break;

+

+  case SystemLevel:

+    Status = SubmitForSystem ();

+    break;

+

+  default:

+    Status = EFI_UNSUPPORTED;

+    break;

+  }

+

+  return Status;

+}

+

+/**

+  Converts the unicode character of the string from uppercase to lowercase.

+  This is a internal function.

+

+  @param ConfigString  String to be converted

+

+**/

+VOID

+EFIAPI

+HiiToLower (

+  IN EFI_STRING  ConfigString

+  )

+{

+  EFI_STRING  String;

+  BOOLEAN     Lower;

+

+  ASSERT (ConfigString != NULL);

+

+  //

+  // Convert all hex digits in range [A-F] in the configuration header to [a-f]

+  //

+  for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {

+    if (*String == L'=') {

+      Lower = TRUE;

+    } else if (*String == L'&') {

+      Lower = FALSE;

+    } else if (Lower && *String >= L'A' && *String <= L'F') {

+      *String = (CHAR16) (*String - L'A' + L'a');

+    }

+  }

+}

+

+/**

+  Find the point in the ConfigResp string for this question.

+

+  @param  Question               The question.

+  @param  ConfigResp             Get ConfigResp string.

+

+  @retval  point to the offset where is for this question.

+

+**/

+CHAR16 *

+GetOffsetFromConfigResp (

+  IN FORM_BROWSER_STATEMENT           *Question,

+  IN CHAR16                           *ConfigResp

+  )

+{

+  CHAR16                       *RequestElement;

+  CHAR16                       *BlockData;

+

+  //

+  // Type is EFI_HII_VARSTORE_NAME_VALUE.

+  //

+  if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    RequestElement = StrStr (ConfigResp, Question->VariableName);

+    if (RequestElement != NULL) {

+      //

+      // Skip the "VariableName=" field.

+      //

+      RequestElement += StrLen (Question->VariableName) + 1;

+    }

+

+    return RequestElement;

+  }

+

+  //

+  // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER

+  //

+

+  //

+  // 1. Directly use Question->BlockName to find.

+  //

+  RequestElement = StrStr (ConfigResp, Question->BlockName);

+  if (RequestElement != NULL) {

+    //

+    // Skip the "Question->BlockName&VALUE=" field.

+    //

+    RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");

+    return RequestElement;

+  }

+  

+  //

+  // 2. Change all hex digits in Question->BlockName to lower and compare again.

+  //

+  BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName);

+  ASSERT (BlockData != NULL);

+  HiiToLower (BlockData);

+  RequestElement = StrStr (ConfigResp, BlockData);

+  FreePool (BlockData);

+

+  if (RequestElement != NULL) {

+    //

+    // Skip the "Question->BlockName&VALUE=" field.

+    //

+    RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");

+  }

+

+  return RequestElement;

+}

+

+/**

+  Get Question default value from AltCfg string.

+

+  @param  FormSet                The form set.

+  @param  Form                   The form

+  @param  Question               The question.

+

+  @retval EFI_SUCCESS            Question is reset to default value.

+

+**/

+EFI_STATUS

+GetDefaultValueFromAltCfg (

+  IN     FORM_BROWSER_FORMSET             *FormSet,

+  IN     FORM_BROWSER_FORM                *Form,

+  IN OUT FORM_BROWSER_STATEMENT           *Question

+  )

+{ 

+  BROWSER_STORAGE              *Storage;

+  FORMSET_STORAGE              *FormSetStorage;

+  CHAR16                       *ConfigResp;

+  CHAR16                       *Value;

+  LIST_ENTRY                   *Link;

+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;

+

+  Storage = Question->Storage;

+  if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {

+    return EFI_NOT_FOUND;

+  }

+

+  //

+  // Try to get AltCfg string from form. If not found it, then

+  // try to get it from formset.

+  //

+  ConfigResp    = NULL;

+  Link = GetFirstNode (&Form->ConfigRequestHead);

+  while (!IsNull (&Form->ConfigRequestHead, Link)) {

+    ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);

+    Link = GetNextNode (&Form->ConfigRequestHead, Link);

+

+    if (Storage == ConfigInfo->Storage) {

+      ConfigResp = ConfigInfo->ConfigAltResp;

+      break;

+    }

+  }

+

+  if (ConfigResp == NULL) {

+    Link = GetFirstNode (&FormSet->StorageListHead);

+    while (!IsNull (&FormSet->StorageListHead, Link)) {

+      FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);

+      Link = GetNextNode (&FormSet->StorageListHead, Link);

+

+      if (Storage == FormSetStorage->BrowserStorage) {

+        ConfigResp = FormSetStorage->ConfigAltResp;

+        break;

+      }

+    }

+  }

+

+  if (ConfigResp == NULL) {

+    return EFI_NOT_FOUND;

+  }

+

+  Value = GetOffsetFromConfigResp (Question, ConfigResp);

+  if (Value == NULL) {

+    return EFI_NOT_FOUND;

+  }

+

+  return BufferToValue (Question, Value);

+}

+

+/**

+  Get default Id value used for browser.

+

+  @param  DefaultId              The default id value used by hii.

+

+  @retval Browser used default value.

+

+**/

+INTN

+GetDefaultIdForCallBack (

+  UINTN DefaultId

+  )

+{ 

+  if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {

+    return EFI_BROWSER_ACTION_DEFAULT_STANDARD;

+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {

+    return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;

+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {

+    return EFI_BROWSER_ACTION_DEFAULT_SAFE;

+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {

+    return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;

+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {

+    return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;

+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {

+    return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;

+  } else {

+    return -1;

+  }

+}

+

+

+

+/**

+  Return data element in an Array by its Index.

+

+  @param  Array                  The data array.

+  @param  Type                   Type of the data in this array.

+  @param  Index                  Zero based index for data in this array.

+

+  @retval Value                  The data to be returned

+

+**/

+UINT64

+GetArrayData (

+  IN VOID                     *Array,

+  IN UINT8                    Type,

+  IN UINTN                    Index

+  )

+{

+  UINT64 Data;

+

+  ASSERT (Array != NULL);

+

+  Data = 0;

+  switch (Type) {

+  case EFI_IFR_TYPE_NUM_SIZE_8:

+    Data = (UINT64) *(((UINT8 *) Array) + Index);

+    break;

+

+  case EFI_IFR_TYPE_NUM_SIZE_16:

+    Data = (UINT64) *(((UINT16 *) Array) + Index);

+    break;

+

+  case EFI_IFR_TYPE_NUM_SIZE_32:

+    Data = (UINT64) *(((UINT32 *) Array) + Index);

+    break;

+

+  case EFI_IFR_TYPE_NUM_SIZE_64:

+    Data = (UINT64) *(((UINT64 *) Array) + Index);

+    break;

+

+  default:

+    break;

+  }

+

+  return Data;

+}

+

+

+/**

+  Set value of a data element in an Array by its Index.

+

+  @param  Array                  The data array.

+  @param  Type                   Type of the data in this array.

+  @param  Index                  Zero based index for data in this array.

+  @param  Value                  The value to be set.

+

+**/

+VOID

+SetArrayData (

+  IN VOID                     *Array,

+  IN UINT8                    Type,

+  IN UINTN                    Index,

+  IN UINT64                   Value

+  )

+{

+

+  ASSERT (Array != NULL);

+

+  switch (Type) {

+  case EFI_IFR_TYPE_NUM_SIZE_8:

+    *(((UINT8 *) Array) + Index) = (UINT8) Value;

+    break;

+

+  case EFI_IFR_TYPE_NUM_SIZE_16:

+    *(((UINT16 *) Array) + Index) = (UINT16) Value;

+    break;

+

+  case EFI_IFR_TYPE_NUM_SIZE_32:

+    *(((UINT32 *) Array) + Index) = (UINT32) Value;

+    break;

+

+  case EFI_IFR_TYPE_NUM_SIZE_64:

+    *(((UINT64 *) Array) + Index) = (UINT64) Value;

+    break;

+

+  default:

+    break;

+  }

+}

+

+/**

+  Search an Option of a Question by its value.

+

+  @param  Question               The Question

+  @param  OptionValue            Value for Option to be searched.

+

+  @retval Pointer                Pointer to the found Option.

+  @retval NULL                   Option not found.

+

+**/

+QUESTION_OPTION *

+ValueToOption (

+  IN FORM_BROWSER_STATEMENT   *Question,

+  IN EFI_HII_VALUE            *OptionValue

+  )

+{

+  LIST_ENTRY       *Link;

+  QUESTION_OPTION  *Option;

+  INTN             Result;

+

+  Link = GetFirstNode (&Question->OptionListHead);

+  while (!IsNull (&Question->OptionListHead, Link)) {

+    Option = QUESTION_OPTION_FROM_LINK (Link);

+

+    if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {

+      //

+      // Check the suppressif condition, only a valid option can be return.

+      //

+      if ((Option->SuppressExpression == NULL) ||

+          ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {

+        return Option;

+      }

+    }

+

+    Link = GetNextNode (&Question->OptionListHead, Link);

+  }

+

+  return NULL;

+}

+

+

+/**

+  Reset Question to its default value.

+

+  @param  FormSet                The form set.

+  @param  Form                   The form.

+  @param  Question               The question.

+  @param  DefaultId              The Class of the default.

+

+  @retval EFI_SUCCESS            Question is reset to default value.

+

+**/

+EFI_STATUS

+GetQuestionDefault (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN FORM_BROWSER_STATEMENT           *Question,

+  IN UINT16                           DefaultId

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  QUESTION_DEFAULT        *Default;

+  QUESTION_OPTION         *Option;

+  EFI_HII_VALUE           *HiiValue;

+  UINT8                   Index;

+  EFI_STRING              StrValue;

+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;

+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;

+  INTN                            Action;

+  CHAR16                          *NewString;

+

+  Status   = EFI_NOT_FOUND;

+  StrValue = NULL;

+

+  //

+  // Statement don't have storage, skip them

+  //

+  if (Question->QuestionId == 0) {

+    return Status;

+  }

+

+  //

+  // There are Five ways to specify default value for a Question:

+  //  1, use call back function (highest priority)

+  //  2, use ExtractConfig function

+  //  3, use nested EFI_IFR_DEFAULT 

+  //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)

+  //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)

+  //

+  HiiValue = &Question->HiiValue;

+

+  //

+  // Get Question defaut value from call back function.

+  //

+  ConfigAccess = FormSet->ConfigAccess;

+  Action = GetDefaultIdForCallBack (DefaultId);

+  if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {

+    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;

+    Status = ConfigAccess->Callback (

+                             ConfigAccess,

+                             Action,

+                             Question->QuestionId,

+                             HiiValue->Type,

+                             &HiiValue->Value,

+                             &ActionRequest

+                             );

+    if (!EFI_ERROR (Status)) {

+      if (HiiValue->Type == EFI_IFR_TYPE_STRING) {

+        NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);

+        ASSERT (NewString != NULL);

+

+        ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);

+        if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {

+          CopyMem (Question->BufferValue, NewString, StrSize (NewString));

+        } else {

+          CopyMem (Question->BufferValue, NewString, Question->StorageWidth);

+        }

+

+        FreePool (NewString);

+      }

+      return Status;

+    }

+  }

+

+  //

+  // Get default value from altcfg string.

+  //

+  if (ConfigAccess != NULL) {  

+    Status = GetDefaultValueFromAltCfg(FormSet, Form, Question);

+    if (!EFI_ERROR (Status)) {

+        return Status;

+    }

+  }

+

+  //

+  // EFI_IFR_DEFAULT has highest priority

+  //

+  if (!IsListEmpty (&Question->DefaultListHead)) {

+    Link = GetFirstNode (&Question->DefaultListHead);

+    while (!IsNull (&Question->DefaultListHead, Link)) {

+      Default = QUESTION_DEFAULT_FROM_LINK (Link);

+

+      if (Default->DefaultId == DefaultId) {

+        if (Default->ValueExpression != NULL) {

+          //

+          // Default is provided by an Expression, evaluate it

+          //

+          Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);

+          if (EFI_ERROR (Status)) {

+            return Status;

+          }

+

+          if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {

+            ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);

+            if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {

+              CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);

+              Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;

+            } else {

+              CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);

+              Question->HiiValue.BufferLen = Question->StorageWidth;

+            }

+            FreePool (Default->ValueExpression->Result.Buffer);

+          }

+          HiiValue->Type = Default->ValueExpression->Result.Type;

+          CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));       

+        } else {

+          //

+          // Default value is embedded in EFI_IFR_DEFAULT

+          //

+          CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));

+        }

+

+        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {

+          StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);

+          if (StrValue == NULL) {

+            return EFI_NOT_FOUND;

+          }

+          if (Question->StorageWidth > StrSize (StrValue)) {

+            CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));

+          } else {

+            CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);

+          }

+        }

+

+        return EFI_SUCCESS;

+      }

+

+      Link = GetNextNode (&Question->DefaultListHead, Link);

+    }

+  }

+

+  //

+  // EFI_ONE_OF_OPTION

+  //

+  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {

+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {

+      //

+      // OneOfOption could only provide Standard and Manufacturing default

+      //

+      Link = GetFirstNode (&Question->OptionListHead);

+      while (!IsNull (&Question->OptionListHead, Link)) {

+        Option = QUESTION_OPTION_FROM_LINK (Link);

+        Link = GetNextNode (&Question->OptionListHead, Link);

+

+        if ((Option->SuppressExpression != NULL) &&

+            EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {

+          continue;

+        }

+

+        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||

+            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))

+           ) {

+          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));

+

+          return EFI_SUCCESS;

+        }

+      }

+    }

+  }

+

+  //

+  // EFI_IFR_CHECKBOX - lowest priority

+  //

+  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {

+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {

+      //

+      // Checkbox could only provide Standard and Manufacturing default

+      //

+      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||

+          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))

+         ) {

+        HiiValue->Value.b = TRUE;

+      } else {

+        HiiValue->Value.b = FALSE;

+      }

+

+      return EFI_SUCCESS;

+    }

+  }

+

+  //

+  // For Questions without default

+  //

+  Status = EFI_NOT_FOUND;

+  switch (Question->Operand) {

+  case EFI_IFR_NUMERIC_OP:

+    //

+    // Take minimum value as numeric default value

+    //

+    if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {

+      HiiValue->Value.u64 = Question->Minimum;

+      Status = EFI_SUCCESS;

+    }

+    break;

+

+  case EFI_IFR_ONE_OF_OP:

+    //

+    // Take first oneof option as oneof's default value

+    //

+    if (ValueToOption (Question, HiiValue) == NULL) {

+      Link = GetFirstNode (&Question->OptionListHead);

+      while (!IsNull (&Question->OptionListHead, Link)) {

+        Option = QUESTION_OPTION_FROM_LINK (Link);

+        Link = GetNextNode (&Question->OptionListHead, Link);

+

+        if ((Option->SuppressExpression != NULL) &&

+            EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {

+          continue;

+        }

+

+        CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));

+        Status = EFI_SUCCESS;

+        break;

+      }

+    }

+    break;

+

+  case EFI_IFR_ORDERED_LIST_OP:

+    //

+    // Take option sequence in IFR as ordered list's default value

+    //

+    Index = 0;

+    Link = GetFirstNode (&Question->OptionListHead);

+    while (!IsNull (&Question->OptionListHead, Link)) {

+      Status = EFI_SUCCESS;

+      Option = QUESTION_OPTION_FROM_LINK (Link);

+      Link = GetNextNode (&Question->OptionListHead, Link);

+

+      if ((Option->SuppressExpression != NULL) &&

+          EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {

+        continue;

+      }

+

+      SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);

+

+      Index++;

+      if (Index >= Question->MaxContainers) {

+        break;

+      }

+    }

+    break;

+

+  default:

+    break;

+  }

+

+  return Status;

+}

+

+/**

+  Get AltCfg string for current form.

+

+  @param  FormSet                Form data structure.

+  @param  Form                   Form data structure.

+  @param  DefaultId              The Class of the default.

+  @param  BrowserStorage         The input request storage for the questions.

+

+**/

+VOID

+ExtractAltCfgForForm (

+  IN FORM_BROWSER_FORMSET   *FormSet,

+  IN FORM_BROWSER_FORM      *Form,

+  IN UINT16                 DefaultId,

+  IN BROWSER_STORAGE        *BrowserStorage

+  )

+{

+  EFI_STATUS                   Status;

+  LIST_ENTRY                   *Link;

+  CHAR16                       *ConfigResp;

+  CHAR16                       *Progress;

+  CHAR16                       *Result;

+  BROWSER_STORAGE              *Storage;

+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;

+  FORMSET_STORAGE              *FormSetStorage;

+

+  //

+  // Check whether has get AltCfg string for this formset.

+  // If yes, no need to get AltCfg for form.

+  //

+  Link = GetFirstNode (&FormSet->StorageListHead);

+  while (!IsNull (&FormSet->StorageListHead, Link)) {

+    FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);

+    Storage        = FormSetStorage->BrowserStorage;

+    Link = GetNextNode (&FormSet->StorageListHead, Link);

+    if (BrowserStorage != NULL && BrowserStorage != Storage) {

+      continue;

+    }

+

+    if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE &&

+        FormSetStorage->ElementCount != 0 &&

+        FormSetStorage->HasCallAltCfg) {

+      return;

+    }

+  }

+

+  //

+  // Get AltCfg string for each form.

+  //

+  Link = GetFirstNode (&Form->ConfigRequestHead);

+  while (!IsNull (&Form->ConfigRequestHead, Link)) {

+    ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);

+    Link = GetNextNode (&Form->ConfigRequestHead, Link);

+

+    Storage = ConfigInfo->Storage;

+    if (BrowserStorage != NULL && BrowserStorage != Storage) {

+      continue;

+    }

+

+    if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+      continue;

+    }

+

+    //

+    // 1. Skip if there is no RequestElement

+    //

+    if (ConfigInfo->ElementCount == 0) {

+      continue;

+    }

+

+    //

+    // 2. Get value through hii config routine protocol.

+    //

+    Status = mHiiConfigRouting->ExtractConfig (

+                                      mHiiConfigRouting,

+                                      ConfigInfo->ConfigRequest,

+                                      &Progress,

+                                      &Result

+                                      );

+    if (EFI_ERROR (Status)) {

+      continue;

+    }

+

+    //

+    // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)

+    //    Get the default configuration string according to the default ID.

+    //

+    Status = mHiiConfigRouting->GetAltConfig (

+                                  mHiiConfigRouting,

+                                  Result,

+                                  &Storage->Guid,

+                                  Storage->Name,

+                                  NULL,

+                                  &DefaultId,  // it can be NULL to get the current setting.

+                                  &ConfigResp

+                                );

+    FreePool (Result);

+    if (EFI_ERROR (Status)) {

+      continue;

+    }

+

+    ConfigInfo->ConfigAltResp = ConfigResp;

+  }

+}

+

+/**

+  Clean AltCfg string for current form.

+

+  @param  Form                   Form data structure.

+

+**/

+VOID

+CleanAltCfgForForm (

+  IN FORM_BROWSER_FORM   *Form

+  )

+{

+  LIST_ENTRY              *Link;

+  FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;

+

+  Link = GetFirstNode (&Form->ConfigRequestHead);

+  while (!IsNull (&Form->ConfigRequestHead, Link)) {

+    ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);

+    Link = GetNextNode (&Form->ConfigRequestHead, Link);

+

+    if (ConfigInfo->ConfigAltResp != NULL) {

+      FreePool (ConfigInfo->ConfigAltResp);

+      ConfigInfo->ConfigAltResp = NULL;

+    }

+  }

+}

+

+/**

+  Get AltCfg string for current formset.

+

+  @param  FormSet                Form data structure.

+  @param  DefaultId              The Class of the default.

+  @param  BrowserStorage         The input request storage for the questions.

+

+**/

+VOID

+ExtractAltCfgForFormSet (

+  IN FORM_BROWSER_FORMSET   *FormSet,

+  IN UINT16                 DefaultId,

+  IN BROWSER_STORAGE        *BrowserStorage

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *Link;

+  CHAR16                  *ConfigResp;

+  CHAR16                  *Progress;

+  CHAR16                  *Result;

+  BROWSER_STORAGE         *Storage;

+  FORMSET_STORAGE         *FormSetStorage;

+

+  Link = GetFirstNode (&FormSet->StorageListHead);

+  while (!IsNull (&FormSet->StorageListHead, Link)) {

+    FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);

+    Storage        = FormSetStorage->BrowserStorage;

+    Link = GetNextNode (&FormSet->StorageListHead, Link);

+

+    if (BrowserStorage != NULL && BrowserStorage != Storage) {

+      continue;

+    }

+

+    if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {

+      continue;

+    }

+

+    //

+    // 1. Skip if there is no RequestElement

+    //

+    if (FormSetStorage->ElementCount == 0) {

+      continue;

+    }

+

+    FormSetStorage->HasCallAltCfg = TRUE;

+

+    //

+    // 2. Get value through hii config routine protocol.

+    //

+    Status = mHiiConfigRouting->ExtractConfig (

+                                      mHiiConfigRouting,

+                                      FormSetStorage->ConfigRequest,

+                                      &Progress,

+                                      &Result

+                                      );

+    if (EFI_ERROR (Status)) {

+      continue;

+    }

+

+    //

+    // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)

+    //    Get the default configuration string according to the default ID.

+    //

+    Status = mHiiConfigRouting->GetAltConfig (

+                                  mHiiConfigRouting,

+                                  Result,

+                                  &Storage->Guid,

+                                  Storage->Name,

+                                  NULL,

+                                  &DefaultId,  // it can be NULL to get the current setting.

+                                  &ConfigResp

+                                );

+

+    FreePool (Result);

+    if (EFI_ERROR (Status)) {

+      continue;

+    }

+

+    FormSetStorage->ConfigAltResp = ConfigResp;

+  }

+

+}

+

+/**

+  Clean AltCfg string for current formset.

+

+  @param  FormSet                Form data structure.

+

+**/

+VOID

+CleanAltCfgForFormSet (

+  IN FORM_BROWSER_FORMSET   *FormSet

+  )

+{

+  LIST_ENTRY              *Link;

+  FORMSET_STORAGE         *FormSetStorage;

+

+  Link = GetFirstNode (&FormSet->StorageListHead);

+  while (!IsNull (&FormSet->StorageListHead, Link)) {

+    FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);

+    Link = GetNextNode (&FormSet->StorageListHead, Link);

+

+    if (FormSetStorage->ConfigAltResp != NULL) {

+      FreePool (FormSetStorage->ConfigAltResp);

+      FormSetStorage->ConfigAltResp = NULL;

+    }

+

+    FormSetStorage->HasCallAltCfg = FALSE;

+  }

+}

+

+/**

+  Reset Questions to their initial value or default value in a Form, Formset or System.

+

+  GetDefaultValueScope parameter decides which questions will reset 

+  to its default value.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  DefaultId              The Class of the default.

+  @param  SettingScope           Setting Scope for Default action.

+  @param  GetDefaultValueScope   Get default value scope.

+  @param  Storage                Get default value only for this storage.

+  @param  RetrieveValueFirst     Whether call the retrieve call back to

+                                 get the initial value before get default

+                                 value.

+  @param  SkipGetAltCfg          Whether skip the get altcfg string process.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

+

+**/

+EFI_STATUS

+ExtractDefault (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN UINT16                           DefaultId,

+  IN BROWSER_SETTING_SCOPE            SettingScope,

+  IN BROWSER_GET_DEFAULT_VALUE        GetDefaultValueScope,

+  IN BROWSER_STORAGE                  *Storage OPTIONAL,

+  IN BOOLEAN                          RetrieveValueFirst,

+  IN BOOLEAN                          SkipGetAltCfg

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *FormLink;

+  LIST_ENTRY              *Link;

+  FORM_BROWSER_STATEMENT  *Question;

+  FORM_BROWSER_FORMSET    *LocalFormSet;

+  FORM_BROWSER_FORMSET    *OldFormSet;

+

+  Status = EFI_SUCCESS;

+

+  //

+  // Check the supported setting level.

+  //

+  if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {

+    return EFI_UNSUPPORTED;

+  }

+

+  if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {

+    return EFI_UNSUPPORTED;

+  }

+

+  if (SettingScope == FormLevel) {

+    //

+    // Prepare the AltCfg String for form.

+    //

+    if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {

+      ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);

+    }

+

+    //

+    // Extract Form default

+    //

+    Link = GetFirstNode (&Form->StatementListHead);

+    while (!IsNull (&Form->StatementListHead, Link)) {

+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);

+      Link = GetNextNode (&Form->StatementListHead, Link);

+

+      //

+      // If get default value only for this storage, check the storage first.

+      //

+      if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {

+        continue;

+      }

+

+      //

+      // If get default value only for no storage question, just skip the question which has storage.

+      //

+      if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {

+        continue;

+      }

+

+      //

+      // If Question is disabled, don't reset it to default

+      //

+      if (Question->Expression != NULL) {

+        if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {

+          continue;

+        }

+      }

+

+      if (RetrieveValueFirst) {

+        //

+        // Call the Retrieve call back to get the initial question value.

+        //

+        Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);

+      }

+

+      //

+      // If not request to get the initial value or get initial value fail, then get default value.

+      //

+      if (!RetrieveValueFirst || EFI_ERROR (Status)) {

+        Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);

+        if (EFI_ERROR (Status)) {

+          continue;

+        }

+      }

+

+      //

+      // Synchronize Buffer storage's Edit buffer

+      //

+      if ((Question->Storage != NULL) &&

+          (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {

+        SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);

+      }

+    }

+

+    //

+    // Clean the AltCfg String.

+    //

+    if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {

+      CleanAltCfgForForm(Form);

+    }

+  } else if (SettingScope == FormSetLevel) {

+    //

+    // Prepare the AltCfg String for formset.

+    //

+    if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {

+      ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);

+    }

+

+    FormLink = GetFirstNode (&FormSet->FormListHead);

+    while (!IsNull (&FormSet->FormListHead, FormLink)) {

+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);

+      ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);

+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);

+    }

+

+    //

+    // Clean the AltCfg String.

+    //

+    if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {

+      CleanAltCfgForFormSet (FormSet);

+    }

+  } else if (SettingScope == SystemLevel) {

+    //

+    // Preload all Hii formset.

+    //

+    LoadAllHiiFormset();

+

+    OldFormSet = mSystemLevelFormSet;

+

+    //

+    // Set Default Value for each FormSet in the maintain list.

+    //

+    Link = GetFirstNode (&gBrowserFormSetList);

+    while (!IsNull (&gBrowserFormSetList, Link)) {

+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);

+      Link = GetNextNode (&gBrowserFormSetList, Link);

+      if (!ValidateFormSet(LocalFormSet)) {

+        continue;

+      }

+

+      mSystemLevelFormSet = LocalFormSet;

+

+      ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);

+    }

+

+    mSystemLevelFormSet = OldFormSet;

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Validate whether this question's value has changed.

+

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+  @param  Question               Question to be initialized.

+  @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.

+

+  @retval TRUE                   Question's value has changed.

+  @retval FALSE                  Question's value has not changed

+

+**/

+BOOLEAN

+IsQuestionValueChanged (

+  IN FORM_BROWSER_FORMSET             *FormSet,

+  IN FORM_BROWSER_FORM                *Form,

+  IN OUT FORM_BROWSER_STATEMENT       *Question,

+  IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom

+  )

+{

+  EFI_HII_VALUE    BackUpValue;

+  CHAR8            *BackUpBuffer;

+  EFI_HII_VALUE    BackUpValue2;

+  CHAR8            *BackUpBuffer2;

+  EFI_STATUS       Status;

+  BOOLEAN          ValueChanged;

+  UINTN            BufferWidth;

+

+  //

+  // For quetion without storage, always mark it as data not changed.

+  //

+  if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {

+    return FALSE;

+  }

+

+  BackUpBuffer = NULL;

+  BackUpBuffer2 = NULL;

+  ValueChanged = FALSE;

+

+  switch (Question->Operand) {

+    case EFI_IFR_ORDERED_LIST_OP:

+      BufferWidth  = Question->StorageWidth;

+      BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);

+      ASSERT (BackUpBuffer != NULL);

+      break;

+

+    case EFI_IFR_STRING_OP:

+    case EFI_IFR_PASSWORD_OP:

+      BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);

+      BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);

+      ASSERT (BackUpBuffer != NULL);

+      break;

+

+    default:

+      BufferWidth = 0;

+      break;

+  }

+  CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));

+

+  if (GetValueFrom == GetSetValueWithBothBuffer) {

+    Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);

+    ASSERT_EFI_ERROR(Status);

+

+    switch (Question->Operand) {

+      case EFI_IFR_ORDERED_LIST_OP:

+        BufferWidth  = Question->StorageWidth;

+        BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);

+        ASSERT (BackUpBuffer2 != NULL);

+        break;

+

+      case EFI_IFR_STRING_OP:

+      case EFI_IFR_PASSWORD_OP:

+        BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);

+        BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);

+        ASSERT (BackUpBuffer2 != NULL);

+        break;

+

+      default:

+        BufferWidth = 0;

+        break;

+    }

+    CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));

+

+    Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);

+    ASSERT_EFI_ERROR(Status);

+

+    if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||

+        CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {

+      ValueChanged = TRUE;

+    }

+  } else {

+    Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);

+    ASSERT_EFI_ERROR(Status);

+

+    if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||

+        CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {

+      ValueChanged = TRUE;

+    }

+  }

+

+  CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));

+  if (BackUpBuffer != NULL) {

+    CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);

+    FreePool (BackUpBuffer);

+  }

+

+  if (BackUpBuffer2 != NULL) {

+    FreePool (BackUpBuffer2);

+  }

+

+  Question->ValueChanged = ValueChanged;

+

+  return ValueChanged;

+}

+

+/**

+  Initialize Question's Edit copy from Storage.

+

+  @param  Selection              Selection contains the information about 

+                                 the Selection, form and formset to be displayed.

+                                 Selection action may be updated in retrieve callback.

+                                 If Selection is NULL, only initialize Question value.

+  @param  FormSet                FormSet data structure.

+  @param  Form                   Form data structure.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+

+**/

+EFI_STATUS

+LoadFormConfig (

+  IN OUT UI_MENU_SELECTION    *Selection,

+  IN FORM_BROWSER_FORMSET     *FormSet,

+  IN FORM_BROWSER_FORM        *Form

+  )

+{

+  EFI_STATUS                  Status;

+  LIST_ENTRY                  *Link;

+  FORM_BROWSER_STATEMENT      *Question;

+  

+  Link = GetFirstNode (&Form->StatementListHead);

+  while (!IsNull (&Form->StatementListHead, Link)) {

+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);

+

+    //

+    // Initialize local copy of Value for each Question

+    //

+    if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {

+      Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);

+    } else {

+      Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);

+    }

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {

+      HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);

+    }

+

+    Link = GetNextNode (&Form->StatementListHead, Link);

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Initialize Question's Edit copy from Storage for the whole Formset.

+

+  @param  Selection              Selection contains the information about 

+                                 the Selection, form and formset to be displayed.

+                                 Selection action may be updated in retrieve callback.

+                                 If Selection is NULL, only initialize Question value.

+  @param  FormSet                FormSet data structure.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+

+**/

+EFI_STATUS

+LoadFormSetConfig (

+  IN OUT UI_MENU_SELECTION    *Selection,

+  IN     FORM_BROWSER_FORMSET *FormSet

+  )

+{

+  EFI_STATUS            Status;

+  LIST_ENTRY            *Link;

+  FORM_BROWSER_FORM     *Form;

+

+  Link = GetFirstNode (&FormSet->FormListHead);

+  while (!IsNull (&FormSet->FormListHead, Link)) {

+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);

+

+    //

+    // Initialize local copy of Value for each Form

+    //

+    Status = LoadFormConfig (Selection, FormSet, Form);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    Link = GetNextNode (&FormSet->FormListHead, Link);

+  }

+

+  //

+  // Finished question initialization.

+  // 

+  FormSet->QuestionInited = TRUE;

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Remove the Request element from the Config Request.

+

+  @param  Storage                Pointer to the browser storage.

+  @param  RequestElement         The pointer to the Request element.

+

+**/

+VOID

+RemoveElement (

+  IN OUT BROWSER_STORAGE      *Storage,

+  IN     CHAR16               *RequestElement

+  )

+{

+  CHAR16   *NewStr;

+  CHAR16   *DestStr;

+

+  ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);

+

+  NewStr = StrStr (Storage->ConfigRequest, RequestElement);

+

+  if (NewStr == NULL) {

+    return;

+  }

+

+  //

+  // Remove this element from this ConfigRequest.

+  //

+  DestStr = NewStr;

+  NewStr += StrLen (RequestElement);

+  CopyMem (DestStr, NewStr, StrSize (NewStr));

+  

+  Storage->SpareStrLen += StrLen (RequestElement);  

+}

+

+/**

+  Adjust config request in storage, remove the request elements existed in the input ConfigRequest.

+

+  @param  Storage                Pointer to the formset storage.

+  @param  ConfigRequest          The pointer to the Request element.

+

+**/

+VOID

+RemoveConfigRequest (

+  FORMSET_STORAGE   *Storage,

+  CHAR16            *ConfigRequest

+  )

+{

+  CHAR16       *RequestElement;

+  CHAR16       *NextRequestElement;

+  CHAR16       *SearchKey;

+

+  //

+  // No request element in it, just return.

+  //

+  if (ConfigRequest == NULL) {

+    return;

+  }

+

+  if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    //

+    // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage

+    //

+    SearchKey = L"&";

+  } else {

+    //

+    // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage

+    //

+    SearchKey = L"&OFFSET";

+  }

+

+  //

+  // Find SearchKey storage

+  //

+  if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    RequestElement = StrStr (ConfigRequest, L"PATH");

+    ASSERT (RequestElement != NULL);

+    RequestElement = StrStr (RequestElement, SearchKey);    

+  } else {

+    RequestElement = StrStr (ConfigRequest, SearchKey);

+  }

+

+  while (RequestElement != NULL) {

+    //

+    // +1 to avoid find header itself.

+    //

+    NextRequestElement = StrStr (RequestElement + 1, SearchKey);

+

+    //

+    // The last Request element in configRequest string.

+    //

+    if (NextRequestElement != NULL) {

+      //

+      // Replace "&" with '\0'.

+      //

+      *NextRequestElement = L'\0';

+    }

+

+    RemoveElement (Storage->BrowserStorage, RequestElement);

+

+    if (NextRequestElement != NULL) {

+      //

+      // Restore '&' with '\0' for later used.

+      //

+      *NextRequestElement = L'&';

+    }

+

+    RequestElement = NextRequestElement;

+  }

+

+  //

+  // If no request element remain, just remove the ConfigRequest string.

+  //

+  if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {

+    FreePool (Storage->BrowserStorage->ConfigRequest);

+    Storage->BrowserStorage->ConfigRequest = NULL;

+    Storage->BrowserStorage->SpareStrLen   = 0;

+  }

+}

+

+/**

+  Base on the current formset info, clean the ConfigRequest string in browser storage.

+

+  @param  FormSet                Pointer of the FormSet

+

+**/

+VOID

+CleanBrowserStorage (

+  IN OUT FORM_BROWSER_FORMSET  *FormSet

+  )

+{

+  LIST_ENTRY            *Link;

+  FORMSET_STORAGE       *Storage;

+

+  Link = GetFirstNode (&FormSet->StorageListHead);

+  while (!IsNull (&FormSet->StorageListHead, Link)) {

+    Storage = FORMSET_STORAGE_FROM_LINK (Link);

+    Link = GetNextNode (&FormSet->StorageListHead, Link);

+

+    if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {

+      if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {

+        continue;

+      }

+

+      RemoveConfigRequest (Storage, Storage->ConfigRequest);

+    } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||

+               Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+      if (Storage->BrowserStorage->ConfigRequest != NULL) { 

+        FreePool (Storage->BrowserStorage->ConfigRequest);

+        Storage->BrowserStorage->ConfigRequest = NULL;

+      }

+      Storage->BrowserStorage->Initialized = FALSE;

+    }

+  }

+}

+

+/**

+  Check whether current element in the ConfigReqeust string.

+

+  @param  BrowserStorage                Storage which includes ConfigReqeust.

+  @param  RequestElement                New element need to check.

+

+  @retval TRUE        The Element is in the ConfigReqeust string.

+  @retval FALSE       The Element not in the configReqeust String.

+

+**/

+BOOLEAN 

+ElementValidation (

+  BROWSER_STORAGE   *BrowserStorage,

+  CHAR16            *RequestElement

+  )

+{

+  return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;

+}

+

+/**

+  Append the Request element to the Config Request.

+

+  @param  ConfigRequest          Current ConfigRequest info.

+  @param  SpareStrLen            Current remain free buffer for config reqeust.

+  @param  RequestElement         New Request element.

+

+**/

+VOID

+AppendConfigRequest (

+  IN OUT CHAR16               **ConfigRequest,

+  IN OUT UINTN                *SpareStrLen,

+  IN     CHAR16               *RequestElement

+  )

+{

+  CHAR16   *NewStr;

+  UINTN    StringSize;

+  UINTN    StrLength;

+

+  StrLength = StrLen (RequestElement);

+

+  //

+  // Append <RequestElement> to <ConfigRequest>

+  //

+  if (StrLength > *SpareStrLen) {

+    //

+    // Old String buffer is not sufficient for RequestElement, allocate a new one

+    //

+    StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);

+    NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));

+    ASSERT (NewStr != NULL);

+

+    if (*ConfigRequest != NULL) {

+      CopyMem (NewStr, *ConfigRequest, StringSize);

+      FreePool (*ConfigRequest);

+    }

+    *ConfigRequest = NewStr;

+    *SpareStrLen   = CONFIG_REQUEST_STRING_INCREMENTAL;

+  }

+

+  StrCat (*ConfigRequest, RequestElement);

+  *SpareStrLen -= StrLength;

+}

+

+/**

+  Adjust the config request info, remove the request elements which already in AllConfigRequest string.

+

+  @param  Storage                Form set Storage.

+  @param  Request                The input request string.

+  @param  RespString             Whether the input is ConfigRequest or ConfigResp format.

+

+  @retval TRUE                   Has element not covered by current used elements, need to continue to call ExtractConfig

+  @retval FALSE                  All elements covered by current used elements.

+

+**/

+BOOLEAN 

+ConfigRequestAdjust (

+  IN  BROWSER_STORAGE         *Storage,

+  IN  CHAR16                  *Request,

+  IN  BOOLEAN                 RespString

+  )

+{

+  CHAR16       *RequestElement;

+  CHAR16       *NextRequestElement;

+  CHAR16       *NextElementBakup;

+  CHAR16       *SearchKey;

+  CHAR16       *ValueKey;

+  BOOLEAN      RetVal;

+  CHAR16       *ConfigRequest;

+

+  RetVal         = FALSE;

+  NextElementBakup = NULL;

+  ValueKey         = NULL;

+

+  if (Request != NULL) {

+    ConfigRequest = Request;

+  } else {

+    ConfigRequest = Storage->ConfigRequest;

+  }

+

+  if (Storage->ConfigRequest == NULL) {

+    Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);

+    return TRUE;

+  }

+

+  if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    //

+    // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage

+    //

+    SearchKey = L"&";

+  } else {

+    //

+    // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage

+    //

+    SearchKey = L"&OFFSET";

+    ValueKey  = L"&VALUE";

+  }

+

+  //

+  // Find SearchKey storage

+  //

+  if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {

+    RequestElement = StrStr (ConfigRequest, L"PATH");

+    ASSERT (RequestElement != NULL);

+    RequestElement = StrStr (RequestElement, SearchKey);    

+  } else {

+    RequestElement = StrStr (ConfigRequest, SearchKey);

+  }

+

+  while (RequestElement != NULL) {

+

+    //

+    // +1 to avoid find header itself.

+    //

+    NextRequestElement = StrStr (RequestElement + 1, SearchKey);

+

+    //

+    // The last Request element in configRequest string.

+    //

+    if (NextRequestElement != NULL) {

+      if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {

+        NextElementBakup = NextRequestElement;

+        NextRequestElement = StrStr (RequestElement, ValueKey);

+        ASSERT (NextRequestElement != NULL);

+      }

+      //

+      // Replace "&" with '\0'.

+      //

+      *NextRequestElement = L'\0';

+    } else {

+      if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {

+        NextElementBakup = NextRequestElement;

+        NextRequestElement = StrStr (RequestElement, ValueKey);

+        ASSERT (NextRequestElement != NULL);

+        //

+        // Replace "&" with '\0'.

+        //

+        *NextRequestElement = L'\0';

+      }

+    }

+ 

+    if (!ElementValidation (Storage, RequestElement)) {

+      //

+      // Add this element to the Storage->BrowserStorage->AllRequestElement.

+      //

+      AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);

+      RetVal = TRUE;

+    }

+

+    if (NextRequestElement != NULL) {

+      //

+      // Restore '&' with '\0' for later used.

+      //

+      *NextRequestElement = L'&';

+    }

+

+    if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {

+      RequestElement = NextElementBakup;

+    } else {

+      RequestElement = NextRequestElement;

+    }

+  }

+

+  return RetVal;

+}

+

+/**

+  Fill storage's edit copy with settings requested from Configuration Driver.

+

+  @param  FormSet                FormSet data structure.

+  @param  Storage                Buffer Storage.

+

+**/

+VOID

+LoadStorage (

+  IN FORM_BROWSER_FORMSET    *FormSet,

+  IN FORMSET_STORAGE         *Storage

+  )

+{

+  EFI_STATUS  Status;

+  EFI_STRING  Progress;

+  EFI_STRING  Result;

+  CHAR16      *StrPtr;

+  EFI_STRING  ConfigRequest;

+  UINTN       StrLen;

+

+  ConfigRequest = NULL;

+

+  switch (Storage->BrowserStorage->Type) {

+    case EFI_HII_VARSTORE_EFI_VARIABLE:

+      return;

+

+    case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:

+      if (Storage->BrowserStorage->ConfigRequest != NULL) {

+        ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);

+        return;

+      }

+      break;

+

+    case EFI_HII_VARSTORE_BUFFER:

+    case EFI_HII_VARSTORE_NAME_VALUE:

+      //

+      // Skip if there is no RequestElement.

+      //

+      if (Storage->ElementCount == 0) {

+        return;

+      }

+

+      //

+      // Just update the ConfigRequest, if storage already initialized. 

+      //

+      if (Storage->BrowserStorage->Initialized) {

+        ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);

+        return;

+      }

+

+      Storage->BrowserStorage->Initialized = TRUE;

+      break;

+

+    default:

+      return;

+  }

+

+  if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {

+    //

+    // Create the config request string to get all fields for this storage.

+    // Allocate and fill a buffer large enough to hold the <ConfigHdr> template

+    // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator

+    //

+    StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);

+    ConfigRequest = AllocateZeroPool (StrLen);

+    ASSERT (ConfigRequest != NULL);

+    UnicodeSPrint (

+               ConfigRequest, 

+               StrLen, 

+               L"%s&OFFSET=0&WIDTH=%04x", 

+               Storage->ConfigHdr,

+               Storage->BrowserStorage->Size);

+  } else {

+    ConfigRequest = Storage->ConfigRequest;

+  }

+

+  //

+  // Request current settings from Configuration Driver

+  //

+  Status = mHiiConfigRouting->ExtractConfig (

+                                    mHiiConfigRouting,

+                                    ConfigRequest,

+                                    &Progress,

+                                    &Result

+                                    );

+

+  //

+  // If get value fail, extract default from IFR binary

+  //

+  if (EFI_ERROR (Status)) {

+    ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);

+  } else {

+    //

+    // Convert Result from <ConfigAltResp> to <ConfigResp>

+    //

+    StrPtr = StrStr (Result, L"&GUID=");

+    if (StrPtr != NULL) {

+      *StrPtr = L'\0';

+    }

+    

+    Status = ConfigRespToStorage (Storage->BrowserStorage, Result);

+    FreePool (Result);

+  }

+

+  Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);

+

+  //

+  // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. 

+  //

+  SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);

+

+  if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {

+    if (ConfigRequest != NULL) {

+      FreePool (ConfigRequest);

+    }

+  }

+}

+

+/**

+  Get Value changed status from old question.

+

+  @param  NewFormSet                FormSet data structure.

+  @param  OldQuestion               Old question which has value changed.

+

+**/

+VOID

+SyncStatusForQuestion (

+  IN OUT FORM_BROWSER_FORMSET             *NewFormSet,

+  IN     FORM_BROWSER_STATEMENT           *OldQuestion

+  )

+{

+  LIST_ENTRY                  *Link;

+  LIST_ENTRY                  *QuestionLink;

+  FORM_BROWSER_FORM           *Form;

+  FORM_BROWSER_STATEMENT      *Question;

+

+  //

+  // For each form in one formset.

+  //

+  Link = GetFirstNode (&NewFormSet->FormListHead);

+  while (!IsNull (&NewFormSet->FormListHead, Link)) {

+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);

+    Link = GetNextNode (&NewFormSet->FormListHead, Link);

+

+    //

+    // for each question in one form.

+    //

+    QuestionLink = GetFirstNode (&Form->StatementListHead);

+    while (!IsNull (&Form->StatementListHead, QuestionLink)) {

+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);

+      QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);

+

+      if (Question->QuestionId == OldQuestion->QuestionId) {

+        Question->ValueChanged = TRUE;

+        return;

+      }

+    }

+  }

+}

+

+/**

+  Get Value changed status from old formset.

+

+  @param  NewFormSet                FormSet data structure.

+  @param  OldFormSet                FormSet data structure.

+

+**/

+VOID

+SyncStatusForFormSet (

+  IN OUT FORM_BROWSER_FORMSET             *NewFormSet,

+  IN     FORM_BROWSER_FORMSET             *OldFormSet

+  )

+{

+  LIST_ENTRY                  *Link;

+  LIST_ENTRY                  *QuestionLink;

+  FORM_BROWSER_FORM           *Form;

+  FORM_BROWSER_STATEMENT      *Question;

+

+  //

+  // For each form in one formset.

+  //

+  Link = GetFirstNode (&OldFormSet->FormListHead);

+  while (!IsNull (&OldFormSet->FormListHead, Link)) {

+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);

+    Link = GetNextNode (&OldFormSet->FormListHead, Link);

+

+    //

+    // for each question in one form.

+    //

+    QuestionLink = GetFirstNode (&Form->StatementListHead);

+    while (!IsNull (&Form->StatementListHead, QuestionLink)) {

+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);

+      QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);

+

+      if (!Question->ValueChanged) {

+        continue;

+      }

+

+      //

+      // Find the same question in new formset and update the value changed flag.

+      //

+      SyncStatusForQuestion (NewFormSet, Question);

+    }

+  }

+}

+

+/**

+  Get current setting of Questions.

+

+  @param  FormSet                FormSet data structure.

+

+**/

+VOID

+InitializeCurrentSetting (

+  IN OUT FORM_BROWSER_FORMSET             *FormSet

+  )

+{

+  LIST_ENTRY              *Link;

+  FORMSET_STORAGE         *Storage;

+  FORM_BROWSER_FORMSET    *OldFormSet;

+

+  //

+  // Try to find pre FormSet in the maintain backup list.

+  // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.

+  //

+  OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);

+  if (OldFormSet != NULL) {

+    SyncStatusForFormSet (FormSet, OldFormSet);

+    RemoveEntryList (&OldFormSet->Link);

+    DestroyFormSet (OldFormSet);

+  }

+  InsertTailList (&gBrowserFormSetList, &FormSet->Link);

+

+  //

+  // Extract default from IFR binary for no storage questions.

+  //  

+  ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);

+

+  //

+  // Request current settings from Configuration Driver

+  //

+  Link = GetFirstNode (&FormSet->StorageListHead);

+  while (!IsNull (&FormSet->StorageListHead, Link)) {

+    Storage = FORMSET_STORAGE_FROM_LINK (Link);

+

+    LoadStorage (FormSet, Storage);

+

+    Link = GetNextNode (&FormSet->StorageListHead, Link);

+  }

+}

+

+

+/**

+  Fetch the Ifr binary data of a FormSet.

+

+  @param  Handle                 PackageList Handle

+  @param  FormSetGuid            On input, GUID or class GUID of a formset. If not

+                                 specified (NULL or zero GUID), take the first

+                                 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID

+                                 found in package list.

+                                 On output, GUID of the formset found(if not NULL).

+  @param  BinaryLength           The length of the FormSet IFR binary.

+  @param  BinaryData             The buffer designed to receive the FormSet.

+

+  @retval EFI_SUCCESS            Buffer filled with the requested FormSet.

+                                 BufferLength was updated.

+  @retval EFI_INVALID_PARAMETER  The handle is unknown.

+  @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot

+                                 be found with the requested FormId.

+

+**/

+EFI_STATUS

+GetIfrBinaryData (

+  IN  EFI_HII_HANDLE   Handle,

+  IN OUT EFI_GUID      *FormSetGuid,

+  OUT UINTN            *BinaryLength,

+  OUT UINT8            **BinaryData

+  )

+{

+  EFI_STATUS                   Status;

+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;

+  UINTN                        BufferSize;

+  UINT8                        *Package;

+  UINT8                        *OpCodeData;

+  UINT32                       Offset;

+  UINT32                       Offset2;

+  UINT32                       PackageListLength;

+  EFI_HII_PACKAGE_HEADER       PackageHeader;

+  UINT8                        Index;

+  UINT8                        NumberOfClassGuid;

+  BOOLEAN                      ClassGuidMatch;

+  EFI_GUID                     *ClassGuid;

+  EFI_GUID                     *ComparingGuid;

+

+  OpCodeData = NULL;

+  Package = NULL;

+  ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));

+

+  //

+  // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list

+  //

+  if (FormSetGuid == NULL) {

+    ComparingGuid = &gZeroGuid;

+  } else {

+    ComparingGuid = FormSetGuid;

+  }

+

+  //

+  // Get HII PackageList

+  //

+  BufferSize = 0;

+  HiiPackageList = NULL;

+  Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);

+  if (Status == EFI_BUFFER_TOO_SMALL) {

+    HiiPackageList = AllocatePool (BufferSize);

+    ASSERT (HiiPackageList != NULL);

+

+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);

+  }

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  ASSERT (HiiPackageList != NULL);

+

+  //

+  // Get Form package from this HII package List

+  //

+  Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);

+  Offset2 = 0;

+  CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));

+

+  ClassGuidMatch = FALSE;

+  while (Offset < PackageListLength) {

+    Package = ((UINT8 *) HiiPackageList) + Offset;

+    CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));

+

+    if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {

+      //

+      // Search FormSet in this Form Package

+      //

+      Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);

+      while (Offset2 < PackageHeader.Length) {

+        OpCodeData = Package + Offset2;

+

+        if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {

+          //

+          // Try to compare against formset GUID

+          //

+          if (CompareGuid (FormSetGuid, &gZeroGuid) || 

+              CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {

+            break;

+          }

+

+          if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {

+            //

+            // Try to compare against formset class GUID

+            //

+            NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);

+            ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));

+            for (Index = 0; Index < NumberOfClassGuid; Index++) {

+              if (CompareGuid (ComparingGuid, ClassGuid + Index)) {

+                ClassGuidMatch = TRUE;

+                break;

+              }

+            }

+            if (ClassGuidMatch) {

+              break;

+            }

+          } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {

+            ClassGuidMatch = TRUE;

+            break;

+          }

+        }

+

+        Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;

+      }

+

+      if (Offset2 < PackageHeader.Length) {

+        //

+        // Target formset found

+        //

+        break;

+      }

+    }

+

+    Offset += PackageHeader.Length;

+  }

+

+  if (Offset >= PackageListLength) {

+    //

+    // Form package not found in this Package List

+    //

+    FreePool (HiiPackageList);

+    return EFI_NOT_FOUND;

+  }

+

+  if (FormSetGuid != NULL) {

+    //

+    // Return the FormSet GUID

+    //

+    CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));

+  }

+

+  //

+  // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes

+  // in this FormSet; So, here just simply copy the data from start of a FormSet to the end

+  // of the Form Package.

+  //

+  *BinaryLength = PackageHeader.Length - Offset2;

+  *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);

+

+  FreePool (HiiPackageList);

+

+  if (*BinaryData == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Initialize the internal data structure of a FormSet.

+

+  @param  Handle                 PackageList Handle

+  @param  FormSetGuid            On input, GUID or class GUID of a formset. If not

+                                 specified (NULL or zero GUID), take the first

+                                 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID

+                                 found in package list.

+                                 On output, GUID of the formset found(if not NULL).

+  @param  FormSet                FormSet data structure.

+

+  @retval EFI_SUCCESS            The function completed successfully.

+  @retval EFI_NOT_FOUND          The specified FormSet could not be found.

+

+**/

+EFI_STATUS

+InitializeFormSet (

+  IN  EFI_HII_HANDLE                   Handle,

+  IN OUT EFI_GUID                      *FormSetGuid,

+  OUT FORM_BROWSER_FORMSET             *FormSet

+  )

+{

+  EFI_STATUS                Status;

+  EFI_HANDLE                DriverHandle;

+

+  Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;

+  FormSet->HiiHandle = Handle;

+  CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));

+  FormSet->QuestionInited = FALSE;

+

+  //

+  // Retrieve ConfigAccess Protocol associated with this HiiPackageList

+  //

+  Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  FormSet->DriverHandle = DriverHandle;

+  Status = gBS->HandleProtocol (

+                  DriverHandle,

+                  &gEfiHiiConfigAccessProtocolGuid,

+                  (VOID **) &FormSet->ConfigAccess

+                  );

+  if (EFI_ERROR (Status)) {

+    //

+    // Configuration Driver don't attach ConfigAccess protocol to its HII package

+    // list, then there will be no configuration action required

+    //

+    FormSet->ConfigAccess = NULL;

+  }

+

+  //

+  // Parse the IFR binary OpCodes

+  //

+  Status = ParseOpCodes (FormSet);

+

+  return Status;

+}

+

+

+/**

+  Save globals used by previous call to SendForm(). SendForm() may be called from 

+  HiiConfigAccess.Callback(), this will cause SendForm() be reentried.

+  So, save globals of previous call to SendForm() and restore them upon exit.

+

+**/

+VOID

+SaveBrowserContext (

+  VOID

+  )

+{

+  BROWSER_CONTEXT  *Context;

+  FORM_ENTRY_INFO     *MenuList;

+

+  gBrowserContextCount++;

+  if (gBrowserContextCount == 1) {

+    //

+    // This is not reentry of SendForm(), no context to save

+    //

+    return;

+  }

+

+  Context = AllocatePool (sizeof (BROWSER_CONTEXT));

+  ASSERT (Context != NULL);

+

+  Context->Signature = BROWSER_CONTEXT_SIGNATURE;

+

+  //

+  // Save FormBrowser context

+  //

+  Context->Selection            = gCurrentSelection;

+  Context->ResetRequired        = gResetRequired;

+  Context->ExitRequired         = gExitRequired;

+  Context->HiiHandle            = mCurrentHiiHandle;

+  Context->FormId               = mCurrentFormId;

+  CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);

+

+  //

+  // Save the menu history data.

+  //

+  InitializeListHead(&Context->FormHistoryList);

+  while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {

+    MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);

+    RemoveEntryList (&MenuList->Link);

+

+    InsertTailList(&Context->FormHistoryList, &MenuList->Link);

+  }

+

+  //

+  // Insert to FormBrowser context list

+  //

+  InsertHeadList (&gBrowserContextList, &Context->Link);

+}

+

+

+/**

+  Restore globals used by previous call to SendForm().

+

+**/

+VOID

+RestoreBrowserContext (

+  VOID

+  )

+{

+  LIST_ENTRY       *Link;

+  BROWSER_CONTEXT  *Context;

+  FORM_ENTRY_INFO     *MenuList;

+

+  ASSERT (gBrowserContextCount != 0);

+  gBrowserContextCount--;

+  if (gBrowserContextCount == 0) {

+    //

+    // This is not reentry of SendForm(), no context to restore

+    //

+    return;

+  }

+

+  ASSERT (!IsListEmpty (&gBrowserContextList));

+

+  Link = GetFirstNode (&gBrowserContextList);

+  Context = BROWSER_CONTEXT_FROM_LINK (Link);

+

+  //

+  // Restore FormBrowser context

+  //

+  gCurrentSelection     = Context->Selection;

+  gResetRequired        = Context->ResetRequired;

+  gExitRequired         = Context->ExitRequired;

+  mCurrentHiiHandle     = Context->HiiHandle;

+  mCurrentFormId        = Context->FormId;

+  CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);

+

+  //

+  // Restore the menu history data.

+  //

+  while (!IsListEmpty (&Context->FormHistoryList)) {

+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);

+    RemoveEntryList (&MenuList->Link);

+

+    InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);

+  }

+

+  //

+  // Remove from FormBrowser context list

+  //

+  RemoveEntryList (&Context->Link);

+  gBS->FreePool (Context);

+}

+

+/**

+  Find the matched FormSet context in the backup maintain list based on HiiHandle.

+  

+  @param Handle  The Hii Handle.

+  

+  @return the found FormSet context. If no found, NULL will return.

+

+**/

+FORM_BROWSER_FORMSET * 

+GetFormSetFromHiiHandle (

+  EFI_HII_HANDLE Handle

+  )

+{

+  LIST_ENTRY           *Link;

+  FORM_BROWSER_FORMSET *FormSet;

+

+  Link = GetFirstNode (&gBrowserFormSetList);

+  while (!IsNull (&gBrowserFormSetList, Link)) {

+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);

+    Link = GetNextNode (&gBrowserFormSetList, Link);

+    if (!ValidateFormSet(FormSet)) {

+      continue;

+    }

+    if (FormSet->HiiHandle == Handle) {

+      return FormSet;

+    }

+  }

+  

+  return NULL;

+}

+

+/**

+  Check whether the input HII handle is the FormSet that is being used.

+  

+  @param Handle  The Hii Handle.

+  

+  @retval TRUE   HII handle is being used.

+  @retval FALSE  HII handle is not being used.

+

+**/

+BOOLEAN

+IsHiiHandleInBrowserContext (

+  EFI_HII_HANDLE Handle

+  )

+{

+  LIST_ENTRY       *Link;

+  BROWSER_CONTEXT  *Context;

+

+  //

+  // HiiHandle is Current FormSet.

+  //

+  if (mCurrentHiiHandle == Handle) {

+    return TRUE;

+  }

+

+  //

+  // Check whether HiiHandle is in BrowserContext.

+  //

+  Link = GetFirstNode (&gBrowserContextList);

+  while (!IsNull (&gBrowserContextList, Link)) {

+    Context = BROWSER_CONTEXT_FROM_LINK (Link);

+    if (Context->HiiHandle == Handle) {

+      //

+      // HiiHandle is in BrowserContext

+      //

+      return TRUE;

+    }

+    Link = GetNextNode (&gBrowserContextList, Link);

+  }

+  

+  return FALSE;

+}

+

+/**

+  Perform Password check. 

+  Passwork may be encrypted by driver that requires the specific check.

+  

+  @param  Form             Form where Password Statement is in.

+  @param  Statement        Password statement

+  @param  PasswordString   Password string to be checked. It may be NULL.

+                           NULL means to restore password.

+                           "" string can be used to checked whether old password does exist.

+  

+  @return Status     Status of Password check.

+**/

+EFI_STATUS

+EFIAPI

+PasswordCheck (

+  IN FORM_DISPLAY_ENGINE_FORM      *Form,

+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,

+  IN EFI_STRING                    PasswordString  OPTIONAL

+  )

+{

+  EFI_STATUS                      Status;

+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;

+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;

+  EFI_IFR_TYPE_VALUE              IfrTypeValue;

+  FORM_BROWSER_STATEMENT          *Question;

+

+  ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;

+  Question = GetBrowserStatement(Statement);

+  ASSERT (Question != NULL);

+

+  if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {

+    if (ConfigAccess == NULL) {

+      return EFI_UNSUPPORTED;

+    }

+  } else {

+    if (PasswordString == NULL) {

+      return EFI_SUCCESS;

+    } 

+

+    //

+    // Check whether has preexisted password.

+    //

+    if (PasswordString[0] == 0) {

+      if (*((CHAR16 *) Question->BufferValue) == 0) {

+        return EFI_SUCCESS;

+      } else {

+        return EFI_NOT_READY;

+      }

+    }

+

+    //

+    // Check whether the input password is same as preexisted password.

+    //

+    if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {

+      return EFI_SUCCESS;

+    } else {

+      return EFI_NOT_READY;

+    }

+  }

+    

+  //

+  // Prepare password string in HII database

+  //

+  if (PasswordString != NULL) {

+    IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);

+  } else {

+    IfrTypeValue.string = 0;

+  }

+

+  //

+  // Send password to Configuration Driver for validation

+  //

+  Status = ConfigAccess->Callback (

+                           ConfigAccess,

+                           EFI_BROWSER_ACTION_CHANGING,

+                           Question->QuestionId,

+                           Question->HiiValue.Type,

+                           &IfrTypeValue,

+                           &ActionRequest

+                           );

+

+  //

+  // Remove password string from HII database

+  //

+  if (PasswordString != NULL) {

+    DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);

+  }

+

+  return Status;

+}

+

+/**

+  Find the registered HotKey based on KeyData.

+  

+  @param[in] KeyData     A pointer to a buffer that describes the keystroke

+                         information for the hot key.

+

+  @return The registered HotKey context. If no found, NULL will return.

+**/

+BROWSER_HOT_KEY *

+GetHotKeyFromRegisterList (

+  IN EFI_INPUT_KEY *KeyData

+  )

+{

+  LIST_ENTRY       *Link;

+  BROWSER_HOT_KEY  *HotKey;

+

+  Link = GetFirstNode (&gBrowserHotKeyList);

+  while (!IsNull (&gBrowserHotKeyList, Link)) {

+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);

+    if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {

+      return HotKey;

+    }

+    Link = GetNextNode (&gBrowserHotKeyList, Link);

+  }

+  

+  return NULL;

+}

+

+/**

+  Configure what scope the hot key will impact.

+  All hot keys have the same scope. The mixed hot keys with the different level are not supported.

+  If no scope is set, the default scope will be FormSet level.

+  After all registered hot keys are removed, previous Scope can reset to another level.

+  

+  @param[in] Scope               Scope level to be set. 

+  

+  @retval EFI_SUCCESS            Scope is set correctly.

+  @retval EFI_INVALID_PARAMETER  Scope is not the valid value specified in BROWSER_SETTING_SCOPE. 

+  @retval EFI_UNSPPORTED         Scope level is different from current one that the registered hot keys have.

+

+**/

+EFI_STATUS

+EFIAPI

+SetScope (

+  IN BROWSER_SETTING_SCOPE Scope

+  )

+{

+  if (Scope >= MaxLevel) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // When no hot key registered in system or on the first setting,

+  // Scope can be set.

+  //

+  if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {

+    gBrowserSettingScope  = Scope;

+    mBrowserScopeFirstSet = FALSE;

+  } else if (Scope != gBrowserSettingScope) {

+    return EFI_UNSUPPORTED;

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Register the hot key with its browser action, or unregistered the hot key.

+  Only support hot key that is not printable character (control key, function key, etc.).

+  If the action value is zero, the hot key will be unregistered if it has been registered.

+  If the same hot key has been registered, the new action and help string will override the previous ones.

+  

+  @param[in] KeyData     A pointer to a buffer that describes the keystroke

+                         information for the hot key. Its type is EFI_INPUT_KEY to 

+                         be supported by all ConsoleIn devices.

+  @param[in] Action      Action value that describes what action will be trigged when the hot key is pressed. 

+  @param[in] DefaultId   Specifies the type of defaults to retrieve, which is only for DEFAULT action.

+  @param[in] HelpString  Help string that describes the hot key information.

+                         Its value may be NULL for the unregistered hot key.

+  

+  @retval EFI_SUCCESS            Hot key is registered or unregistered.

+  @retval EFI_INVALID_PARAMETER  KeyData is NULL or HelpString is NULL on register.

+  @retval EFI_NOT_FOUND          KeyData is not found to be unregistered.

+  @retval EFI_UNSUPPORTED        Key represents a printable character. It is conflicted with Browser.

+**/

+EFI_STATUS

+EFIAPI

+RegisterHotKey (

+  IN EFI_INPUT_KEY *KeyData,

+  IN UINT32        Action,

+  IN UINT16        DefaultId,

+  IN EFI_STRING    HelpString OPTIONAL

+  )

+{

+  BROWSER_HOT_KEY  *HotKey;

+

+  //

+  // Check input parameters.

+  //

+  if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || 

+     (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Check whether the input KeyData is in BrowserHotKeyList.

+  //

+  HotKey = GetHotKeyFromRegisterList (KeyData);

+  

+  //

+  // Unregister HotKey

+  //

+  if (Action == BROWSER_ACTION_UNREGISTER) {

+    if (HotKey != NULL) {

+      //

+      // The registered HotKey is found.  

+      // Remove it from List, and free its resource.

+      //

+      RemoveEntryList (&HotKey->Link);

+      FreePool (HotKey->KeyData);

+      FreePool (HotKey->HelpString);

+      return EFI_SUCCESS;

+    } else {

+      //

+      // The registered HotKey is not found. 

+      //

+      return EFI_NOT_FOUND;

+    }

+  }

+  

+  //

+  // Register HotKey into List.

+  //

+  if (HotKey == NULL) {

+    //

+    // Create new Key, and add it into List.

+    //

+    HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));

+    ASSERT (HotKey != NULL);

+    HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;

+    HotKey->KeyData   = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);

+    InsertTailList (&gBrowserHotKeyList, &HotKey->Link);

+  }

+

+  //

+  // Fill HotKey information.

+  //

+  HotKey->Action     = Action;

+  HotKey->DefaultId  = DefaultId;

+  if (HotKey->HelpString != NULL) {

+    FreePool (HotKey->HelpString);

+  }

+  HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Register Exit handler function. 

+  When more than one handler function is registered, the latter one will override the previous one. 

+  When NULL handler is specified, the previous Exit handler will be unregistered. 

+  

+  @param[in] Handler      Pointer to handler function. 

+

+**/

+VOID

+EFIAPI

+RegiserExitHandler (

+  IN EXIT_HANDLER Handler

+  )

+{

+  ExitHandlerFunction = Handler;

+  return;

+}

+

+/**

+  Check whether the browser data has been modified.

+

+  @retval TRUE        Browser data is modified.

+  @retval FALSE       No browser data is modified.

+

+**/

+BOOLEAN

+EFIAPI

+IsBrowserDataModified (

+  VOID

+  )

+{

+  LIST_ENTRY              *Link;

+  FORM_BROWSER_FORMSET    *FormSet;

+

+  switch (gBrowserSettingScope) {

+    case FormLevel:

+      if (gCurrentSelection == NULL) {

+        return FALSE;

+      }

+      return IsNvUpdateRequiredForForm (gCurrentSelection->Form);

+

+    case FormSetLevel:

+      if (gCurrentSelection == NULL) {

+        return FALSE;

+      }

+      return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);

+

+    case SystemLevel:

+      Link = GetFirstNode (&gBrowserFormSetList);

+      while (!IsNull (&gBrowserFormSetList, Link)) {

+        FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);

+        if (!ValidateFormSet(FormSet)) {

+          continue;

+        }

+

+        if (IsNvUpdateRequiredForFormSet (FormSet)) {

+          return TRUE;

+        }

+        Link = GetNextNode (&gBrowserFormSetList, Link);

+      }

+      return FALSE;

+

+    default:

+      return FALSE;

+  }

+}

+

+/**

+  Execute the action requested by the Action parameter.

+

+  @param[in] Action     Execute the request action.

+  @param[in] DefaultId  The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.

+

+  @retval EFI_SUCCESS              Execute the request action succss.

+  @retval EFI_INVALID_PARAMETER    The input action value is invalid.

+

+**/

+EFI_STATUS 

+EFIAPI

+ExecuteAction (

+  IN UINT32        Action,

+  IN UINT16        DefaultId

+  )

+{

+  EFI_STATUS              Status;

+  FORM_BROWSER_FORMSET    *FormSet;

+  FORM_BROWSER_FORM       *Form;

+

+  if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {

+    return EFI_NOT_READY;

+  }

+

+  Status  = EFI_SUCCESS;

+  FormSet = NULL;

+  Form    = NULL;

+  if (gBrowserSettingScope < SystemLevel) {

+    FormSet = gCurrentSelection->FormSet;

+    Form    = gCurrentSelection->Form; 

+  }

+

+  //

+  // Executet the discard action.

+  //

+  if ((Action & BROWSER_ACTION_DISCARD) != 0) {

+    Status = DiscardForm (FormSet, Form, gBrowserSettingScope);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  //

+  // Executet the difault action.

+  //

+  if ((Action & BROWSER_ACTION_DEFAULT) != 0) {

+    Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);

+  }

+

+  //

+  // Executet the submit action.

+  //

+  if ((Action & BROWSER_ACTION_SUBMIT) != 0) {

+    Status = SubmitForm (FormSet, Form, gBrowserSettingScope);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  //

+  // Executet the reset action.

+  //

+  if ((Action & BROWSER_ACTION_RESET) != 0) {

+    gResetRequired = TRUE;

+  }

+

+  //

+  // Executet the exit action.

+  //

+  if ((Action & BROWSER_ACTION_EXIT) != 0) {

+    DiscardForm (FormSet, Form, gBrowserSettingScope);

+    if (gBrowserSettingScope == SystemLevel) {

+      if (ExitHandlerFunction != NULL) {

+        ExitHandlerFunction ();

+      }

+    }

+

+    gExitRequired = TRUE;

+  }

+

+  return Status;

+}

+

+/**

+  Create reminder to let user to choose save or discard the changed browser data.

+  Caller can use it to actively check the changed browser data.

+

+  @retval BROWSER_NO_CHANGES       No browser data is changed.

+  @retval BROWSER_SAVE_CHANGES     The changed browser data is saved.

+  @retval BROWSER_DISCARD_CHANGES  The changed browser data is discard.

+  @retval BROWSER_KEEP_CURRENT     Browser keep current changes.

+

+**/

+UINT32

+EFIAPI

+SaveReminder (

+  VOID

+  )

+{

+  LIST_ENTRY              *Link;

+  FORM_BROWSER_FORMSET    *FormSet;

+  BOOLEAN                 IsDataChanged;

+  UINT32                  DataSavedAction;

+  UINT32                  ConfirmRet;

+

+  DataSavedAction  = BROWSER_NO_CHANGES;

+  IsDataChanged    = FALSE;

+  Link = GetFirstNode (&gBrowserFormSetList);

+  while (!IsNull (&gBrowserFormSetList, Link)) {

+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);

+    Link = GetNextNode (&gBrowserFormSetList, Link);

+    if (!ValidateFormSet(FormSet)) {

+      continue;

+    }

+    if (IsNvUpdateRequiredForFormSet (FormSet)) {

+      IsDataChanged = TRUE;

+      break;

+    }

+  }

+  

+  //

+  // No data is changed. No save is required. 

+  //

+  if (!IsDataChanged) {

+    return DataSavedAction;

+  }

+  

+  //

+  // If data is changed, prompt user to save or discard it. 

+  //

+  do {

+    ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();

+

+    if (ConfirmRet == BROWSER_ACTION_SUBMIT) {

+      SubmitForm (NULL, NULL, SystemLevel);

+      DataSavedAction = BROWSER_SAVE_CHANGES;

+      break;

+    } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {

+      DiscardForm (NULL, NULL, SystemLevel);

+      DataSavedAction = BROWSER_DISCARD_CHANGES;

+      break;

+    } else if (ConfirmRet == BROWSER_ACTION_NONE) {

+      DataSavedAction = BROWSER_KEEP_CURRENT;

+      break;

+    }

+  } while (1);

+

+  return DataSavedAction;

+}

+

+/**

+  Check whether the Reset Required for the browser

+

+  @retval TRUE      Browser required to reset after exit.

+  @retval FALSE     Browser not need to reset after exit.

+

+**/

+BOOLEAN

+EFIAPI

+IsResetRequired (

+  VOID

+  )

+{

+  return gResetRequired;

+}

+