Home | History | Annotate | Download | only in SetupBrowserDxe
      1 /** @file
      2 Entry and initialization module for the browser.
      3 
      4 Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Setup.h"
     16 
     17 SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {
     18   SETUP_DRIVER_SIGNATURE,
     19   NULL,
     20   {
     21     SendForm,
     22     BrowserCallback
     23   },
     24   {
     25     SetScope,
     26     RegisterHotKey,
     27     RegiserExitHandler,
     28     SaveReminder
     29   },
     30   {
     31     BROWSER_EXTENSION2_VERSION_1_1,
     32     SetScope,
     33     RegisterHotKey,
     34     RegiserExitHandler,
     35     IsBrowserDataModified,
     36     ExecuteAction,
     37     {NULL,NULL},
     38     {NULL,NULL},
     39     IsResetRequired
     40   }
     41 };
     42 
     43 EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;
     44 EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;
     45 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
     46 EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
     47 
     48 UINTN           gBrowserContextCount = 0;
     49 LIST_ENTRY      gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
     50 LIST_ENTRY      gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
     51 LIST_ENTRY      gBrowserHotKeyList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
     52 LIST_ENTRY      gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
     53 LIST_ENTRY      gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList);
     54 
     55 BOOLEAN               mSystemSubmit = FALSE;
     56 BOOLEAN               gResetRequired;
     57 BOOLEAN               gExitRequired;
     58 BOOLEAN               gFlagReconnect;
     59 BOOLEAN               gCallbackReconnect;
     60 BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
     61 BOOLEAN               mBrowserScopeFirstSet = TRUE;
     62 EXIT_HANDLER          ExitHandlerFunction = NULL;
     63 FORM_BROWSER_FORMSET  *mSystemLevelFormSet;
     64 
     65 //
     66 // Browser Global Strings
     67 //
     68 CHAR16            *gEmptyString;
     69 CHAR16            *mUnknownString = L"!";
     70 
     71 extern EFI_GUID        mCurrentFormSetGuid;
     72 extern EFI_HII_HANDLE  mCurrentHiiHandle;
     73 extern UINT16          mCurrentFormId;
     74 extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
     75 
     76 /**
     77   Create a menu with specified formset GUID and form ID, and add it as a child
     78   of the given parent menu.
     79 
     80   @param  HiiHandle              Hii handle related to this formset.
     81   @param  FormSetGuid            The Formset Guid of menu to be added.
     82   @param  FormId                 The Form ID of menu to be added.
     83   @param  QuestionId             The question id of this menu to be added.
     84 
     85   @return A pointer to the newly added menu or NULL if memory is insufficient.
     86 
     87 **/
     88 FORM_ENTRY_INFO *
     89 UiAddMenuList (
     90   IN EFI_HII_HANDLE       HiiHandle,
     91   IN EFI_GUID             *FormSetGuid,
     92   IN UINT16               FormId,
     93   IN UINT16               QuestionId
     94   )
     95 {
     96   FORM_ENTRY_INFO  *MenuList;
     97 
     98   MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
     99   if (MenuList == NULL) {
    100     return NULL;
    101   }
    102 
    103   MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;
    104 
    105   MenuList->HiiHandle  = HiiHandle;
    106   CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
    107   MenuList->FormId     = FormId;
    108   MenuList->QuestionId = QuestionId;
    109 
    110   //
    111   // If parent is not specified, it is the root Form of a Formset
    112   //
    113   InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
    114 
    115   return MenuList;
    116 }
    117 
    118 /**
    119   Return the form id for the input hiihandle and formset.
    120 
    121   @param  HiiHandle              HiiHandle for FormSet.
    122   @param  FormSetGuid            The Formset GUID of the menu to search.
    123 
    124   @return First form's id for this form set.
    125 
    126 **/
    127 EFI_FORM_ID
    128 GetFirstFormId (
    129   IN EFI_HII_HANDLE       HiiHandle,
    130   IN EFI_GUID             *FormSetGuid
    131   )
    132 {
    133   LIST_ENTRY         *Link;
    134   FORM_BROWSER_FORM  *Form;
    135 
    136   Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);
    137   Form = FORM_BROWSER_FORM_FROM_LINK (Link);
    138 
    139   return Form->FormId;
    140 }
    141 
    142 /**
    143   Search Menu with given FormSetGuid and FormId in all cached menu list.
    144 
    145   @param  HiiHandle              HiiHandle for FormSet.
    146   @param  FormSetGuid            The Formset GUID of the menu to search.
    147   @param  FormId                 The Form ID of menu to search.
    148 
    149   @return A pointer to menu found or NULL if not found.
    150 
    151 **/
    152 FORM_ENTRY_INFO *
    153 UiFindMenuList (
    154   IN EFI_HII_HANDLE       HiiHandle,
    155   IN EFI_GUID             *FormSetGuid,
    156   IN UINT16               FormId
    157   )
    158 {
    159   LIST_ENTRY         *Link;
    160   FORM_ENTRY_INFO    *MenuList;
    161   FORM_ENTRY_INFO    *RetMenu;
    162   EFI_FORM_ID        FirstFormId;
    163 
    164   RetMenu = NULL;
    165 
    166   Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
    167   while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {
    168     MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
    169     Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);
    170 
    171     //
    172     // If already find the menu, free the menus behind it.
    173     //
    174     if (RetMenu != NULL) {
    175       RemoveEntryList (&MenuList->Link);
    176       FreePool (MenuList);
    177       continue;
    178     }
    179 
    180     //
    181     // Find the same FromSet.
    182     //
    183     if (MenuList->HiiHandle == HiiHandle) {
    184       if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) {
    185         //
    186         // FormSetGuid is not specified.
    187         //
    188         RetMenu = MenuList;
    189       } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {
    190         if (MenuList->FormId == FormId) {
    191           RetMenu = MenuList;
    192         } else if (FormId == 0 || MenuList->FormId == 0 ) {
    193           FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);
    194           if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {
    195             RetMenu = MenuList;
    196           }
    197         }
    198       }
    199     }
    200   }
    201 
    202   return RetMenu;
    203 }
    204 
    205 /**
    206   Find parent menu for current menu.
    207 
    208   @param  CurrentMenu    Current Menu
    209   @param  SettingLevel   Whether find parent menu in Form Level or Formset level.
    210                          In form level, just find the parent menu;
    211                          In formset level, find the parent menu which has different
    212                          formset guid value.
    213 
    214   @retval   The parent menu for current menu.
    215 **/
    216 FORM_ENTRY_INFO *
    217 UiFindParentMenu (
    218   IN FORM_ENTRY_INFO          *CurrentMenu,
    219   IN BROWSER_SETTING_SCOPE    SettingLevel
    220   )
    221 {
    222   FORM_ENTRY_INFO    *ParentMenu;
    223   LIST_ENTRY         *Link;
    224 
    225   ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel);
    226 
    227   if (CurrentMenu == NULL) {
    228     return NULL;
    229   }
    230 
    231   ParentMenu = NULL;
    232   Link       = &CurrentMenu->Link;
    233 
    234   while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
    235     ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink);
    236 
    237     if (SettingLevel == FormLevel) {
    238       //
    239       // For FormLevel, just find the parent menu, return.
    240       //
    241       break;
    242     }
    243 
    244     if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
    245       //
    246       // For SystemLevel, must find the menu which has different formset.
    247       //
    248       break;
    249     }
    250 
    251     Link = Link->BackLink;
    252   }
    253 
    254   //
    255   // Not find the parent menu, just return NULL.
    256   //
    257   if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
    258     return NULL;
    259   }
    260 
    261   return ParentMenu;
    262 }
    263 
    264 /**
    265   Free Menu list linked list.
    266 
    267   @param  MenuListHead    One Menu list point in the menu list.
    268 
    269 **/
    270 VOID
    271 UiFreeMenuList (
    272   LIST_ENTRY   *MenuListHead
    273   )
    274 {
    275   FORM_ENTRY_INFO    *MenuList;
    276 
    277   while (!IsListEmpty (MenuListHead)) {
    278     MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);
    279     RemoveEntryList (&MenuList->Link);
    280 
    281     FreePool (MenuList);
    282   }
    283 }
    284 
    285 /**
    286   Copy current Menu list to the new menu list.
    287 
    288   @param  NewMenuListHead        New create Menu list.
    289   @param  CurrentMenuListHead    Current Menu list.
    290 
    291 **/
    292 VOID
    293 UiCopyMenuList (
    294   OUT LIST_ENTRY   *NewMenuListHead,
    295   IN  LIST_ENTRY   *CurrentMenuListHead
    296   )
    297 {
    298   LIST_ENTRY         *Link;
    299   FORM_ENTRY_INFO    *MenuList;
    300   FORM_ENTRY_INFO    *NewMenuEntry;
    301 
    302   //
    303   // If new menu list not empty, free it first.
    304   //
    305   UiFreeMenuList (NewMenuListHead);
    306 
    307   Link = GetFirstNode (CurrentMenuListHead);
    308   while (!IsNull (CurrentMenuListHead, Link)) {
    309     MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
    310     Link = GetNextNode (CurrentMenuListHead, Link);
    311 
    312     NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
    313     ASSERT (NewMenuEntry != NULL);
    314     NewMenuEntry->Signature  = FORM_ENTRY_INFO_SIGNATURE;
    315     NewMenuEntry->HiiHandle  = MenuList->HiiHandle;
    316     CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID));
    317     NewMenuEntry->FormId     = MenuList->FormId;
    318     NewMenuEntry->QuestionId = MenuList->QuestionId;
    319 
    320     InsertTailList (NewMenuListHead, &NewMenuEntry->Link);
    321   }
    322 }
    323 
    324 /**
    325   Load all hii formset to the browser.
    326 
    327 **/
    328 VOID
    329 LoadAllHiiFormset (
    330   VOID
    331   )
    332 {
    333   FORM_BROWSER_FORMSET    *LocalFormSet;
    334   EFI_HII_HANDLE          *HiiHandles;
    335   UINTN                   Index;
    336   EFI_GUID                ZeroGuid;
    337   EFI_STATUS              Status;
    338   FORM_BROWSER_FORMSET    *OldFormset;
    339 
    340   OldFormset = mSystemLevelFormSet;
    341 
    342   //
    343   // Get all the Hii handles
    344   //
    345   HiiHandles = HiiGetHiiHandles (NULL);
    346   ASSERT (HiiHandles != NULL);
    347 
    348   //
    349   // Search for formset of each class type
    350   //
    351   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
    352     //
    353     // Check HiiHandles[Index] does exist in global maintain list.
    354     //
    355     if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
    356       continue;
    357     }
    358 
    359     //
    360     // Initilize FormSet Setting
    361     //
    362     LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
    363     ASSERT (LocalFormSet != NULL);
    364     mSystemLevelFormSet = LocalFormSet;
    365 
    366     ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
    367     Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);
    368     if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
    369       DestroyFormSet (LocalFormSet);
    370       continue;
    371     }
    372     InitializeCurrentSetting (LocalFormSet);
    373 
    374     //
    375     // Initilize Questions' Value
    376     //
    377     Status = LoadFormSetConfig (NULL, LocalFormSet);
    378     if (EFI_ERROR (Status)) {
    379       DestroyFormSet (LocalFormSet);
    380       continue;
    381     }
    382   }
    383 
    384   //
    385   // Free resources, and restore gOldFormSet and gClassOfVfr
    386   //
    387   FreePool (HiiHandles);
    388 
    389   mSystemLevelFormSet = OldFormset;
    390 }
    391 
    392 /**
    393   Pop up the error info.
    394 
    395   @param      BrowserStatus    The input browser status.
    396   @param      HiiHandle        The Hiihandle for this opcode.
    397   @param      OpCode           The opcode use to get the erro info and timeout value.
    398   @param      ErrorString      Error string used by BROWSER_NO_SUBMIT_IF.
    399 
    400 **/
    401 UINT32
    402 PopupErrorMessage (
    403   IN UINT32                BrowserStatus,
    404   IN EFI_HII_HANDLE        HiiHandle,
    405   IN EFI_IFR_OP_HEADER     *OpCode, OPTIONAL
    406   IN CHAR16                *ErrorString
    407   )
    408 {
    409   FORM_DISPLAY_ENGINE_STATEMENT *Statement;
    410   USER_INPUT                    UserInputData;
    411 
    412   Statement = NULL;
    413 
    414   if (OpCode != NULL) {
    415     Statement = AllocateZeroPool (sizeof(FORM_DISPLAY_ENGINE_STATEMENT));
    416     ASSERT (Statement != NULL);
    417     Statement->OpCode = OpCode;
    418     gDisplayFormData.HighLightedStatement = Statement;
    419   }
    420 
    421   //
    422   // Used to compatible with old display engine.
    423   // New display engine not use this field.
    424   //
    425   gDisplayFormData.ErrorString   = ErrorString;
    426   gDisplayFormData.BrowserStatus = BrowserStatus;
    427 
    428   if (HiiHandle != NULL) {
    429     gDisplayFormData.HiiHandle     = HiiHandle;
    430   }
    431 
    432   mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData);
    433 
    434   gDisplayFormData.BrowserStatus = BROWSER_SUCCESS;
    435   gDisplayFormData.ErrorString   = NULL;
    436 
    437   if (OpCode != NULL) {
    438     FreePool (Statement);
    439   }
    440 
    441   return UserInputData.Action;
    442 }
    443 
    444 /**
    445   This is the routine which an external caller uses to direct the browser
    446   where to obtain it's information.
    447 
    448 
    449   @param This            The Form Browser protocol instanse.
    450   @param Handles         A pointer to an array of Handles.  If HandleCount > 1 we
    451                          display a list of the formsets for the handles specified.
    452   @param HandleCount     The number of Handles specified in Handle.
    453   @param FormSetGuid     This field points to the EFI_GUID which must match the Guid
    454                          field in the EFI_IFR_FORM_SET op-code for the specified
    455                          forms-based package. If FormSetGuid is NULL, then this
    456                          function will display the first found forms package.
    457   @param FormId          This field specifies which EFI_IFR_FORM to render as the first
    458                          displayable page. If this field has a value of 0x0000, then
    459                          the forms browser will render the specified forms in their encoded order.
    460   @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
    461                           characters.
    462   @param ActionRequest   Points to the action recommended by the form.
    463 
    464   @retval  EFI_SUCCESS            The function completed successfully.
    465   @retval  EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
    466   @retval  EFI_NOT_FOUND          No valid forms could be found to display.
    467 
    468 **/
    469 EFI_STATUS
    470 EFIAPI
    471 SendForm (
    472   IN  CONST EFI_FORM_BROWSER2_PROTOCOL *This,
    473   IN  EFI_HII_HANDLE                   *Handles,
    474   IN  UINTN                            HandleCount,
    475   IN  EFI_GUID                         *FormSetGuid, OPTIONAL
    476   IN  UINT16                           FormId, OPTIONAL
    477   IN  CONST EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL
    478   OUT EFI_BROWSER_ACTION_REQUEST       *ActionRequest  OPTIONAL
    479   )
    480 {
    481   EFI_STATUS                    Status;
    482   UI_MENU_SELECTION             *Selection;
    483   UINTN                         Index;
    484   FORM_BROWSER_FORMSET          *FormSet;
    485   FORM_ENTRY_INFO               *MenuList;
    486   BOOLEAN                       RetVal;
    487 
    488   //
    489   // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.
    490   //
    491   if (mFormDisplay == NULL) {
    492     DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!"));
    493     return EFI_UNSUPPORTED;
    494   }
    495 
    496   //
    497   // Save globals used by SendForm()
    498   //
    499   SaveBrowserContext ();
    500 
    501   gFlagReconnect = FALSE;
    502   gResetRequired = FALSE;
    503   gExitRequired  = FALSE;
    504   gCallbackReconnect = FALSE;
    505   Status         = EFI_SUCCESS;
    506   gEmptyString   = L"";
    507   gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;
    508 
    509   for (Index = 0; Index < HandleCount; Index++) {
    510     Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
    511     ASSERT (Selection != NULL);
    512 
    513     Selection->Handle = Handles[Index];
    514     if (FormSetGuid != NULL) {
    515       CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
    516       Selection->FormId = FormId;
    517     } else {
    518       CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));
    519     }
    520 
    521     do {
    522       FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
    523       ASSERT (FormSet != NULL);
    524 
    525       //
    526       // Validate the HiiHandle
    527       // if validate failed, find the first validate parent HiiHandle.
    528       //
    529       if (!ValidateHiiHandle(Selection->Handle)) {
    530         FindNextMenu (Selection, FormSetLevel);
    531       }
    532 
    533       //
    534       // Initialize internal data structures of FormSet
    535       //
    536       Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
    537       if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
    538         DestroyFormSet (FormSet);
    539         break;
    540       }
    541       Selection->FormSet = FormSet;
    542       mSystemLevelFormSet = FormSet;
    543 
    544       //
    545       // Display this formset
    546       //
    547       gCurrentSelection = Selection;
    548 
    549       Status = SetupBrowser (Selection);
    550 
    551       gCurrentSelection = NULL;
    552       mSystemLevelFormSet = NULL;
    553 
    554       if (gFlagReconnect || gCallbackReconnect) {
    555         RetVal = ReconnectController (FormSet->DriverHandle);
    556         if (!RetVal) {
    557           PopupErrorMessage(BROWSER_RECONNECT_FAIL, NULL, NULL, NULL);
    558         }
    559         gFlagReconnect = FALSE;
    560         gCallbackReconnect = FALSE;
    561       }
    562 
    563       //
    564       // If no data is changed, don't need to save current FormSet into the maintain list.
    565       //
    566       if (!IsNvUpdateRequiredForFormSet (FormSet)) {
    567         CleanBrowserStorage(FormSet);
    568         RemoveEntryList (&FormSet->Link);
    569         DestroyFormSet (FormSet);
    570       }
    571 
    572       if (EFI_ERROR (Status)) {
    573         break;
    574       }
    575     } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
    576 
    577     FreePool (Selection);
    578   }
    579 
    580   if (ActionRequest != NULL) {
    581     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
    582     if (gResetRequired) {
    583       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
    584     }
    585   }
    586 
    587   mFormDisplay->ExitDisplay();
    588 
    589   //
    590   // Clear the menu history data.
    591   //
    592   while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
    593     MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
    594     RemoveEntryList (&MenuList->Link);
    595     FreePool (MenuList);
    596   }
    597 
    598   //
    599   // Restore globals used by SendForm()
    600   //
    601   RestoreBrowserContext ();
    602 
    603   return Status;
    604 }
    605 
    606 /**
    607   Get or set data to the storage.
    608 
    609   @param  ResultsDataSize        The size of the buffer associatedwith ResultsData.
    610   @param  ResultsData            A string returned from an IFR browser or
    611                                  equivalent. The results string will have no
    612                                  routing information in them.
    613   @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve
    614                                  (if RetrieveData = TRUE) data from the uncommitted
    615                                  browser state information or set (if RetrieveData
    616                                  = FALSE) data in the uncommitted browser state
    617                                  information.
    618   @param  Storage                The pointer to the storage.
    619 
    620   @retval EFI_SUCCESS            The results have been distributed or are awaiting
    621                                  distribution.
    622 
    623 **/
    624 EFI_STATUS
    625 ProcessStorage (
    626   IN OUT UINTN                         *ResultsDataSize,
    627   IN OUT EFI_STRING                    *ResultsData,
    628   IN BOOLEAN                           RetrieveData,
    629   IN BROWSER_STORAGE                   *Storage
    630   )
    631 {
    632   CHAR16                *ConfigResp;
    633   EFI_STATUS            Status;
    634   CHAR16                *StrPtr;
    635   UINTN                 BufferSize;
    636   UINTN                 TmpSize;
    637   UINTN                 MaxLen;
    638   FORMSET_STORAGE       *BrowserStorage;
    639 
    640   if (RetrieveData) {
    641     //
    642     // Generate <ConfigResp>
    643     //
    644     Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);
    645     if (EFI_ERROR (Status)) {
    646       return Status;
    647     }
    648 
    649     //
    650     // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.
    651     // Also need to consider add "\0" at first time.
    652     //
    653     StrPtr = StrStr (ConfigResp, L"PATH");
    654     ASSERT (StrPtr != NULL);
    655     StrPtr = StrStr (StrPtr, L"&");
    656     StrPtr += 1;
    657     BufferSize = StrSize (StrPtr);
    658 
    659     //
    660     // Copy the data if the input buffer is bigger enough.
    661     //
    662     if (*ResultsDataSize >= BufferSize) {
    663       StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr);
    664     }
    665 
    666     *ResultsDataSize = BufferSize;
    667     FreePool (ConfigResp);
    668   } else {
    669     //
    670     // Prepare <ConfigResp>
    671     //
    672     BrowserStorage = GetFstStgFromBrsStg (Storage);
    673     ASSERT (BrowserStorage != NULL);
    674     TmpSize = StrLen (*ResultsData);
    675     BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);
    676     MaxLen = BufferSize / sizeof (CHAR16);
    677     ConfigResp = AllocateZeroPool (BufferSize);
    678     ASSERT (ConfigResp != NULL);
    679 
    680     StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr);
    681     StrCatS (ConfigResp, MaxLen, L"&");
    682     StrCatS (ConfigResp, MaxLen, *ResultsData);
    683 
    684     //
    685     // Update Browser uncommited data
    686     //
    687     Status = ConfigRespToStorage (Storage, ConfigResp);
    688     FreePool (ConfigResp);
    689     if (EFI_ERROR (Status)) {
    690       return Status;
    691     }
    692   }
    693 
    694   return EFI_SUCCESS;
    695 }
    696 
    697 /**
    698   This routine called this service in the browser to retrieve or set certain uncommitted
    699   state information that resides in the open formsets.
    700 
    701   @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL
    702                                  instance.
    703   @param  ResultsDataSize        A pointer to the size of the buffer associated
    704                                  with ResultsData.
    705   @param  ResultsData            A string returned from an IFR browser or
    706                                  equivalent. The results string will have no
    707                                  routing information in them.
    708   @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve
    709                                  (if RetrieveData = TRUE) data from the uncommitted
    710                                  browser state information or set (if RetrieveData
    711                                  = FALSE) data in the uncommitted browser state
    712                                  information.
    713   @param  VariableGuid           An optional field to indicate the target variable
    714                                  GUID name to use.
    715   @param  VariableName           An optional field to indicate the target
    716                                  human-readable variable name.
    717 
    718   @retval EFI_SUCCESS            The results have been distributed or are awaiting
    719                                  distribution.
    720   @retval EFI_BUFFER_TOO_SMALL   The ResultsDataSize specified was too small to
    721                                  contain the results data.
    722 
    723 **/
    724 EFI_STATUS
    725 EFIAPI
    726 BrowserCallback (
    727   IN CONST EFI_FORM_BROWSER2_PROTOCOL  *This,
    728   IN OUT UINTN                         *ResultsDataSize,
    729   IN OUT EFI_STRING                    ResultsData,
    730   IN BOOLEAN                           RetrieveData,
    731   IN CONST EFI_GUID                    *VariableGuid, OPTIONAL
    732   IN CONST CHAR16                      *VariableName  OPTIONAL
    733   )
    734 {
    735   EFI_STATUS            Status;
    736   LIST_ENTRY            *Link;
    737   BROWSER_STORAGE       *Storage;
    738   FORMSET_STORAGE       *FormsetStorage;
    739   UINTN                 TotalSize;
    740   BOOLEAN               Found;
    741 
    742   if (ResultsDataSize == NULL || ResultsData == NULL) {
    743     return EFI_INVALID_PARAMETER;
    744   }
    745 
    746   TotalSize = *ResultsDataSize;
    747   Storage   = NULL;
    748   Found     = FALSE;
    749   Status    = EFI_SUCCESS;
    750 
    751   if (VariableGuid != NULL) {
    752     //
    753     // Try to find target storage in the current formset.
    754     //
    755     Link = GetFirstNode (&gBrowserStorageList);
    756     while (!IsNull (&gBrowserStorageList, Link)) {
    757       Storage = BROWSER_STORAGE_FROM_LINK (Link);
    758       Link = GetNextNode (&gBrowserStorageList, Link);
    759       //
    760       // Check the current storage.
    761       //
    762       if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
    763         continue;
    764       }
    765 
    766       if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
    767           Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
    768         //
    769         // Buffer storage require both GUID and Name
    770         //
    771         if (VariableName == NULL) {
    772           return EFI_NOT_FOUND;
    773         }
    774 
    775         if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
    776           continue;
    777         }
    778       }
    779 
    780       if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE ||
    781           Storage->Type == EFI_HII_VARSTORE_BUFFER) {
    782         if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) {
    783           return EFI_NOT_FOUND;
    784         }
    785 
    786         if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {
    787           continue;
    788         }
    789       }
    790 
    791       Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);
    792       if (EFI_ERROR (Status)) {
    793         return Status;
    794       }
    795 
    796       if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
    797         ConfigRequestAdjust (Storage, ResultsData, TRUE);
    798       }
    799 
    800       //
    801       // Different formsets may have same varstore, so here just set the flag
    802       // not exit the circle.
    803       //
    804       Found = TRUE;
    805       break;
    806     }
    807 
    808     if (!Found) {
    809       return EFI_NOT_FOUND;
    810     }
    811   } else {
    812     //
    813     // GUID/Name is not specified, take the first storage in FormSet
    814     //
    815     if (mSystemLevelFormSet == NULL) {
    816       return EFI_NOT_READY;
    817     }
    818 
    819     //
    820     // Generate <ConfigResp>
    821     //
    822     Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);
    823     if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {
    824       return EFI_UNSUPPORTED;
    825     }
    826 
    827     FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
    828 
    829     Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);
    830     if (EFI_ERROR (Status)) {
    831       return Status;
    832     }
    833   }
    834 
    835   if (RetrieveData) {
    836     Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
    837     *ResultsDataSize = TotalSize;
    838   }
    839 
    840   return Status;
    841 
    842 }
    843 
    844 
    845 /**
    846   Callback function for SimpleTextInEx protocol install events
    847 
    848   @param Event           the event that is signaled.
    849   @param Context         not used here.
    850 
    851 **/
    852 VOID
    853 EFIAPI
    854 FormDisplayCallback (
    855   IN EFI_EVENT    Event,
    856   IN VOID         *Context
    857   )
    858 {
    859   if (mFormDisplay != NULL) {
    860     return;
    861   }
    862 
    863   gBS->LocateProtocol (
    864                   &gEdkiiFormDisplayEngineProtocolGuid,
    865                   NULL,
    866                   (VOID **) &mFormDisplay
    867                   );
    868 }
    869 
    870 /**
    871   Initialize Setup Browser driver.
    872 
    873   @param ImageHandle     The image handle.
    874   @param SystemTable     The system table.
    875 
    876   @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..
    877   @return Other value if failed to initialize the Setup Browser module.
    878 
    879 **/
    880 EFI_STATUS
    881 EFIAPI
    882 InitializeSetup (
    883   IN EFI_HANDLE           ImageHandle,
    884   IN EFI_SYSTEM_TABLE     *SystemTable
    885   )
    886 {
    887   EFI_STATUS                  Status;
    888   VOID                        *Registration;
    889 
    890   //
    891   // Locate required Hii relative protocols
    892   //
    893   Status = gBS->LocateProtocol (
    894                   &gEfiHiiDatabaseProtocolGuid,
    895                   NULL,
    896                   (VOID **) &mHiiDatabase
    897                   );
    898   ASSERT_EFI_ERROR (Status);
    899 
    900   Status = gBS->LocateProtocol (
    901                   &gEfiHiiConfigRoutingProtocolGuid,
    902                   NULL,
    903                   (VOID **) &mHiiConfigRouting
    904                   );
    905   ASSERT_EFI_ERROR (Status);
    906 
    907   Status = gBS->LocateProtocol (
    908                   &gEfiDevicePathFromTextProtocolGuid,
    909                   NULL,
    910                   (VOID **) &mPathFromText
    911                   );
    912 
    913   //
    914   // Install FormBrowser2 protocol
    915   //
    916   mPrivateData.Handle = NULL;
    917   Status = gBS->InstallProtocolInterface (
    918                   &mPrivateData.Handle,
    919                   &gEfiFormBrowser2ProtocolGuid,
    920                   EFI_NATIVE_INTERFACE,
    921                   &mPrivateData.FormBrowser2
    922                   );
    923   ASSERT_EFI_ERROR (Status);
    924 
    925   //
    926   // Install FormBrowserEx2 protocol
    927   //
    928   InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
    929   InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
    930   mPrivateData.Handle = NULL;
    931   Status = gBS->InstallProtocolInterface (
    932                   &mPrivateData.Handle,
    933                   &gEdkiiFormBrowserEx2ProtocolGuid,
    934                   EFI_NATIVE_INTERFACE,
    935                   &mPrivateData.FormBrowserEx2
    936                   );
    937   ASSERT_EFI_ERROR (Status);
    938 
    939   Status = gBS->InstallProtocolInterface (
    940                   &mPrivateData.Handle,
    941                   &gEfiFormBrowserExProtocolGuid,
    942                   EFI_NATIVE_INTERFACE,
    943                   &mPrivateData.FormBrowserEx
    944                   );
    945   ASSERT_EFI_ERROR (Status);
    946 
    947   InitializeDisplayFormData ();
    948 
    949   Status = gBS->LocateProtocol (
    950                   &gEdkiiFormDisplayEngineProtocolGuid,
    951                   NULL,
    952                   (VOID **) &mFormDisplay
    953                   );
    954 
    955   if (EFI_ERROR (Status)) {
    956     EfiCreateProtocolNotifyEvent (
    957       &gEdkiiFormDisplayEngineProtocolGuid,
    958       TPL_CALLBACK,
    959       FormDisplayCallback,
    960       NULL,
    961       &Registration
    962       );
    963   }
    964 
    965   return EFI_SUCCESS;
    966 }
    967 
    968 
    969 /**
    970   Create a new string in HII Package List.
    971 
    972   @param  String                 The String to be added
    973   @param  HiiHandle              The package list in the HII database to insert the
    974                                  specified string.
    975 
    976   @return The output string.
    977 
    978 **/
    979 EFI_STRING_ID
    980 NewString (
    981   IN  CHAR16                   *String,
    982   IN  EFI_HII_HANDLE           HiiHandle
    983   )
    984 {
    985   EFI_STRING_ID  StringId;
    986 
    987   StringId = HiiSetString (HiiHandle, 0, String, NULL);
    988   ASSERT (StringId != 0);
    989 
    990   return StringId;
    991 }
    992 
    993 
    994 /**
    995   Delete a string from HII Package List.
    996 
    997   @param  StringId               Id of the string in HII database.
    998   @param  HiiHandle              The HII package list handle.
    999 
   1000   @retval EFI_SUCCESS            The string was deleted successfully.
   1001 
   1002 **/
   1003 EFI_STATUS
   1004 DeleteString (
   1005   IN  EFI_STRING_ID            StringId,
   1006   IN  EFI_HII_HANDLE           HiiHandle
   1007   )
   1008 {
   1009   CHAR16  NullChar;
   1010 
   1011   NullChar = CHAR_NULL;
   1012   HiiSetString (HiiHandle, StringId, &NullChar, NULL);
   1013   return EFI_SUCCESS;
   1014 }
   1015 
   1016 
   1017 /**
   1018   Get the string based on the StringId and HII Package List Handle.
   1019 
   1020   @param  Token                  The String's ID.
   1021   @param  HiiHandle              The package list in the HII database to search for
   1022                                  the specified string.
   1023 
   1024   @return The output string.
   1025 
   1026 **/
   1027 CHAR16 *
   1028 GetToken (
   1029   IN  EFI_STRING_ID                Token,
   1030   IN  EFI_HII_HANDLE               HiiHandle
   1031   )
   1032 {
   1033   EFI_STRING  String;
   1034 
   1035   if (HiiHandle == NULL) {
   1036     return NULL;
   1037   }
   1038 
   1039   String = HiiGetString (HiiHandle, Token, NULL);
   1040   if (String == NULL) {
   1041     String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
   1042     ASSERT (String != NULL);
   1043   }
   1044   return (CHAR16 *) String;
   1045 }
   1046 
   1047 
   1048 /**
   1049   Allocate new memory and then copy the Unicode string Source to Destination.
   1050 
   1051   @param  Dest                   Location to copy string
   1052   @param  Src                    String to copy
   1053 
   1054 **/
   1055 VOID
   1056 NewStringCpy (
   1057   IN OUT CHAR16       **Dest,
   1058   IN CHAR16           *Src
   1059   )
   1060 {
   1061   if (*Dest != NULL) {
   1062     FreePool (*Dest);
   1063   }
   1064   *Dest = AllocateCopyPool (StrSize (Src), Src);
   1065   ASSERT (*Dest != NULL);
   1066 }
   1067 
   1068 
   1069 /**
   1070   Allocate new memory and concatinate Source on the end of Destination.
   1071 
   1072   @param  Dest                   String to added to the end of.
   1073   @param  Src                    String to concatinate.
   1074 
   1075 **/
   1076 VOID
   1077 NewStringCat (
   1078   IN OUT CHAR16       **Dest,
   1079   IN CHAR16           *Src
   1080   )
   1081 {
   1082   CHAR16  *NewString;
   1083   UINTN   MaxLen;
   1084 
   1085   if (*Dest == NULL) {
   1086     NewStringCpy (Dest, Src);
   1087     return;
   1088   }
   1089 
   1090   MaxLen = ( StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16);
   1091   NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1092   ASSERT (NewString != NULL);
   1093 
   1094   StrCpyS (NewString, MaxLen, *Dest);
   1095   StrCatS (NewString, MaxLen, Src);
   1096 
   1097   FreePool (*Dest);
   1098   *Dest = NewString;
   1099 }
   1100 
   1101 /**
   1102   Get Value for given Name from a NameValue Storage.
   1103 
   1104   @param  Storage                The NameValue Storage.
   1105   @param  Name                   The Name.
   1106   @param  Value                  The retured Value.
   1107   @param  GetValueFrom           Where to get source value, from EditValue or Value.
   1108 
   1109   @retval EFI_SUCCESS            Value found for given Name.
   1110   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
   1111 
   1112 **/
   1113 EFI_STATUS
   1114 GetValueByName (
   1115   IN BROWSER_STORAGE             *Storage,
   1116   IN CHAR16                      *Name,
   1117   IN OUT CHAR16                  **Value,
   1118   IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
   1119   )
   1120 {
   1121   LIST_ENTRY              *Link;
   1122   NAME_VALUE_NODE         *Node;
   1123 
   1124   if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {
   1125     return EFI_INVALID_PARAMETER;
   1126   }
   1127 
   1128   *Value = NULL;
   1129 
   1130   Link = GetFirstNode (&Storage->NameValueListHead);
   1131   while (!IsNull (&Storage->NameValueListHead, Link)) {
   1132     Node = NAME_VALUE_NODE_FROM_LINK (Link);
   1133 
   1134     if (StrCmp (Name, Node->Name) == 0) {
   1135       if (GetValueFrom == GetSetValueWithEditBuffer) {
   1136         NewStringCpy (Value, Node->EditValue);
   1137       } else {
   1138         NewStringCpy (Value, Node->Value);
   1139       }
   1140       return EFI_SUCCESS;
   1141     }
   1142 
   1143     Link = GetNextNode (&Storage->NameValueListHead, Link);
   1144   }
   1145 
   1146   return EFI_NOT_FOUND;
   1147 }
   1148 
   1149 
   1150 /**
   1151   Set Value of given Name in a NameValue Storage.
   1152 
   1153   @param  Storage                The NameValue Storage.
   1154   @param  Name                   The Name.
   1155   @param  Value                  The Value to set.
   1156   @param  SetValueTo             Whether update editValue or Value.
   1157   @param  ReturnNode             The node use the input name.
   1158 
   1159   @retval EFI_SUCCESS            Value found for given Name.
   1160   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
   1161 
   1162 **/
   1163 EFI_STATUS
   1164 SetValueByName (
   1165   IN  BROWSER_STORAGE             *Storage,
   1166   IN  CHAR16                      *Name,
   1167   IN  CHAR16                      *Value,
   1168   IN  GET_SET_QUESTION_VALUE_WITH SetValueTo,
   1169   OUT NAME_VALUE_NODE             **ReturnNode
   1170   )
   1171 {
   1172   LIST_ENTRY              *Link;
   1173   NAME_VALUE_NODE         *Node;
   1174   CHAR16                  *Buffer;
   1175 
   1176   if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {
   1177     return EFI_INVALID_PARAMETER;
   1178   }
   1179 
   1180   Link = GetFirstNode (&Storage->NameValueListHead);
   1181   while (!IsNull (&Storage->NameValueListHead, Link)) {
   1182     Node = NAME_VALUE_NODE_FROM_LINK (Link);
   1183 
   1184     if (StrCmp (Name, Node->Name) == 0) {
   1185       if (SetValueTo == GetSetValueWithEditBuffer) {
   1186         Buffer = Node->EditValue;
   1187       } else {
   1188         Buffer = Node->Value;
   1189       }
   1190       if (Buffer != NULL) {
   1191         FreePool (Buffer);
   1192       }
   1193       Buffer = AllocateCopyPool (StrSize (Value), Value);
   1194       ASSERT (Buffer != NULL);
   1195       if (SetValueTo == GetSetValueWithEditBuffer) {
   1196         Node->EditValue = Buffer;
   1197       } else {
   1198         Node->Value = Buffer;
   1199       }
   1200 
   1201       if (ReturnNode != NULL) {
   1202         *ReturnNode = Node;
   1203       }
   1204 
   1205       return EFI_SUCCESS;
   1206     }
   1207 
   1208     Link = GetNextNode (&Storage->NameValueListHead, Link);
   1209   }
   1210 
   1211   return EFI_NOT_FOUND;
   1212 }
   1213 
   1214 
   1215 /**
   1216   Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
   1217 
   1218   @param  Storage                The Storage to be conveted.
   1219   @param  ConfigResp             The returned <ConfigResp>.
   1220   @param  ConfigRequest          The ConfigRequest string.
   1221   @param  GetEditBuf             Get the data from editbuffer or buffer.
   1222 
   1223   @retval EFI_SUCCESS            Convert success.
   1224   @retval EFI_INVALID_PARAMETER  Incorrect storage type.
   1225 
   1226 **/
   1227 EFI_STATUS
   1228 StorageToConfigResp (
   1229   IN BROWSER_STORAGE         *Storage,
   1230   IN CHAR16                  **ConfigResp,
   1231   IN CHAR16                  *ConfigRequest,
   1232   IN BOOLEAN                 GetEditBuf
   1233   )
   1234 {
   1235   EFI_STATUS              Status;
   1236   EFI_STRING              Progress;
   1237   LIST_ENTRY              *Link;
   1238   NAME_VALUE_NODE         *Node;
   1239   UINT8                   *SourceBuf;
   1240   FORMSET_STORAGE         *FormsetStorage;
   1241 
   1242   Status = EFI_SUCCESS;
   1243 
   1244   switch (Storage->Type) {
   1245   case EFI_HII_VARSTORE_BUFFER:
   1246   case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
   1247     SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;
   1248     Status = mHiiConfigRouting->BlockToConfig (
   1249                                   mHiiConfigRouting,
   1250                                   ConfigRequest,
   1251                                   SourceBuf,
   1252                                   Storage->Size,
   1253                                   ConfigResp,
   1254                                   &Progress
   1255                                   );
   1256     break;
   1257 
   1258   case EFI_HII_VARSTORE_NAME_VALUE:
   1259     *ConfigResp = NULL;
   1260     FormsetStorage = GetFstStgFromBrsStg(Storage);
   1261     ASSERT (FormsetStorage != NULL);
   1262     NewStringCat (ConfigResp, FormsetStorage->ConfigHdr);
   1263 
   1264     Link = GetFirstNode (&Storage->NameValueListHead);
   1265     while (!IsNull (&Storage->NameValueListHead, Link)) {
   1266       Node = NAME_VALUE_NODE_FROM_LINK (Link);
   1267 
   1268       if (StrStr (ConfigRequest, Node->Name) != NULL) {
   1269         NewStringCat (ConfigResp, L"&");
   1270         NewStringCat (ConfigResp, Node->Name);
   1271         NewStringCat (ConfigResp, L"=");
   1272         if (GetEditBuf) {
   1273           NewStringCat (ConfigResp, Node->EditValue);
   1274         } else {
   1275           NewStringCat (ConfigResp, Node->Value);
   1276         }
   1277       }
   1278       Link = GetNextNode (&Storage->NameValueListHead, Link);
   1279     }
   1280     break;
   1281 
   1282   case EFI_HII_VARSTORE_EFI_VARIABLE:
   1283   default:
   1284     Status = EFI_INVALID_PARAMETER;
   1285     break;
   1286   }
   1287 
   1288   return Status;
   1289 }
   1290 
   1291 
   1292 /**
   1293   Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
   1294 
   1295   @param  Storage                The Storage to receive the settings.
   1296   @param  ConfigResp             The <ConfigResp> to be converted.
   1297 
   1298   @retval EFI_SUCCESS            Convert success.
   1299   @retval EFI_INVALID_PARAMETER  Incorrect storage type.
   1300 
   1301 **/
   1302 EFI_STATUS
   1303 ConfigRespToStorage (
   1304   IN BROWSER_STORAGE         *Storage,
   1305   IN CHAR16                  *ConfigResp
   1306   )
   1307 {
   1308   EFI_STATUS  Status;
   1309   EFI_STRING  Progress;
   1310   UINTN       BufferSize;
   1311   CHAR16      *StrPtr;
   1312   CHAR16      *Name;
   1313   CHAR16      *Value;
   1314 
   1315   Status = EFI_SUCCESS;
   1316 
   1317   switch (Storage->Type) {
   1318   case EFI_HII_VARSTORE_BUFFER:
   1319   case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
   1320     BufferSize = Storage->Size;
   1321     Status = mHiiConfigRouting->ConfigToBlock (
   1322                                   mHiiConfigRouting,
   1323                                   ConfigResp,
   1324                                   Storage->EditBuffer,
   1325                                   &BufferSize,
   1326                                   &Progress
   1327                                   );
   1328     break;
   1329 
   1330   case EFI_HII_VARSTORE_NAME_VALUE:
   1331     StrPtr = StrStr (ConfigResp, L"PATH");
   1332     if (StrPtr == NULL) {
   1333       break;
   1334     }
   1335     StrPtr = StrStr (ConfigResp, L"&");
   1336     while (StrPtr != NULL) {
   1337       //
   1338       // Skip '&'
   1339       //
   1340       StrPtr = StrPtr + 1;
   1341       Name = StrPtr;
   1342       StrPtr = StrStr (StrPtr, L"=");
   1343       if (StrPtr == NULL) {
   1344         break;
   1345       }
   1346       *StrPtr = 0;
   1347 
   1348       //
   1349       // Skip '='
   1350       //
   1351       StrPtr = StrPtr + 1;
   1352       Value = StrPtr;
   1353       StrPtr = StrStr (StrPtr, L"&");
   1354       if (StrPtr != NULL) {
   1355         *StrPtr = 0;
   1356       }
   1357       SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);
   1358     }
   1359     break;
   1360 
   1361   case EFI_HII_VARSTORE_EFI_VARIABLE:
   1362   default:
   1363     Status = EFI_INVALID_PARAMETER;
   1364     break;
   1365   }
   1366 
   1367   return Status;
   1368 }
   1369 
   1370 /**
   1371   Convert the buffer value to HiiValue.
   1372 
   1373   @param  Question               The question.
   1374   @param  Value                  Unicode buffer save the question value.
   1375 
   1376   @retval  Status whether convert the value success.
   1377 
   1378 **/
   1379 EFI_STATUS
   1380 BufferToValue (
   1381   IN OUT FORM_BROWSER_STATEMENT           *Question,
   1382   IN     CHAR16                           *Value
   1383   )
   1384 {
   1385   CHAR16                       *StringPtr;
   1386   BOOLEAN                      IsBufferStorage;
   1387   CHAR16                       *DstBuf;
   1388   CHAR16                       TempChar;
   1389   UINTN                        LengthStr;
   1390   UINT8                        *Dst;
   1391   CHAR16                       TemStr[5];
   1392   UINTN                        Index;
   1393   UINT8                        DigitUint8;
   1394   BOOLEAN                      IsString;
   1395   UINTN                        Length;
   1396   EFI_STATUS                   Status;
   1397 
   1398   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
   1399   if (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   1400       Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   1401     IsBufferStorage = TRUE;
   1402   } else {
   1403     IsBufferStorage = FALSE;
   1404   }
   1405 
   1406   //
   1407   // Question Value is provided by Buffer Storage or NameValue Storage
   1408   //
   1409   if (Question->BufferValue != NULL) {
   1410     //
   1411     // This Question is password or orderedlist
   1412     //
   1413     Dst = Question->BufferValue;
   1414   } else {
   1415     //
   1416     // Other type of Questions
   1417     //
   1418     Dst = (UINT8 *) &Question->HiiValue.Value;
   1419   }
   1420 
   1421   //
   1422   // Temp cut at the end of this section, end with '\0' or '&'.
   1423   //
   1424   StringPtr = Value;
   1425   while (*StringPtr != L'\0' && *StringPtr != L'&') {
   1426     StringPtr++;
   1427   }
   1428   TempChar = *StringPtr;
   1429   *StringPtr = L'\0';
   1430 
   1431   LengthStr = StrLen (Value);
   1432   Status    = EFI_SUCCESS;
   1433   if (!IsBufferStorage && IsString) {
   1434     //
   1435     // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
   1436     // Add string tail char L'\0' into Length
   1437     //
   1438     Length    = Question->StorageWidth + sizeof (CHAR16);
   1439     if (Length < ((LengthStr / 4 + 1) * 2)) {
   1440       Status = EFI_BUFFER_TOO_SMALL;
   1441     } else {
   1442       DstBuf = (CHAR16 *) Dst;
   1443       ZeroMem (TemStr, sizeof (TemStr));
   1444       for (Index = 0; Index < LengthStr; Index += 4) {
   1445         StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4);
   1446         DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
   1447       }
   1448       //
   1449       // Add tailing L'\0' character
   1450       //
   1451       DstBuf[Index/4] = L'\0';
   1452     }
   1453   } else {
   1454     if (Question->StorageWidth < ((LengthStr + 1) / 2)) {
   1455       Status = EFI_BUFFER_TOO_SMALL;
   1456     } else {
   1457       ZeroMem (TemStr, sizeof (TemStr));
   1458       for (Index = 0; Index < LengthStr; Index ++) {
   1459         TemStr[0] = Value[LengthStr - Index - 1];
   1460         DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
   1461         if ((Index & 1) == 0) {
   1462           Dst [Index/2] = DigitUint8;
   1463         } else {
   1464           Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
   1465         }
   1466       }
   1467     }
   1468   }
   1469 
   1470   *StringPtr = TempChar;
   1471 
   1472   return Status;
   1473 }
   1474 
   1475 /**
   1476   Get Question's current Value.
   1477 
   1478   @param  FormSet                FormSet data structure.
   1479   @param  Form                   Form data structure.
   1480   @param  Question               Question to be initialized.
   1481   @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.
   1482 
   1483   @retval EFI_SUCCESS            The function completed successfully.
   1484 
   1485 **/
   1486 EFI_STATUS
   1487 GetQuestionValue (
   1488   IN FORM_BROWSER_FORMSET             *FormSet,
   1489   IN FORM_BROWSER_FORM                *Form,
   1490   IN OUT FORM_BROWSER_STATEMENT       *Question,
   1491   IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom
   1492   )
   1493 {
   1494   EFI_STATUS          Status;
   1495   BOOLEAN             Enabled;
   1496   BOOLEAN             Pending;
   1497   UINT8               *Dst;
   1498   UINTN               StorageWidth;
   1499   EFI_TIME            EfiTime;
   1500   BROWSER_STORAGE     *Storage;
   1501   FORMSET_STORAGE     *FormsetStorage;
   1502   EFI_IFR_TYPE_VALUE  *QuestionValue;
   1503   CHAR16              *ConfigRequest;
   1504   CHAR16              *Progress;
   1505   CHAR16              *Result;
   1506   CHAR16              *Value;
   1507   UINTN               Length;
   1508   BOOLEAN             IsBufferStorage;
   1509   UINTN               MaxLen;
   1510 
   1511   Status = EFI_SUCCESS;
   1512   Value  = NULL;
   1513   Result = NULL;
   1514 
   1515   if (GetValueFrom >= GetSetValueWithMax) {
   1516     return EFI_INVALID_PARAMETER;
   1517   }
   1518 
   1519   //
   1520   // Question value is provided by an Expression, evaluate it
   1521   //
   1522   if (Question->ValueExpression != NULL) {
   1523     Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
   1524     if (!EFI_ERROR (Status)) {
   1525       if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
   1526         ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
   1527         if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
   1528           CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
   1529           Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
   1530         } else {
   1531           CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
   1532           Question->HiiValue.BufferLen = Question->StorageWidth;
   1533         }
   1534         FreePool (Question->ValueExpression->Result.Buffer);
   1535       }
   1536       Question->HiiValue.Type = Question->ValueExpression->Result.Type;
   1537       CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
   1538     }
   1539     return Status;
   1540   }
   1541 
   1542   //
   1543   // Get question value by read expression.
   1544   //
   1545   if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
   1546     Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
   1547     if (!EFI_ERROR (Status) &&
   1548       ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
   1549       //
   1550       // Only update question value to the valid result.
   1551       //
   1552       if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
   1553         ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
   1554         if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
   1555           CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
   1556           Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
   1557         } else {
   1558           CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
   1559           Question->HiiValue.BufferLen = Question->StorageWidth;
   1560         }
   1561         FreePool (Question->ReadExpression->Result.Buffer);
   1562       }
   1563       Question->HiiValue.Type = Question->ReadExpression->Result.Type;
   1564       CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
   1565       return EFI_SUCCESS;
   1566     }
   1567   }
   1568 
   1569   //
   1570   // Question value is provided by RTC
   1571   //
   1572   Storage = Question->Storage;
   1573   QuestionValue = &Question->HiiValue.Value;
   1574   if (Storage == NULL) {
   1575     //
   1576     // It's a Question without storage, or RTC date/time
   1577     //
   1578     if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
   1579       //
   1580       // Date and time define the same Flags bit
   1581       //
   1582       switch (Question->Flags & EFI_QF_DATE_STORAGE) {
   1583       case QF_DATE_STORAGE_TIME:
   1584         Status = gRT->GetTime (&EfiTime, NULL);
   1585         break;
   1586 
   1587       case QF_DATE_STORAGE_WAKEUP:
   1588         Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
   1589         break;
   1590 
   1591       case QF_DATE_STORAGE_NORMAL:
   1592       default:
   1593         //
   1594         // For date/time without storage
   1595         //
   1596         return EFI_SUCCESS;
   1597       }
   1598 
   1599       if (EFI_ERROR (Status)) {
   1600         if (Question->Operand == EFI_IFR_DATE_OP){
   1601           QuestionValue->date.Year  = 0xff;
   1602           QuestionValue->date.Month = 0xff;
   1603           QuestionValue->date.Day   = 0xff;
   1604         } else {
   1605           QuestionValue->time.Hour   = 0xff;
   1606           QuestionValue->time.Minute = 0xff;
   1607           QuestionValue->time.Second = 0xff;
   1608         }
   1609         return EFI_SUCCESS;
   1610       }
   1611 
   1612       if (Question->Operand == EFI_IFR_DATE_OP) {
   1613         QuestionValue->date.Year  = EfiTime.Year;
   1614         QuestionValue->date.Month = EfiTime.Month;
   1615         QuestionValue->date.Day   = EfiTime.Day;
   1616       } else {
   1617         QuestionValue->time.Hour   = EfiTime.Hour;
   1618         QuestionValue->time.Minute = EfiTime.Minute;
   1619         QuestionValue->time.Second = EfiTime.Second;
   1620       }
   1621     }
   1622 
   1623     return EFI_SUCCESS;
   1624   }
   1625 
   1626   //
   1627   // Question value is provided by EFI variable
   1628   //
   1629   StorageWidth = Question->StorageWidth;
   1630   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   1631     if (Question->BufferValue != NULL) {
   1632       Dst = Question->BufferValue;
   1633     } else {
   1634       Dst = (UINT8 *) QuestionValue;
   1635     }
   1636 
   1637     Status = gRT->GetVariable (
   1638                      Question->VariableName,
   1639                      &Storage->Guid,
   1640                      NULL,
   1641                      &StorageWidth,
   1642                      Dst
   1643                      );
   1644     //
   1645     // Always return success, even this EFI variable doesn't exist
   1646     //
   1647     return EFI_SUCCESS;
   1648   }
   1649 
   1650   //
   1651   // Question Value is provided by Buffer Storage or NameValue Storage
   1652   //
   1653   if (Question->BufferValue != NULL) {
   1654     //
   1655     // This Question is password or orderedlist
   1656     //
   1657     Dst = Question->BufferValue;
   1658   } else {
   1659     //
   1660     // Other type of Questions
   1661     //
   1662     Dst = (UINT8 *) &Question->HiiValue.Value;
   1663   }
   1664 
   1665   if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   1666       Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   1667     IsBufferStorage = TRUE;
   1668   } else {
   1669     IsBufferStorage = FALSE;
   1670   }
   1671   if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
   1672     if (IsBufferStorage) {
   1673       if (GetValueFrom == GetSetValueWithEditBuffer) {
   1674         //
   1675         // Copy from storage Edit buffer
   1676         //
   1677         CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
   1678       } else {
   1679         //
   1680         // Copy from storage Edit buffer
   1681         //
   1682         CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
   1683       }
   1684     } else {
   1685       Value = NULL;
   1686       Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
   1687       if (EFI_ERROR (Status)) {
   1688         return Status;
   1689       }
   1690 
   1691       ASSERT (Value != NULL);
   1692       Status = BufferToValue (Question, Value);
   1693       FreePool (Value);
   1694     }
   1695   } else {
   1696     FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
   1697     ASSERT (FormsetStorage != NULL);
   1698     //
   1699     // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
   1700     //                   <ConfigHdr> + "&" + <VariableName>
   1701     //
   1702     if (IsBufferStorage) {
   1703       Length = StrLen (FormsetStorage->ConfigHdr);
   1704       Length += StrLen (Question->BlockName);
   1705     } else {
   1706       Length = StrLen (FormsetStorage->ConfigHdr);
   1707       Length += StrLen (Question->VariableName) + 1;
   1708     }
   1709     // Allocate buffer include '\0'
   1710     MaxLen = Length + 1;
   1711     ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1712     ASSERT (ConfigRequest != NULL);
   1713 
   1714     StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr);
   1715     if (IsBufferStorage) {
   1716       StrCatS (ConfigRequest, MaxLen, Question->BlockName);
   1717     } else {
   1718       StrCatS (ConfigRequest, MaxLen, L"&");
   1719       StrCatS (ConfigRequest, MaxLen, Question->VariableName);
   1720     }
   1721 
   1722     //
   1723     // Request current settings from Configuration Driver
   1724     //
   1725     Status = mHiiConfigRouting->ExtractConfig (
   1726                                       mHiiConfigRouting,
   1727                                       ConfigRequest,
   1728                                       &Progress,
   1729                                       &Result
   1730                                       );
   1731     FreePool (ConfigRequest);
   1732     if (EFI_ERROR (Status)) {
   1733       return Status;
   1734     }
   1735 
   1736     //
   1737     // Skip <ConfigRequest>
   1738     //
   1739     if (IsBufferStorage) {
   1740       Value = StrStr (Result, L"&VALUE");
   1741       if (Value == NULL) {
   1742         FreePool (Result);
   1743         return EFI_NOT_FOUND;
   1744       }
   1745       //
   1746       // Skip "&VALUE"
   1747       //
   1748       Value = Value + 6;
   1749     } else {
   1750       Value = Result + Length;
   1751     }
   1752     if (*Value != '=') {
   1753       FreePool (Result);
   1754       return EFI_NOT_FOUND;
   1755     }
   1756     //
   1757     // Skip '=', point to value
   1758     //
   1759     Value = Value + 1;
   1760 
   1761     Status = BufferToValue (Question, Value);
   1762     if (EFI_ERROR (Status)) {
   1763       FreePool (Result);
   1764       return Status;
   1765     }
   1766 
   1767     //
   1768     // Synchronize Edit Buffer
   1769     //
   1770     if (IsBufferStorage) {
   1771       CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
   1772     } else {
   1773       SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
   1774     }
   1775 
   1776     if (Result != NULL) {
   1777       FreePool (Result);
   1778     }
   1779   }
   1780 
   1781   return Status;
   1782 }
   1783 
   1784 
   1785 /**
   1786   Save Question Value to edit copy(cached) or Storage(uncached).
   1787 
   1788   @param  FormSet                FormSet data structure.
   1789   @param  Form                   Form data structure.
   1790   @param  Question               Pointer to the Question.
   1791   @param  SetValueTo             Update the question value to editbuffer , buffer or hii driver.
   1792 
   1793   @retval EFI_SUCCESS            The function completed successfully.
   1794 
   1795 **/
   1796 EFI_STATUS
   1797 SetQuestionValue (
   1798   IN FORM_BROWSER_FORMSET             *FormSet,
   1799   IN FORM_BROWSER_FORM                *Form,
   1800   IN OUT FORM_BROWSER_STATEMENT       *Question,
   1801   IN GET_SET_QUESTION_VALUE_WITH      SetValueTo
   1802   )
   1803 {
   1804   EFI_STATUS          Status;
   1805   BOOLEAN             Enabled;
   1806   BOOLEAN             Pending;
   1807   UINT8               *Src;
   1808   EFI_TIME            EfiTime;
   1809   UINTN               BufferLen;
   1810   UINTN               StorageWidth;
   1811   BROWSER_STORAGE     *Storage;
   1812   FORMSET_STORAGE     *FormsetStorage;
   1813   EFI_IFR_TYPE_VALUE  *QuestionValue;
   1814   CHAR16              *ConfigResp;
   1815   CHAR16              *Progress;
   1816   CHAR16              *Value;
   1817   UINTN               Length;
   1818   BOOLEAN             IsBufferStorage;
   1819   BOOLEAN             IsString;
   1820   UINT8               *TemBuffer;
   1821   CHAR16              *TemName;
   1822   CHAR16              *TemString;
   1823   UINTN               Index;
   1824   NAME_VALUE_NODE     *Node;
   1825   UINTN               MaxLen;
   1826 
   1827   Status = EFI_SUCCESS;
   1828   Node   = NULL;
   1829 
   1830   if (SetValueTo >= GetSetValueWithMax) {
   1831     return EFI_INVALID_PARAMETER;
   1832   }
   1833 
   1834   //
   1835   // If Question value is provided by an Expression, then it is read only
   1836   //
   1837   if (Question->ValueExpression != NULL) {
   1838     return Status;
   1839   }
   1840 
   1841   //
   1842   // Before set question value, evaluate its write expression.
   1843   //
   1844   if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
   1845     Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
   1846     if (EFI_ERROR (Status)) {
   1847       return Status;
   1848     }
   1849   }
   1850 
   1851   //
   1852   // Question value is provided by RTC
   1853   //
   1854   Storage = Question->Storage;
   1855   QuestionValue = &Question->HiiValue.Value;
   1856   if (Storage == NULL) {
   1857     //
   1858     // It's a Question without storage, or RTC date/time
   1859     //
   1860     if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
   1861       //
   1862       // Date and time define the same Flags bit
   1863       //
   1864       switch (Question->Flags & EFI_QF_DATE_STORAGE) {
   1865       case QF_DATE_STORAGE_TIME:
   1866         Status = gRT->GetTime (&EfiTime, NULL);
   1867         break;
   1868 
   1869       case QF_DATE_STORAGE_WAKEUP:
   1870         Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
   1871         break;
   1872 
   1873       case QF_DATE_STORAGE_NORMAL:
   1874       default:
   1875         //
   1876         // For date/time without storage
   1877         //
   1878         return EFI_SUCCESS;
   1879       }
   1880 
   1881       if (EFI_ERROR (Status)) {
   1882         return Status;
   1883       }
   1884 
   1885       if (Question->Operand == EFI_IFR_DATE_OP) {
   1886         EfiTime.Year  = QuestionValue->date.Year;
   1887         EfiTime.Month = QuestionValue->date.Month;
   1888         EfiTime.Day   = QuestionValue->date.Day;
   1889       } else {
   1890         EfiTime.Hour   = QuestionValue->time.Hour;
   1891         EfiTime.Minute = QuestionValue->time.Minute;
   1892         EfiTime.Second = QuestionValue->time.Second;
   1893       }
   1894 
   1895       if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
   1896         Status = gRT->SetTime (&EfiTime);
   1897       } else {
   1898         Status = gRT->SetWakeupTime (TRUE, &EfiTime);
   1899       }
   1900     }
   1901 
   1902     return Status;
   1903   }
   1904 
   1905   //
   1906   // Question value is provided by EFI variable
   1907   //
   1908   StorageWidth = Question->StorageWidth;
   1909   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   1910     if (Question->BufferValue != NULL) {
   1911       Src = Question->BufferValue;
   1912     } else {
   1913       Src = (UINT8 *) QuestionValue;
   1914     }
   1915 
   1916     Status = gRT->SetVariable (
   1917                      Question->VariableName,
   1918                      &Storage->Guid,
   1919                      Storage->Attributes,
   1920                      StorageWidth,
   1921                      Src
   1922                      );
   1923     return Status;
   1924   }
   1925 
   1926   //
   1927   // Question Value is provided by Buffer Storage or NameValue Storage
   1928   //
   1929   if (Question->BufferValue != NULL) {
   1930     Src = Question->BufferValue;
   1931   } else {
   1932     Src = (UINT8 *) &Question->HiiValue.Value;
   1933   }
   1934 
   1935   if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   1936       Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   1937     IsBufferStorage = TRUE;
   1938   } else {
   1939     IsBufferStorage = FALSE;
   1940   }
   1941   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
   1942 
   1943   if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
   1944     if (IsBufferStorage) {
   1945       if (SetValueTo == GetSetValueWithEditBuffer) {
   1946         //
   1947         // Copy to storage edit buffer
   1948         //
   1949         CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
   1950       } else if (SetValueTo == GetSetValueWithBuffer) {
   1951         //
   1952         // Copy to storage edit buffer
   1953         //
   1954         CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
   1955       }
   1956     } else {
   1957       if (IsString) {
   1958         //
   1959         // Allocate enough string buffer.
   1960         //
   1961         Value = NULL;
   1962         BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
   1963         Value = AllocateZeroPool (BufferLen);
   1964         ASSERT (Value != NULL);
   1965         //
   1966         // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
   1967         //
   1968         TemName = (CHAR16 *) Src;
   1969         TemString = Value;
   1970         for (; *TemName != L'\0'; TemName++) {
   1971           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
   1972         }
   1973       } else {
   1974         BufferLen = StorageWidth * 2 + 1;
   1975         Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
   1976         ASSERT (Value != NULL);
   1977         //
   1978         // Convert Buffer to Hex String
   1979         //
   1980         TemBuffer = Src + StorageWidth - 1;
   1981         TemString = Value;
   1982         for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
   1983           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
   1984         }
   1985       }
   1986 
   1987       Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
   1988       FreePool (Value);
   1989       if (EFI_ERROR (Status)) {
   1990         return Status;
   1991       }
   1992     }
   1993   } else if (SetValueTo == GetSetValueWithHiiDriver) {
   1994     //
   1995     // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
   1996     //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
   1997     //
   1998     if (IsBufferStorage) {
   1999       Length = StrLen (Question->BlockName) + 7;
   2000     } else {
   2001       Length = StrLen (Question->VariableName) + 2;
   2002     }
   2003     if (!IsBufferStorage && IsString) {
   2004       Length += (StrLen ((CHAR16 *) Src) * 4);
   2005     } else {
   2006       Length += (StorageWidth * 2);
   2007     }
   2008     FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
   2009     ASSERT (FormsetStorage != NULL);
   2010     MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1;
   2011     ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   2012     ASSERT (ConfigResp != NULL);
   2013 
   2014     StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr);
   2015     if (IsBufferStorage) {
   2016       StrCatS (ConfigResp, MaxLen, Question->BlockName);
   2017       StrCatS (ConfigResp, MaxLen, L"&VALUE=");
   2018     } else {
   2019       StrCatS (ConfigResp, MaxLen, L"&");
   2020       StrCatS (ConfigResp, MaxLen, Question->VariableName);
   2021       StrCatS (ConfigResp, MaxLen, L"=");
   2022     }
   2023 
   2024     Value = ConfigResp + StrLen (ConfigResp);
   2025 
   2026     if (!IsBufferStorage && IsString) {
   2027       //
   2028       // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
   2029       //
   2030       TemName = (CHAR16 *) Src;
   2031       TemString = Value;
   2032       for (; *TemName != L'\0'; TemName++) {
   2033         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
   2034       }
   2035     } else {
   2036       //
   2037       // Convert Buffer to Hex String
   2038       //
   2039       TemBuffer = Src + StorageWidth - 1;
   2040       TemString = Value;
   2041       for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
   2042         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
   2043       }
   2044     }
   2045 
   2046     //
   2047     // Convert to lower char.
   2048     //
   2049     for (TemString = Value; *Value != L'\0'; Value++) {
   2050       if (*Value >= L'A' && *Value <= L'Z') {
   2051         *Value = (CHAR16) (*Value - L'A' + L'a');
   2052       }
   2053     }
   2054 
   2055     //
   2056     // Submit Question Value to Configuration Driver
   2057     //
   2058     Status = mHiiConfigRouting->RouteConfig (
   2059                                       mHiiConfigRouting,
   2060                                       ConfigResp,
   2061                                       &Progress
   2062                                       );
   2063     if (EFI_ERROR (Status)) {
   2064       FreePool (ConfigResp);
   2065       return Status;
   2066     }
   2067     FreePool (ConfigResp);
   2068 
   2069     //
   2070     // Sync storage, from editbuffer to buffer.
   2071     //
   2072     CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
   2073   }
   2074 
   2075   return Status;
   2076 }
   2077 
   2078 
   2079 /**
   2080   Perform nosubmitif check for a Form.
   2081 
   2082   @param  FormSet                FormSet data structure.
   2083   @param  Form                   Form data structure.
   2084   @param  Question               The Question to be validated.
   2085   @param  Type                   Validation type: NoSubmit
   2086 
   2087   @retval EFI_SUCCESS            Form validation pass.
   2088   @retval other                  Form validation failed.
   2089 
   2090 **/
   2091 EFI_STATUS
   2092 ValidateQuestion (
   2093   IN  FORM_BROWSER_FORMSET            *FormSet,
   2094   IN  FORM_BROWSER_FORM               *Form,
   2095   IN  FORM_BROWSER_STATEMENT          *Question,
   2096   IN  UINTN                           Type
   2097   )
   2098 {
   2099   EFI_STATUS              Status;
   2100   LIST_ENTRY              *Link;
   2101   LIST_ENTRY              *ListHead;
   2102   FORM_EXPRESSION         *Expression;
   2103   UINT32                  BrowserStatus;
   2104   CHAR16                  *ErrorStr;
   2105 
   2106   BrowserStatus = BROWSER_SUCCESS;
   2107   ErrorStr      = NULL;
   2108 
   2109   switch (Type) {
   2110   case EFI_HII_EXPRESSION_INCONSISTENT_IF:
   2111     ListHead = &Question->InconsistentListHead;
   2112     break;
   2113 
   2114   case EFI_HII_EXPRESSION_WARNING_IF:
   2115     ListHead = &Question->WarningListHead;
   2116     break;
   2117 
   2118   case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
   2119     ListHead = &Question->NoSubmitListHead;
   2120     break;
   2121 
   2122   default:
   2123     ASSERT (FALSE);
   2124     return EFI_UNSUPPORTED;
   2125   }
   2126 
   2127   Link = GetFirstNode (ListHead);
   2128   while (!IsNull (ListHead, Link)) {
   2129     Expression = FORM_EXPRESSION_FROM_LINK (Link);
   2130 
   2131     //
   2132     // Evaluate the expression
   2133     //
   2134     Status = EvaluateExpression (FormSet, Form, Expression);
   2135     if (EFI_ERROR (Status)) {
   2136       return Status;
   2137     }
   2138 
   2139     if (IsTrue (&Expression->Result)) {
   2140       switch (Type) {
   2141       case EFI_HII_EXPRESSION_INCONSISTENT_IF:
   2142         BrowserStatus = BROWSER_INCONSISTENT_IF;
   2143         break;
   2144 
   2145       case EFI_HII_EXPRESSION_WARNING_IF:
   2146         BrowserStatus = BROWSER_WARNING_IF;
   2147         break;
   2148 
   2149       case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
   2150         BrowserStatus = BROWSER_NO_SUBMIT_IF;
   2151         //
   2152         // This code only used to compatible with old display engine,
   2153         // New display engine will not use this field.
   2154         //
   2155         if (Expression->Error != 0) {
   2156           ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);
   2157         }
   2158         break;
   2159 
   2160       default:
   2161         ASSERT (FALSE);
   2162         break;
   2163       }
   2164 
   2165       if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {
   2166         //
   2167         // If in system submit process and for no_submit_if check, not popup this error message.
   2168         // Will process this fail again later in not system submit process.
   2169         //
   2170         PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);
   2171       }
   2172 
   2173       if (ErrorStr != NULL) {
   2174         FreePool (ErrorStr);
   2175       }
   2176 
   2177       if (Type == EFI_HII_EXPRESSION_WARNING_IF) {
   2178         return EFI_SUCCESS;
   2179       } else {
   2180         return EFI_NOT_READY;
   2181       }
   2182     }
   2183 
   2184     Link = GetNextNode (ListHead, Link);
   2185   }
   2186 
   2187   return EFI_SUCCESS;
   2188 }
   2189 
   2190 /**
   2191   Perform question check.
   2192 
   2193   If one question has more than one check, process form high priority to low.
   2194   Only one error info will be popup.
   2195 
   2196   @param  FormSet                FormSet data structure.
   2197   @param  Form                   Form data structure.
   2198   @param  Question               The Question to be validated.
   2199 
   2200   @retval EFI_SUCCESS            Form validation pass.
   2201   @retval other                  Form validation failed.
   2202 
   2203 **/
   2204 EFI_STATUS
   2205 ValueChangedValidation (
   2206   IN  FORM_BROWSER_FORMSET            *FormSet,
   2207   IN  FORM_BROWSER_FORM               *Form,
   2208   IN  FORM_BROWSER_STATEMENT          *Question
   2209   )
   2210 {
   2211   EFI_STATUS   Status;
   2212 
   2213   Status = EFI_SUCCESS;
   2214 
   2215   //
   2216   // Do the inconsistentif check.
   2217   //
   2218   if (!IsListEmpty (&Question->InconsistentListHead)) {
   2219     Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
   2220     if (EFI_ERROR (Status)) {
   2221       return Status;
   2222     }
   2223   }
   2224 
   2225   //
   2226   // Do the warningif check.
   2227   //
   2228   if (!IsListEmpty (&Question->WarningListHead)) {
   2229     Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);
   2230   }
   2231 
   2232   return Status;
   2233 }
   2234 
   2235 /**
   2236   Perform NoSubmit check for each Form in FormSet.
   2237 
   2238   @param  FormSet                FormSet data structure.
   2239   @param  CurrentForm            Current input form data structure.
   2240   @param  Statement              The statement for this check.
   2241 
   2242   @retval EFI_SUCCESS            Form validation pass.
   2243   @retval other                  Form validation failed.
   2244 
   2245 **/
   2246 EFI_STATUS
   2247 NoSubmitCheck (
   2248   IN      FORM_BROWSER_FORMSET            *FormSet,
   2249   IN OUT  FORM_BROWSER_FORM               **CurrentForm,
   2250   OUT     FORM_BROWSER_STATEMENT          **Statement
   2251   )
   2252 {
   2253   EFI_STATUS              Status;
   2254   LIST_ENTRY              *Link;
   2255   FORM_BROWSER_STATEMENT  *Question;
   2256   FORM_BROWSER_FORM       *Form;
   2257   LIST_ENTRY              *LinkForm;
   2258 
   2259   LinkForm = GetFirstNode (&FormSet->FormListHead);
   2260   while (!IsNull (&FormSet->FormListHead, LinkForm)) {
   2261     Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
   2262     LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
   2263 
   2264     if (*CurrentForm != NULL && *CurrentForm != Form) {
   2265       continue;
   2266     }
   2267 
   2268     Link = GetFirstNode (&Form->StatementListHead);
   2269     while (!IsNull (&Form->StatementListHead, Link)) {
   2270       Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2271       Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
   2272       if (EFI_ERROR (Status)) {
   2273         if (*CurrentForm == NULL) {
   2274           *CurrentForm = Form;
   2275         }
   2276         if (Statement != NULL) {
   2277           *Statement = Question;
   2278         }
   2279         return Status;
   2280       }
   2281 
   2282       Link = GetNextNode (&Form->StatementListHead, Link);
   2283     }
   2284   }
   2285 
   2286   return EFI_SUCCESS;
   2287 }
   2288 
   2289 /**
   2290   Fill storage's edit copy with settings requested from Configuration Driver.
   2291 
   2292   @param  Storage                The storage which need to sync.
   2293   @param  ConfigRequest          The config request string which used to sync storage.
   2294   @param  SyncOrRestore          Sync the buffer to editbuffer or Restore  the
   2295                                  editbuffer to buffer
   2296                                  if TRUE, copy the editbuffer to the buffer.
   2297                                  if FALSE, copy the buffer to the editbuffer.
   2298 
   2299   @retval EFI_SUCCESS            The function completed successfully.
   2300 
   2301 **/
   2302 EFI_STATUS
   2303 SynchronizeStorage (
   2304   OUT BROWSER_STORAGE             *Storage,
   2305   IN  CHAR16                      *ConfigRequest,
   2306   IN  BOOLEAN                     SyncOrRestore
   2307   )
   2308 {
   2309   EFI_STATUS              Status;
   2310   EFI_STRING              Progress;
   2311   EFI_STRING              Result;
   2312   UINTN                   BufferSize;
   2313   LIST_ENTRY              *Link;
   2314   NAME_VALUE_NODE         *Node;
   2315   UINT8                   *Src;
   2316   UINT8                   *Dst;
   2317 
   2318   Status = EFI_SUCCESS;
   2319   Result = NULL;
   2320 
   2321   if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   2322       (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   2323     BufferSize = Storage->Size;
   2324 
   2325     if (SyncOrRestore) {
   2326       Src = Storage->EditBuffer;
   2327       Dst = Storage->Buffer;
   2328     } else {
   2329       Src = Storage->Buffer;
   2330       Dst = Storage->EditBuffer;
   2331     }
   2332 
   2333     if (ConfigRequest != NULL) {
   2334       Status = mHiiConfigRouting->BlockToConfig(
   2335                                     mHiiConfigRouting,
   2336                                     ConfigRequest,
   2337                                     Src,
   2338                                     BufferSize,
   2339                                     &Result,
   2340                                     &Progress
   2341                                     );
   2342       if (EFI_ERROR (Status)) {
   2343         return Status;
   2344       }
   2345 
   2346       Status = mHiiConfigRouting->ConfigToBlock (
   2347                                     mHiiConfigRouting,
   2348                                     Result,
   2349                                     Dst,
   2350                                     &BufferSize,
   2351                                     &Progress
   2352                                     );
   2353       if (Result != NULL) {
   2354         FreePool (Result);
   2355       }
   2356     } else {
   2357       CopyMem (Dst, Src, BufferSize);
   2358     }
   2359   } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2360     Link = GetFirstNode (&Storage->NameValueListHead);
   2361     while (!IsNull (&Storage->NameValueListHead, Link)) {
   2362       Node = NAME_VALUE_NODE_FROM_LINK (Link);
   2363 
   2364       if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
   2365           (ConfigRequest == NULL)) {
   2366         if (SyncOrRestore) {
   2367           NewStringCpy (&Node->Value, Node->EditValue);
   2368         } else {
   2369           NewStringCpy (&Node->EditValue, Node->Value);
   2370         }
   2371       }
   2372 
   2373       Link = GetNextNode (&Storage->NameValueListHead, Link);
   2374     }
   2375   }
   2376 
   2377   return Status;
   2378 }
   2379 
   2380 /**
   2381   When discard the question value, call the callback function with Changed type
   2382   to inform the hii driver.
   2383 
   2384   @param  FormSet                FormSet data structure.
   2385   @param  Form                   Form data structure.
   2386 
   2387 **/
   2388 VOID
   2389 SendDiscardInfoToDriver (
   2390   IN FORM_BROWSER_FORMSET             *FormSet,
   2391   IN FORM_BROWSER_FORM                *Form
   2392   )
   2393 {
   2394   LIST_ENTRY                  *Link;
   2395   FORM_BROWSER_STATEMENT      *Question;
   2396   EFI_IFR_TYPE_VALUE          *TypeValue;
   2397   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
   2398 
   2399   if (FormSet->ConfigAccess == NULL) {
   2400     return;
   2401   }
   2402 
   2403   Link = GetFirstNode (&Form->StatementListHead);
   2404   while (!IsNull (&Form->StatementListHead, Link)) {
   2405     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2406     Link = GetNextNode (&Form->StatementListHead, Link);
   2407 
   2408     if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   2409       continue;
   2410     }
   2411 
   2412     if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
   2413       continue;
   2414     }
   2415 
   2416     if (Question->Operand == EFI_IFR_PASSWORD_OP) {
   2417       continue;
   2418     }
   2419 
   2420     if (!Question->ValueChanged) {
   2421       continue;
   2422     }
   2423 
   2424     //
   2425     // Restore the question value before call the CHANGED callback type.
   2426     //
   2427     GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   2428 
   2429     if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
   2430       TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
   2431     } else {
   2432       TypeValue = &Question->HiiValue.Value;
   2433     }
   2434 
   2435     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2436     FormSet->ConfigAccess->Callback (
   2437                              FormSet->ConfigAccess,
   2438                              EFI_BROWSER_ACTION_CHANGED,
   2439                              Question->QuestionId,
   2440                              Question->HiiValue.Type,
   2441                              TypeValue,
   2442                              &ActionRequest
   2443                              );
   2444   }
   2445 }
   2446 
   2447 /**
   2448   Validate the HiiHandle.
   2449 
   2450   @param  HiiHandle              The input HiiHandle which need to validate.
   2451 
   2452   @retval TRUE                   The handle is validate.
   2453   @retval FALSE                  The handle is invalidate.
   2454 
   2455 **/
   2456 BOOLEAN
   2457 ValidateHiiHandle (
   2458   EFI_HII_HANDLE          HiiHandle
   2459   )
   2460 {
   2461   EFI_HII_HANDLE          *HiiHandles;
   2462   UINTN                   Index;
   2463   BOOLEAN                 Find;
   2464 
   2465   if (HiiHandle == NULL) {
   2466     return FALSE;
   2467   }
   2468 
   2469   Find = FALSE;
   2470 
   2471   HiiHandles = HiiGetHiiHandles (NULL);
   2472   ASSERT (HiiHandles != NULL);
   2473 
   2474   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
   2475     if (HiiHandles[Index] == HiiHandle) {
   2476       Find = TRUE;
   2477       break;
   2478     }
   2479   }
   2480 
   2481   FreePool (HiiHandles);
   2482 
   2483   return Find;
   2484 }
   2485 
   2486 /**
   2487   Validate the FormSet. If the formset is not validate, remove it from the list.
   2488 
   2489   @param  FormSet                The input FormSet which need to validate.
   2490 
   2491   @retval TRUE                   The handle is validate.
   2492   @retval FALSE                  The handle is invalidate.
   2493 
   2494 **/
   2495 BOOLEAN
   2496 ValidateFormSet (
   2497   FORM_BROWSER_FORMSET    *FormSet
   2498   )
   2499 {
   2500   BOOLEAN  Find;
   2501 
   2502   ASSERT (FormSet != NULL);
   2503 
   2504   Find = ValidateHiiHandle(FormSet->HiiHandle);
   2505   //
   2506   // Should not remove the formset which is being used.
   2507   //
   2508   if (!Find && (FormSet != gCurrentSelection->FormSet)) {
   2509     CleanBrowserStorage(FormSet);
   2510     RemoveEntryList (&FormSet->Link);
   2511     DestroyFormSet (FormSet);
   2512   }
   2513 
   2514   return Find;
   2515 }
   2516 /**
   2517   Check whether need to enable the reset flag in form level.
   2518   Also clean all ValueChanged flag in question.
   2519 
   2520   @param  SetFlag                Whether need to set the Reset Flag.
   2521   @param  FormSet                FormSet data structure.
   2522   @param  Form                   Form data structure.
   2523 
   2524 **/
   2525 VOID
   2526 UpdateFlagForForm (
   2527   IN BOOLEAN                          SetFlag,
   2528   IN FORM_BROWSER_FORMSET             *FormSet,
   2529   IN FORM_BROWSER_FORM                *Form
   2530   )
   2531 {
   2532   LIST_ENTRY              *Link;
   2533   FORM_BROWSER_STATEMENT  *Question;
   2534   BOOLEAN                 OldValue;
   2535 
   2536   Link = GetFirstNode (&Form->StatementListHead);
   2537   while (!IsNull (&Form->StatementListHead, Link)) {
   2538     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2539     Link = GetNextNode (&Form->StatementListHead, Link);
   2540 
   2541     if (!Question->ValueChanged) {
   2542       continue;
   2543     }
   2544 
   2545     OldValue = Question->ValueChanged;
   2546 
   2547     //
   2548     // Compare the buffer and editbuffer data to see whether the data has been saved.
   2549     //
   2550     Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);
   2551 
   2552     //
   2553     // Only the changed data has been saved, then need to set the reset flag.
   2554     //
   2555     if (SetFlag && OldValue && !Question->ValueChanged) {
   2556       if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
   2557         gResetRequired = TRUE;
   2558       }
   2559 
   2560       if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
   2561         gFlagReconnect = TRUE;
   2562       }
   2563     }
   2564   }
   2565 }
   2566 
   2567 /**
   2568   Check whether need to enable the reset flag.
   2569   Also clean ValueChanged flag for all statements.
   2570 
   2571   Form level or formset level, only one.
   2572 
   2573   @param  SetFlag                Whether need to set the Reset Flag.
   2574   @param  FormSet                FormSet data structure.
   2575   @param  Form                   Form data structure.
   2576 
   2577 **/
   2578 VOID
   2579 ValueChangeResetFlagUpdate (
   2580   IN BOOLEAN                          SetFlag,
   2581   IN FORM_BROWSER_FORMSET             *FormSet,
   2582   IN FORM_BROWSER_FORM                *Form
   2583   )
   2584 {
   2585   FORM_BROWSER_FORM       *CurrentForm;
   2586   LIST_ENTRY              *Link;
   2587 
   2588   if (Form != NULL) {
   2589     UpdateFlagForForm(SetFlag, FormSet, Form);
   2590     return;
   2591   }
   2592 
   2593   Link = GetFirstNode (&FormSet->FormListHead);
   2594   while (!IsNull (&FormSet->FormListHead, Link)) {
   2595     CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
   2596     Link = GetNextNode (&FormSet->FormListHead, Link);
   2597 
   2598     UpdateFlagForForm(SetFlag, FormSet, CurrentForm);
   2599   }
   2600 }
   2601 
   2602 /**
   2603   Base on the return Progress string to find the form.
   2604 
   2605   Base on the first return Offset/Width (Name) string to find the form
   2606   which keep this string.
   2607 
   2608   @param  FormSet                FormSet data structure.
   2609   @param  Storage                Storage which has this Progress string.
   2610   @param  Progress               The Progress string which has the first fail string.
   2611   @param  RetForm                The return form for this progress string.
   2612   @param  RetQuestion            The return question for the error progress string.
   2613 
   2614   @retval TRUE                   Find the error form and statement for this error progress string.
   2615   @retval FALSE                  Not find the error form.
   2616 
   2617 **/
   2618 BOOLEAN
   2619 FindQuestionFromProgress (
   2620   IN FORM_BROWSER_FORMSET             *FormSet,
   2621   IN BROWSER_STORAGE                  *Storage,
   2622   IN EFI_STRING                       Progress,
   2623   OUT FORM_BROWSER_FORM               **RetForm,
   2624   OUT FORM_BROWSER_STATEMENT          **RetQuestion
   2625   )
   2626 {
   2627   LIST_ENTRY                   *Link;
   2628   LIST_ENTRY                   *LinkStorage;
   2629   LIST_ENTRY                   *LinkStatement;
   2630   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   2631   FORM_BROWSER_FORM            *Form;
   2632   EFI_STRING                   EndStr;
   2633   FORM_BROWSER_STATEMENT       *Statement;
   2634 
   2635   ASSERT ((*Progress == '&') || (*Progress == 'G'));
   2636 
   2637   ConfigInfo   = NULL;
   2638   *RetForm     = NULL;
   2639   *RetQuestion = NULL;
   2640 
   2641   //
   2642   // Skip the first "&" or the ConfigHdr part.
   2643   //
   2644   if (*Progress == '&') {
   2645     Progress++;
   2646   } else {
   2647     //
   2648     // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
   2649     //
   2650     if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2651       //
   2652       // For Name/Value type, Skip the ConfigHdr part.
   2653       //
   2654       EndStr = StrStr (Progress, L"PATH=");
   2655       ASSERT (EndStr != NULL);
   2656       while (*EndStr != '&') {
   2657         EndStr++;
   2658       }
   2659 
   2660       *EndStr = '\0';
   2661     } else {
   2662       //
   2663       // For Buffer type, Skip the ConfigHdr part.
   2664       //
   2665       EndStr = StrStr (Progress, L"&OFFSET=");
   2666       ASSERT (EndStr != NULL);
   2667       *EndStr = '\0';
   2668     }
   2669 
   2670     Progress = EndStr + 1;
   2671   }
   2672 
   2673   //
   2674   // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
   2675   //
   2676   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2677     //
   2678     // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
   2679     // here, just keep the "Fred" string.
   2680     //
   2681     EndStr = StrStr (Progress, L"=");
   2682     ASSERT (EndStr != NULL);
   2683     *EndStr = '\0';
   2684   } else {
   2685     //
   2686     // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
   2687     // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
   2688     //
   2689     EndStr = StrStr (Progress, L"&VALUE=");
   2690     ASSERT (EndStr != NULL);
   2691     *EndStr = '\0';
   2692   }
   2693 
   2694   //
   2695   // Search in the form list.
   2696   //
   2697   Link = GetFirstNode (&FormSet->FormListHead);
   2698   while (!IsNull (&FormSet->FormListHead, Link)) {
   2699     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   2700     Link = GetNextNode (&FormSet->FormListHead, Link);
   2701 
   2702     //
   2703     // Search in the ConfigReqeust list in this form.
   2704     //
   2705     LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
   2706     while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
   2707       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
   2708       LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
   2709 
   2710       if (Storage != ConfigInfo->Storage) {
   2711         continue;
   2712       }
   2713 
   2714       if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
   2715         //
   2716         // Find the OffsetWidth string in this form.
   2717         //
   2718         *RetForm = Form;
   2719         break;
   2720       }
   2721     }
   2722 
   2723     if (*RetForm != NULL) {
   2724       LinkStatement = GetFirstNode (&Form->StatementListHead);
   2725       while (!IsNull (&Form->StatementListHead, LinkStatement)) {
   2726         Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
   2727         LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
   2728 
   2729         if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {
   2730           *RetQuestion = Statement;
   2731           break;
   2732         }
   2733 
   2734         if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) {
   2735           *RetQuestion = Statement;
   2736           break;
   2737         }
   2738       }
   2739     }
   2740 
   2741     if (*RetForm != NULL) {
   2742       break;
   2743     }
   2744   }
   2745 
   2746   //
   2747   // restore the OffsetWidth string to the original format.
   2748   //
   2749   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2750     *EndStr = '=';
   2751   } else {
   2752     *EndStr = '&';
   2753   }
   2754 
   2755   return (BOOLEAN) (*RetForm != NULL);
   2756 }
   2757 
   2758 /**
   2759   Popup an save error info and get user input.
   2760 
   2761   @param  TitleId                The form title id.
   2762   @param  HiiHandle              The hii handle for this package.
   2763 
   2764   @retval UINT32                 The user select option for the save fail.
   2765                                  BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
   2766 **/
   2767 UINT32
   2768 ConfirmSaveFail (
   2769   IN EFI_STRING_ID    TitleId,
   2770   IN EFI_HII_HANDLE   HiiHandle
   2771   )
   2772 {
   2773   CHAR16                  *FormTitle;
   2774   CHAR16                  *StringBuffer;
   2775   UINT32                  RetVal;
   2776 
   2777   FormTitle = GetToken (TitleId, HiiHandle);
   2778 
   2779   StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
   2780   ASSERT (StringBuffer != NULL);
   2781 
   2782   UnicodeSPrint (
   2783     StringBuffer,
   2784     24 * sizeof (CHAR16) + StrSize (FormTitle),
   2785     L"Submit Fail For Form: %s.",
   2786     FormTitle
   2787     );
   2788 
   2789   RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
   2790 
   2791   FreePool (StringBuffer);
   2792   FreePool (FormTitle);
   2793 
   2794   return RetVal;
   2795 }
   2796 
   2797 /**
   2798   Popup an NO_SUBMIT_IF error info and get user input.
   2799 
   2800   @param  TitleId                The form title id.
   2801   @param  HiiHandle              The hii handle for this package.
   2802 
   2803   @retval UINT32                 The user select option for the save fail.
   2804                                  BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
   2805 **/
   2806 UINT32
   2807 ConfirmNoSubmitFail (
   2808   IN EFI_STRING_ID    TitleId,
   2809   IN EFI_HII_HANDLE   HiiHandle
   2810   )
   2811 {
   2812   CHAR16                  *FormTitle;
   2813   CHAR16                  *StringBuffer;
   2814   UINT32                  RetVal;
   2815 
   2816   FormTitle = GetToken (TitleId, HiiHandle);
   2817 
   2818   StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
   2819   ASSERT (StringBuffer != NULL);
   2820 
   2821   UnicodeSPrint (
   2822     StringBuffer,
   2823     24 * sizeof (CHAR16) + StrSize (FormTitle),
   2824     L"NO_SUBMIT_IF error For Form: %s.",
   2825     FormTitle
   2826     );
   2827 
   2828   RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
   2829 
   2830   FreePool (StringBuffer);
   2831   FreePool (FormTitle);
   2832 
   2833   return RetVal;
   2834 }
   2835 
   2836 /**
   2837   Discard data based on the input setting scope (Form, FormSet or System).
   2838 
   2839   @param  FormSet                FormSet data structure.
   2840   @param  Form                   Form data structure.
   2841   @param  SettingScope           Setting Scope for Discard action.
   2842 
   2843   @retval EFI_SUCCESS            The function completed successfully.
   2844   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   2845 
   2846 **/
   2847 EFI_STATUS
   2848 DiscardForm (
   2849   IN FORM_BROWSER_FORMSET             *FormSet,
   2850   IN FORM_BROWSER_FORM                *Form,
   2851   IN BROWSER_SETTING_SCOPE            SettingScope
   2852   )
   2853 {
   2854   LIST_ENTRY                   *Link;
   2855   FORMSET_STORAGE              *Storage;
   2856   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   2857   FORM_BROWSER_FORMSET         *LocalFormSet;
   2858   FORM_BROWSER_FORMSET         *OldFormSet;
   2859 
   2860   //
   2861   // Check the supported setting level.
   2862   //
   2863   if (SettingScope >= MaxLevel) {
   2864     return EFI_UNSUPPORTED;
   2865   }
   2866 
   2867   if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
   2868     ConfigInfo = NULL;
   2869     Link = GetFirstNode (&Form->ConfigRequestHead);
   2870     while (!IsNull (&Form->ConfigRequestHead, Link)) {
   2871       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   2872       Link = GetNextNode (&Form->ConfigRequestHead, Link);
   2873 
   2874       if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   2875         continue;
   2876       }
   2877 
   2878       //
   2879       // Skip if there is no RequestElement
   2880       //
   2881       if (ConfigInfo->ElementCount == 0) {
   2882         continue;
   2883       }
   2884 
   2885       //
   2886       // Prepare <ConfigResp>
   2887       //
   2888       SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
   2889 
   2890       //
   2891       // Call callback with Changed type to inform the driver.
   2892       //
   2893       SendDiscardInfoToDriver (FormSet, Form);
   2894     }
   2895 
   2896     ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
   2897   } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
   2898 
   2899     //
   2900     // Discard Buffer storage or Name/Value storage
   2901     //
   2902     Link = GetFirstNode (&FormSet->StorageListHead);
   2903     while (!IsNull (&FormSet->StorageListHead, Link)) {
   2904       Storage = FORMSET_STORAGE_FROM_LINK (Link);
   2905       Link = GetNextNode (&FormSet->StorageListHead, Link);
   2906 
   2907       if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   2908         continue;
   2909       }
   2910 
   2911       //
   2912       // Skip if there is no RequestElement
   2913       //
   2914       if (Storage->ElementCount == 0) {
   2915         continue;
   2916       }
   2917 
   2918       SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
   2919     }
   2920 
   2921     Link = GetFirstNode (&FormSet->FormListHead);
   2922     while (!IsNull (&FormSet->FormListHead, Link)) {
   2923       Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   2924       Link = GetNextNode (&FormSet->FormListHead, Link);
   2925 
   2926       //
   2927       // Call callback with Changed type to inform the driver.
   2928       //
   2929       SendDiscardInfoToDriver (FormSet, Form);
   2930     }
   2931 
   2932     ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
   2933   } else if (SettingScope == SystemLevel) {
   2934     //
   2935     // System Level Discard.
   2936     //
   2937     OldFormSet = mSystemLevelFormSet;
   2938 
   2939     //
   2940     // Discard changed value for each FormSet in the maintain list.
   2941     //
   2942     Link = GetFirstNode (&gBrowserFormSetList);
   2943     while (!IsNull (&gBrowserFormSetList, Link)) {
   2944       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   2945       Link = GetNextNode (&gBrowserFormSetList, Link);
   2946       if (!ValidateFormSet(LocalFormSet)) {
   2947         continue;
   2948       }
   2949 
   2950       mSystemLevelFormSet = LocalFormSet;
   2951 
   2952       DiscardForm (LocalFormSet, NULL, FormSetLevel);
   2953       if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
   2954         //
   2955         // Remove maintain backup list after discard except for the current using FormSet.
   2956         //
   2957         CleanBrowserStorage(LocalFormSet);
   2958         RemoveEntryList (&LocalFormSet->Link);
   2959         DestroyFormSet (LocalFormSet);
   2960       }
   2961     }
   2962 
   2963     mSystemLevelFormSet = OldFormSet;
   2964   }
   2965 
   2966   return EFI_SUCCESS;
   2967 }
   2968 
   2969 /**
   2970   Submit data for a form.
   2971 
   2972   @param  FormSet                FormSet data structure.
   2973   @param  Form                   Form data structure.
   2974 
   2975   @retval EFI_SUCCESS            The function completed successfully.
   2976   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   2977 
   2978 **/
   2979 EFI_STATUS
   2980 SubmitForForm (
   2981   IN FORM_BROWSER_FORMSET             *FormSet,
   2982   IN FORM_BROWSER_FORM                *Form
   2983   )
   2984 {
   2985   EFI_STATUS              Status;
   2986   LIST_ENTRY              *Link;
   2987   EFI_STRING              ConfigResp;
   2988   EFI_STRING              Progress;
   2989   BROWSER_STORAGE         *Storage;
   2990   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   2991 
   2992   if (!IsNvUpdateRequiredForForm (Form)) {
   2993     return EFI_SUCCESS;
   2994   }
   2995 
   2996   Status = NoSubmitCheck (FormSet, &Form, NULL);
   2997   if (EFI_ERROR (Status)) {
   2998     return Status;
   2999   }
   3000 
   3001   Link = GetFirstNode (&Form->ConfigRequestHead);
   3002   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   3003     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   3004     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   3005 
   3006     Storage = ConfigInfo->Storage;
   3007     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   3008       continue;
   3009     }
   3010 
   3011     //
   3012     // Skip if there is no RequestElement
   3013     //
   3014     if (ConfigInfo->ElementCount == 0) {
   3015       continue;
   3016     }
   3017 
   3018     //
   3019     // 1. Prepare <ConfigResp>
   3020     //
   3021     Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
   3022     if (EFI_ERROR (Status)) {
   3023       return Status;
   3024     }
   3025 
   3026     //
   3027     // 2. Set value to hii config routine protocol.
   3028     //
   3029     Status = mHiiConfigRouting->RouteConfig (
   3030                                       mHiiConfigRouting,
   3031                                       ConfigResp,
   3032                                       &Progress
   3033                                       );
   3034     FreePool (ConfigResp);
   3035 
   3036     if (EFI_ERROR (Status)) {
   3037       InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
   3038       continue;
   3039     }
   3040 
   3041     //
   3042     // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
   3043     //
   3044     SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
   3045   }
   3046 
   3047   //
   3048   // 4. Process the save failed storage.
   3049   //
   3050   if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
   3051     if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
   3052       Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3053       while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
   3054         ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
   3055         Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
   3056 
   3057         SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
   3058 
   3059         Status = EFI_SUCCESS;
   3060       }
   3061     } else {
   3062       Status = EFI_UNSUPPORTED;
   3063     }
   3064 
   3065     //
   3066     // Free Form save fail list.
   3067     //
   3068     while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
   3069       Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3070       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
   3071       RemoveEntryList (&ConfigInfo->SaveFailLink);
   3072     }
   3073   }
   3074 
   3075   //
   3076   // 5. Update the NV flag.
   3077   //
   3078   ValueChangeResetFlagUpdate(TRUE, FormSet, Form);
   3079 
   3080   return Status;
   3081 }
   3082 
   3083 /**
   3084   Submit data for a formset.
   3085 
   3086   @param  FormSet                FormSet data structure.
   3087   @param  SkipProcessFail        Whether skip to process the save failed storage.
   3088                                  If submit formset is called when do system level save,
   3089                                  set this value to true and process the failed formset
   3090                                  together.
   3091                                  if submit formset is called when do formset level save,
   3092                                  set the value to false and process the failed storage
   3093                                  right after process all storages for this formset.
   3094 
   3095   @retval EFI_SUCCESS            The function completed successfully.
   3096   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3097 
   3098 **/
   3099 EFI_STATUS
   3100 SubmitForFormSet (
   3101   IN FORM_BROWSER_FORMSET             *FormSet,
   3102   IN BOOLEAN                          SkipProcessFail
   3103   )
   3104 {
   3105   EFI_STATUS              Status;
   3106   LIST_ENTRY              *Link;
   3107   EFI_STRING              ConfigResp;
   3108   EFI_STRING              Progress;
   3109   BROWSER_STORAGE         *Storage;
   3110   FORMSET_STORAGE         *FormSetStorage;
   3111   FORM_BROWSER_FORM       *Form;
   3112   BOOLEAN                 HasInserted;
   3113   FORM_BROWSER_STATEMENT  *Question;
   3114 
   3115   HasInserted = FALSE;
   3116 
   3117   if (!IsNvUpdateRequiredForFormSet (FormSet)) {
   3118     return EFI_SUCCESS;
   3119   }
   3120 
   3121   Form = NULL;
   3122   Status = NoSubmitCheck (FormSet, &Form, &Question);
   3123   if (EFI_ERROR (Status)) {
   3124     if (SkipProcessFail) {
   3125       //
   3126       // Process NO_SUBMIT check first, so insert it at head.
   3127       //
   3128       FormSet->SaveFailForm = Form;
   3129       FormSet->SaveFailStatement = Question;
   3130       InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
   3131     }
   3132 
   3133     return Status;
   3134   }
   3135 
   3136   Form = NULL;
   3137   Question = NULL;
   3138   //
   3139   // Submit Buffer storage or Name/Value storage
   3140   //
   3141   Link = GetFirstNode (&FormSet->StorageListHead);
   3142   while (!IsNull (&FormSet->StorageListHead, Link)) {
   3143     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   3144     Storage        = FormSetStorage->BrowserStorage;
   3145     Link = GetNextNode (&FormSet->StorageListHead, Link);
   3146 
   3147     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   3148       continue;
   3149     }
   3150 
   3151     //
   3152     // Skip if there is no RequestElement
   3153     //
   3154     if (FormSetStorage->ElementCount == 0) {
   3155       continue;
   3156     }
   3157 
   3158     //
   3159     // 1. Prepare <ConfigResp>
   3160     //
   3161     Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
   3162     if (EFI_ERROR (Status)) {
   3163       return Status;
   3164     }
   3165 
   3166     //
   3167     // 2. Send <ConfigResp> to Routine config Protocol.
   3168     //
   3169     Status = mHiiConfigRouting->RouteConfig (
   3170                                       mHiiConfigRouting,
   3171                                       ConfigResp,
   3172                                       &Progress
   3173                                       );
   3174     if (EFI_ERROR (Status)) {
   3175       InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
   3176       if (!HasInserted) {
   3177         //
   3178         // Call submit formset for system level, save the formset info
   3179         // and process later.
   3180         //
   3181         FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);
   3182         ASSERT (Form != NULL && Question != NULL);
   3183         FormSet->SaveFailForm = Form;
   3184         FormSet->SaveFailStatement = Question;
   3185         if (SkipProcessFail) {
   3186           InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
   3187         }
   3188         HasInserted = TRUE;
   3189       }
   3190 
   3191       FreePool (ConfigResp);
   3192       continue;
   3193     }
   3194 
   3195     FreePool (ConfigResp);
   3196     //
   3197     // 3. Config success, update storage shadow Buffer
   3198     //
   3199     SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
   3200   }
   3201 
   3202   //
   3203   // 4. Has save fail storage need to handle.
   3204   //
   3205   if (Form != NULL) {
   3206     if (!SkipProcessFail) {
   3207       //
   3208       // If not in system level, just handl the save failed storage here.
   3209       //
   3210       if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
   3211         Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
   3212         while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
   3213           FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
   3214           Storage        = FormSetStorage->BrowserStorage;
   3215           Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
   3216 
   3217           SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
   3218 
   3219           Status = EFI_SUCCESS;
   3220         }
   3221       } else {
   3222         UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
   3223 
   3224         gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
   3225         gCurrentSelection->Handle = FormSet->HiiHandle;
   3226         CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
   3227         gCurrentSelection->FormId = Form->FormId;
   3228         gCurrentSelection->QuestionId = Question->QuestionId;
   3229 
   3230         Status = EFI_UNSUPPORTED;
   3231       }
   3232 
   3233       //
   3234       // Free FormSet save fail list.
   3235       //
   3236       while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
   3237         Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
   3238         FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
   3239         RemoveEntryList (&FormSetStorage->SaveFailLink);
   3240       }
   3241     } else {
   3242       //
   3243       // If in system level, just return error and handle the failed formset later.
   3244       //
   3245       Status = EFI_UNSUPPORTED;
   3246     }
   3247   }
   3248 
   3249   //
   3250   // 5. Update the NV flag.
   3251   //
   3252   ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
   3253 
   3254   return Status;
   3255 }
   3256 
   3257 /**
   3258   Submit data for all formsets.
   3259 
   3260   @retval EFI_SUCCESS            The function completed successfully.
   3261   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3262 
   3263 **/
   3264 EFI_STATUS
   3265 SubmitForSystem (
   3266   VOID
   3267   )
   3268 {
   3269   EFI_STATUS              Status;
   3270   LIST_ENTRY              *Link;
   3271   LIST_ENTRY              *StorageLink;
   3272   FORMSET_STORAGE         *FormSetStorage;
   3273   FORM_BROWSER_FORM       *Form;
   3274   FORM_BROWSER_FORMSET    *LocalFormSet;
   3275   UINT32                  UserSelection;
   3276   FORM_BROWSER_STATEMENT  *Question;
   3277 
   3278   mSystemSubmit = TRUE;
   3279   Link = GetFirstNode (&gBrowserFormSetList);
   3280   while (!IsNull (&gBrowserFormSetList, Link)) {
   3281     LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   3282     Link = GetNextNode (&gBrowserFormSetList, Link);
   3283     if (!ValidateFormSet(LocalFormSet)) {
   3284       continue;
   3285     }
   3286 
   3287     Status = SubmitForFormSet (LocalFormSet, TRUE);
   3288     if (EFI_ERROR (Status)) {
   3289       continue;
   3290     }
   3291 
   3292     //
   3293     // Remove maintain backup list after save except for the current using FormSet.
   3294     //
   3295     if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
   3296       CleanBrowserStorage(LocalFormSet);
   3297       RemoveEntryList (&LocalFormSet->Link);
   3298       DestroyFormSet (LocalFormSet);
   3299     }
   3300   }
   3301   mSystemSubmit = FALSE;
   3302 
   3303   Status = EFI_SUCCESS;
   3304 
   3305   //
   3306   // Process the save failed formsets.
   3307   //
   3308   Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3309   while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
   3310     LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
   3311     Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
   3312 
   3313     if (!ValidateFormSet(LocalFormSet)) {
   3314       continue;
   3315     }
   3316 
   3317     Form = LocalFormSet->SaveFailForm;
   3318     Question= LocalFormSet->SaveFailStatement;
   3319 
   3320     //
   3321     // Confirm with user, get user input.
   3322     //
   3323     if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3324       //
   3325       // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
   3326       //
   3327       UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
   3328     } else {
   3329       UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
   3330     }
   3331 
   3332     if (UserSelection == BROWSER_ACTION_DISCARD) {
   3333       if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3334         StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
   3335         while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
   3336           FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
   3337           StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
   3338 
   3339           SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
   3340         }
   3341       } else {
   3342         StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
   3343         while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
   3344           FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
   3345           StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
   3346 
   3347           SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
   3348         }
   3349       }
   3350 
   3351       if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
   3352         CleanBrowserStorage(LocalFormSet);
   3353         RemoveEntryList (&LocalFormSet->Link);
   3354         RemoveEntryList (&LocalFormSet->SaveFailLink);
   3355         DestroyFormSet (LocalFormSet);
   3356       } else {
   3357         ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);
   3358       }
   3359     } else {
   3360       if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3361         NoSubmitCheck (LocalFormSet, &Form, &Question);
   3362       }
   3363 
   3364       UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
   3365 
   3366       gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
   3367       gCurrentSelection->Handle = LocalFormSet->HiiHandle;
   3368       CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
   3369       gCurrentSelection->FormId = Form->FormId;
   3370       gCurrentSelection->QuestionId = Question->QuestionId;
   3371 
   3372       Status = EFI_UNSUPPORTED;
   3373       break;
   3374     }
   3375   }
   3376 
   3377   //
   3378   // Clean the list which will not process.
   3379   //
   3380   while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
   3381     Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3382     LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
   3383     RemoveEntryList (&LocalFormSet->SaveFailLink);
   3384 
   3385     while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3386       StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
   3387       FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
   3388       RemoveEntryList (&FormSetStorage->SaveFailLink);
   3389     }
   3390   }
   3391 
   3392   return Status;
   3393 }
   3394 
   3395 /**
   3396   Submit data based on the input Setting level (Form, FormSet or System).
   3397 
   3398   @param  FormSet                FormSet data structure.
   3399   @param  Form                   Form data structure.
   3400   @param  SettingScope           Setting Scope for Submit action.
   3401 
   3402   @retval EFI_SUCCESS            The function completed successfully.
   3403   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3404 
   3405 **/
   3406 EFI_STATUS
   3407 SubmitForm (
   3408   IN FORM_BROWSER_FORMSET             *FormSet,
   3409   IN FORM_BROWSER_FORM                *Form,
   3410   IN BROWSER_SETTING_SCOPE            SettingScope
   3411   )
   3412 {
   3413   EFI_STATUS              Status;
   3414 
   3415   switch (SettingScope) {
   3416   case FormLevel:
   3417     Status = SubmitForForm(FormSet, Form);
   3418     break;
   3419 
   3420   case FormSetLevel:
   3421     Status = SubmitForFormSet (FormSet, FALSE);
   3422     break;
   3423 
   3424   case SystemLevel:
   3425     Status = SubmitForSystem ();
   3426     break;
   3427 
   3428   default:
   3429     Status = EFI_UNSUPPORTED;
   3430     break;
   3431   }
   3432 
   3433   return Status;
   3434 }
   3435 
   3436 /**
   3437   Converts the unicode character of the string from uppercase to lowercase.
   3438   This is a internal function.
   3439 
   3440   @param ConfigString  String to be converted
   3441 
   3442 **/
   3443 VOID
   3444 EFIAPI
   3445 HiiToLower (
   3446   IN EFI_STRING  ConfigString
   3447   )
   3448 {
   3449   EFI_STRING  String;
   3450   BOOLEAN     Lower;
   3451 
   3452   ASSERT (ConfigString != NULL);
   3453 
   3454   //
   3455   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
   3456   //
   3457   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
   3458     if (*String == L'=') {
   3459       Lower = TRUE;
   3460     } else if (*String == L'&') {
   3461       Lower = FALSE;
   3462     } else if (Lower && *String >= L'A' && *String <= L'F') {
   3463       *String = (CHAR16) (*String - L'A' + L'a');
   3464     }
   3465   }
   3466 }
   3467 
   3468 /**
   3469   Find the point in the ConfigResp string for this question.
   3470 
   3471   @param  Question               The question.
   3472   @param  ConfigResp             Get ConfigResp string.
   3473 
   3474   @retval  point to the offset where is for this question.
   3475 
   3476 **/
   3477 CHAR16 *
   3478 GetOffsetFromConfigResp (
   3479   IN FORM_BROWSER_STATEMENT           *Question,
   3480   IN CHAR16                           *ConfigResp
   3481   )
   3482 {
   3483   CHAR16                       *RequestElement;
   3484   CHAR16                       *BlockData;
   3485 
   3486   //
   3487   // Type is EFI_HII_VARSTORE_NAME_VALUE.
   3488   //
   3489   if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   3490     RequestElement = StrStr (ConfigResp, Question->VariableName);
   3491     if (RequestElement != NULL) {
   3492       //
   3493       // Skip the "VariableName=" field.
   3494       //
   3495       RequestElement += StrLen (Question->VariableName) + 1;
   3496     }
   3497 
   3498     return RequestElement;
   3499   }
   3500 
   3501   //
   3502   // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
   3503   //
   3504 
   3505   //
   3506   // 1. Directly use Question->BlockName to find.
   3507   //
   3508   RequestElement = StrStr (ConfigResp, Question->BlockName);
   3509   if (RequestElement != NULL) {
   3510     //
   3511     // Skip the "Question->BlockName&VALUE=" field.
   3512     //
   3513     RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
   3514     return RequestElement;
   3515   }
   3516 
   3517   //
   3518   // 2. Change all hex digits in Question->BlockName to lower and compare again.
   3519   //
   3520   BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName);
   3521   ASSERT (BlockData != NULL);
   3522   HiiToLower (BlockData);
   3523   RequestElement = StrStr (ConfigResp, BlockData);
   3524   FreePool (BlockData);
   3525 
   3526   if (RequestElement != NULL) {
   3527     //
   3528     // Skip the "Question->BlockName&VALUE=" field.
   3529     //
   3530     RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
   3531   }
   3532 
   3533   return RequestElement;
   3534 }
   3535 
   3536 /**
   3537   Get Question default value from AltCfg string.
   3538 
   3539   @param  FormSet                The form set.
   3540   @param  Form                   The form
   3541   @param  Question               The question.
   3542 
   3543   @retval EFI_SUCCESS            Question is reset to default value.
   3544 
   3545 **/
   3546 EFI_STATUS
   3547 GetDefaultValueFromAltCfg (
   3548   IN     FORM_BROWSER_FORMSET             *FormSet,
   3549   IN     FORM_BROWSER_FORM                *Form,
   3550   IN OUT FORM_BROWSER_STATEMENT           *Question
   3551   )
   3552 {
   3553   BROWSER_STORAGE              *Storage;
   3554   FORMSET_STORAGE              *FormSetStorage;
   3555   CHAR16                       *ConfigResp;
   3556   CHAR16                       *Value;
   3557   LIST_ENTRY                   *Link;
   3558   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   3559 
   3560   Storage = Question->Storage;
   3561   if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
   3562     return EFI_NOT_FOUND;
   3563   }
   3564 
   3565   //
   3566   // Try to get AltCfg string from form. If not found it, then
   3567   // try to get it from formset.
   3568   //
   3569   ConfigResp    = NULL;
   3570   Link = GetFirstNode (&Form->ConfigRequestHead);
   3571   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   3572     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   3573     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   3574 
   3575     if (Storage == ConfigInfo->Storage) {
   3576       ConfigResp = ConfigInfo->ConfigAltResp;
   3577       break;
   3578     }
   3579   }
   3580 
   3581   if (ConfigResp == NULL) {
   3582     Link = GetFirstNode (&FormSet->StorageListHead);
   3583     while (!IsNull (&FormSet->StorageListHead, Link)) {
   3584       FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   3585       Link = GetNextNode (&FormSet->StorageListHead, Link);
   3586 
   3587       if (Storage == FormSetStorage->BrowserStorage) {
   3588         ConfigResp = FormSetStorage->ConfigAltResp;
   3589         break;
   3590       }
   3591     }
   3592   }
   3593 
   3594   if (ConfigResp == NULL) {
   3595     return EFI_NOT_FOUND;
   3596   }
   3597 
   3598   Value = GetOffsetFromConfigResp (Question, ConfigResp);
   3599   if (Value == NULL) {
   3600     return EFI_NOT_FOUND;
   3601   }
   3602 
   3603   return BufferToValue (Question, Value);
   3604 }
   3605 
   3606 /**
   3607   Get default Id value used for browser.
   3608 
   3609   @param  DefaultId              The default id value used by hii.
   3610 
   3611   @retval Browser used default value.
   3612 
   3613 **/
   3614 INTN
   3615 GetDefaultIdForCallBack (
   3616   UINTN DefaultId
   3617   )
   3618 {
   3619   if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
   3620     return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
   3621   } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
   3622     return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
   3623   } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
   3624     return EFI_BROWSER_ACTION_DEFAULT_SAFE;
   3625   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
   3626     return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
   3627   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
   3628     return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
   3629   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
   3630     return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
   3631   } else {
   3632     return -1;
   3633   }
   3634 }
   3635 
   3636 
   3637 
   3638 /**
   3639   Return data element in an Array by its Index.
   3640 
   3641   @param  Array                  The data array.
   3642   @param  Type                   Type of the data in this array.
   3643   @param  Index                  Zero based index for data in this array.
   3644 
   3645   @retval Value                  The data to be returned
   3646 
   3647 **/
   3648 UINT64
   3649 GetArrayData (
   3650   IN VOID                     *Array,
   3651   IN UINT8                    Type,
   3652   IN UINTN                    Index
   3653   )
   3654 {
   3655   UINT64 Data;
   3656 
   3657   ASSERT (Array != NULL);
   3658 
   3659   Data = 0;
   3660   switch (Type) {
   3661   case EFI_IFR_TYPE_NUM_SIZE_8:
   3662     Data = (UINT64) *(((UINT8 *) Array) + Index);
   3663     break;
   3664 
   3665   case EFI_IFR_TYPE_NUM_SIZE_16:
   3666     Data = (UINT64) *(((UINT16 *) Array) + Index);
   3667     break;
   3668 
   3669   case EFI_IFR_TYPE_NUM_SIZE_32:
   3670     Data = (UINT64) *(((UINT32 *) Array) + Index);
   3671     break;
   3672 
   3673   case EFI_IFR_TYPE_NUM_SIZE_64:
   3674     Data = (UINT64) *(((UINT64 *) Array) + Index);
   3675     break;
   3676 
   3677   default:
   3678     break;
   3679   }
   3680 
   3681   return Data;
   3682 }
   3683 
   3684 
   3685 /**
   3686   Set value of a data element in an Array by its Index.
   3687 
   3688   @param  Array                  The data array.
   3689   @param  Type                   Type of the data in this array.
   3690   @param  Index                  Zero based index for data in this array.
   3691   @param  Value                  The value to be set.
   3692 
   3693 **/
   3694 VOID
   3695 SetArrayData (
   3696   IN VOID                     *Array,
   3697   IN UINT8                    Type,
   3698   IN UINTN                    Index,
   3699   IN UINT64                   Value
   3700   )
   3701 {
   3702 
   3703   ASSERT (Array != NULL);
   3704 
   3705   switch (Type) {
   3706   case EFI_IFR_TYPE_NUM_SIZE_8:
   3707     *(((UINT8 *) Array) + Index) = (UINT8) Value;
   3708     break;
   3709 
   3710   case EFI_IFR_TYPE_NUM_SIZE_16:
   3711     *(((UINT16 *) Array) + Index) = (UINT16) Value;
   3712     break;
   3713 
   3714   case EFI_IFR_TYPE_NUM_SIZE_32:
   3715     *(((UINT32 *) Array) + Index) = (UINT32) Value;
   3716     break;
   3717 
   3718   case EFI_IFR_TYPE_NUM_SIZE_64:
   3719     *(((UINT64 *) Array) + Index) = (UINT64) Value;
   3720     break;
   3721 
   3722   default:
   3723     break;
   3724   }
   3725 }
   3726 
   3727 /**
   3728   Search an Option of a Question by its value.
   3729 
   3730   @param  Question               The Question
   3731   @param  OptionValue            Value for Option to be searched.
   3732 
   3733   @retval Pointer                Pointer to the found Option.
   3734   @retval NULL                   Option not found.
   3735 
   3736 **/
   3737 QUESTION_OPTION *
   3738 ValueToOption (
   3739   IN FORM_BROWSER_STATEMENT   *Question,
   3740   IN EFI_HII_VALUE            *OptionValue
   3741   )
   3742 {
   3743   LIST_ENTRY       *Link;
   3744   QUESTION_OPTION  *Option;
   3745   INTN             Result;
   3746 
   3747   Link = GetFirstNode (&Question->OptionListHead);
   3748   while (!IsNull (&Question->OptionListHead, Link)) {
   3749     Option = QUESTION_OPTION_FROM_LINK (Link);
   3750 
   3751     if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
   3752       //
   3753       // Check the suppressif condition, only a valid option can be return.
   3754       //
   3755       if ((Option->SuppressExpression == NULL) ||
   3756           ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
   3757         return Option;
   3758       }
   3759     }
   3760 
   3761     Link = GetNextNode (&Question->OptionListHead, Link);
   3762   }
   3763 
   3764   return NULL;
   3765 }
   3766 
   3767 
   3768 /**
   3769   Reset Question to its default value.
   3770 
   3771   @param  FormSet                The form set.
   3772   @param  Form                   The form.
   3773   @param  Question               The question.
   3774   @param  DefaultId              The Class of the default.
   3775 
   3776   @retval EFI_SUCCESS            Question is reset to default value.
   3777 
   3778 **/
   3779 EFI_STATUS
   3780 GetQuestionDefault (
   3781   IN FORM_BROWSER_FORMSET             *FormSet,
   3782   IN FORM_BROWSER_FORM                *Form,
   3783   IN FORM_BROWSER_STATEMENT           *Question,
   3784   IN UINT16                           DefaultId
   3785   )
   3786 {
   3787   EFI_STATUS              Status;
   3788   LIST_ENTRY              *Link;
   3789   QUESTION_DEFAULT        *Default;
   3790   QUESTION_OPTION         *Option;
   3791   EFI_HII_VALUE           *HiiValue;
   3792   UINT8                   Index;
   3793   EFI_STRING              StrValue;
   3794   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   3795   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   3796   INTN                            Action;
   3797   CHAR16                          *NewString;
   3798 
   3799   Status   = EFI_NOT_FOUND;
   3800   StrValue = NULL;
   3801 
   3802   //
   3803   // Statement don't have storage, skip them
   3804   //
   3805   if (Question->QuestionId == 0) {
   3806     return Status;
   3807   }
   3808 
   3809   //
   3810   // There are Five ways to specify default value for a Question:
   3811   //  1, use call back function (highest priority)
   3812   //  2, use ExtractConfig function
   3813   //  3, use nested EFI_IFR_DEFAULT
   3814   //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
   3815   //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
   3816   //
   3817   HiiValue = &Question->HiiValue;
   3818 
   3819   //
   3820   // Get Question defaut value from call back function.
   3821   //
   3822   ConfigAccess = FormSet->ConfigAccess;
   3823   Action = GetDefaultIdForCallBack (DefaultId);
   3824   if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
   3825     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   3826     Status = ConfigAccess->Callback (
   3827                              ConfigAccess,
   3828                              Action,
   3829                              Question->QuestionId,
   3830                              HiiValue->Type,
   3831                              &HiiValue->Value,
   3832                              &ActionRequest
   3833                              );
   3834     if (!EFI_ERROR (Status)) {
   3835       if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
   3836         NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
   3837         ASSERT (NewString != NULL);
   3838 
   3839         ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
   3840         if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
   3841           CopyMem (Question->BufferValue, NewString, StrSize (NewString));
   3842         } else {
   3843           CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
   3844         }
   3845 
   3846         FreePool (NewString);
   3847       }
   3848       return Status;
   3849     }
   3850   }
   3851 
   3852   //
   3853   // Get default value from altcfg string.
   3854   //
   3855   if (ConfigAccess != NULL) {
   3856     Status = GetDefaultValueFromAltCfg(FormSet, Form, Question);
   3857     if (!EFI_ERROR (Status)) {
   3858         return Status;
   3859     }
   3860   }
   3861 
   3862   //
   3863   // EFI_IFR_DEFAULT has highest priority
   3864   //
   3865   if (!IsListEmpty (&Question->DefaultListHead)) {
   3866     Link = GetFirstNode (&Question->DefaultListHead);
   3867     while (!IsNull (&Question->DefaultListHead, Link)) {
   3868       Default = QUESTION_DEFAULT_FROM_LINK (Link);
   3869 
   3870       if (Default->DefaultId == DefaultId) {
   3871         if (Default->ValueExpression != NULL) {
   3872           //
   3873           // Default is provided by an Expression, evaluate it
   3874           //
   3875           Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
   3876           if (EFI_ERROR (Status)) {
   3877             return Status;
   3878           }
   3879 
   3880           if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
   3881             ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
   3882             if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
   3883               CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
   3884               Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
   3885             } else {
   3886               CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
   3887               Question->HiiValue.BufferLen = Question->StorageWidth;
   3888             }
   3889             FreePool (Default->ValueExpression->Result.Buffer);
   3890           }
   3891           HiiValue->Type = Default->ValueExpression->Result.Type;
   3892           CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
   3893         } else {
   3894           //
   3895           // Default value is embedded in EFI_IFR_DEFAULT
   3896           //
   3897           if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
   3898             ASSERT (HiiValue->Buffer != NULL);
   3899             CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
   3900           } else {
   3901             CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
   3902           }
   3903         }
   3904 
   3905         if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
   3906           StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
   3907           if (StrValue == NULL) {
   3908             return EFI_NOT_FOUND;
   3909           }
   3910           if (Question->StorageWidth > StrSize (StrValue)) {
   3911             CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
   3912           } else {
   3913             CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
   3914           }
   3915         }
   3916 
   3917         return EFI_SUCCESS;
   3918       }
   3919 
   3920       Link = GetNextNode (&Question->DefaultListHead, Link);
   3921     }
   3922   }
   3923 
   3924   //
   3925   // EFI_ONE_OF_OPTION
   3926   //
   3927   if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
   3928     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
   3929       //
   3930       // OneOfOption could only provide Standard and Manufacturing default
   3931       //
   3932       Link = GetFirstNode (&Question->OptionListHead);
   3933       while (!IsNull (&Question->OptionListHead, Link)) {
   3934         Option = QUESTION_OPTION_FROM_LINK (Link);
   3935         Link = GetNextNode (&Question->OptionListHead, Link);
   3936 
   3937         if ((Option->SuppressExpression != NULL) &&
   3938             EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
   3939           continue;
   3940         }
   3941 
   3942         if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
   3943             ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
   3944            ) {
   3945           CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
   3946 
   3947           return EFI_SUCCESS;
   3948         }
   3949       }
   3950     }
   3951   }
   3952 
   3953   //
   3954   // EFI_IFR_CHECKBOX - lowest priority
   3955   //
   3956   if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
   3957     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
   3958       //
   3959       // Checkbox could only provide Standard and Manufacturing default
   3960       //
   3961       if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
   3962           ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
   3963          ) {
   3964         HiiValue->Value.b = TRUE;
   3965       } else {
   3966         HiiValue->Value.b = FALSE;
   3967       }
   3968 
   3969       return EFI_SUCCESS;
   3970     }
   3971   }
   3972 
   3973   //
   3974   // For Questions without default
   3975   //
   3976   Status = EFI_NOT_FOUND;
   3977   switch (Question->Operand) {
   3978   case EFI_IFR_NUMERIC_OP:
   3979     //
   3980     // Take minimum value as numeric default value
   3981     //
   3982     if ((Question->Flags & EFI_IFR_DISPLAY) == 0) {
   3983       //
   3984       // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
   3985       //
   3986       switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) {
   3987       case EFI_IFR_NUMERIC_SIZE_1:
   3988         if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) {
   3989           HiiValue->Value.u8 = (UINT8) Question->Minimum;
   3990           Status = EFI_SUCCESS;
   3991         }
   3992         break;
   3993       case EFI_IFR_NUMERIC_SIZE_2:
   3994         if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) {
   3995           HiiValue->Value.u16 = (UINT16) Question->Minimum;
   3996           Status = EFI_SUCCESS;
   3997         }
   3998         break;
   3999       case EFI_IFR_NUMERIC_SIZE_4:
   4000         if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) {
   4001           HiiValue->Value.u32 = (UINT32) Question->Minimum;
   4002           Status = EFI_SUCCESS;
   4003         }
   4004         break;
   4005       case EFI_IFR_NUMERIC_SIZE_8:
   4006         if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) {
   4007           HiiValue->Value.u64 = Question->Minimum;
   4008           Status = EFI_SUCCESS;
   4009         }
   4010         break;
   4011       default:
   4012         break;
   4013       }
   4014     } else {
   4015       if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
   4016         HiiValue->Value.u64 = Question->Minimum;
   4017         Status = EFI_SUCCESS;
   4018       }
   4019     }
   4020     break;
   4021 
   4022   case EFI_IFR_ONE_OF_OP:
   4023     //
   4024     // Take first oneof option as oneof's default value
   4025     //
   4026     if (ValueToOption (Question, HiiValue) == NULL) {
   4027       Link = GetFirstNode (&Question->OptionListHead);
   4028       while (!IsNull (&Question->OptionListHead, Link)) {
   4029         Option = QUESTION_OPTION_FROM_LINK (Link);
   4030         Link = GetNextNode (&Question->OptionListHead, Link);
   4031 
   4032         if ((Option->SuppressExpression != NULL) &&
   4033             EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
   4034           continue;
   4035         }
   4036 
   4037         CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
   4038         Status = EFI_SUCCESS;
   4039         break;
   4040       }
   4041     }
   4042     break;
   4043 
   4044   case EFI_IFR_ORDERED_LIST_OP:
   4045     //
   4046     // Take option sequence in IFR as ordered list's default value
   4047     //
   4048     Index = 0;
   4049     Link = GetFirstNode (&Question->OptionListHead);
   4050     while (!IsNull (&Question->OptionListHead, Link)) {
   4051       Status = EFI_SUCCESS;
   4052       Option = QUESTION_OPTION_FROM_LINK (Link);
   4053       Link = GetNextNode (&Question->OptionListHead, Link);
   4054 
   4055       if ((Option->SuppressExpression != NULL) &&
   4056           EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
   4057         continue;
   4058       }
   4059 
   4060       SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
   4061 
   4062       Index++;
   4063       if (Index >= Question->MaxContainers) {
   4064         break;
   4065       }
   4066     }
   4067     break;
   4068 
   4069   default:
   4070     break;
   4071   }
   4072 
   4073   return Status;
   4074 }
   4075 
   4076 /**
   4077   Get AltCfg string for current form.
   4078 
   4079   @param  FormSet                Form data structure.
   4080   @param  Form                   Form data structure.
   4081   @param  DefaultId              The Class of the default.
   4082   @param  BrowserStorage         The input request storage for the questions.
   4083 
   4084 **/
   4085 VOID
   4086 ExtractAltCfgForForm (
   4087   IN FORM_BROWSER_FORMSET   *FormSet,
   4088   IN FORM_BROWSER_FORM      *Form,
   4089   IN UINT16                 DefaultId,
   4090   IN BROWSER_STORAGE        *BrowserStorage
   4091   )
   4092 {
   4093   EFI_STATUS                   Status;
   4094   LIST_ENTRY                   *Link;
   4095   CHAR16                       *ConfigResp;
   4096   CHAR16                       *Progress;
   4097   CHAR16                       *Result;
   4098   BROWSER_STORAGE              *Storage;
   4099   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   4100   FORMSET_STORAGE              *FormSetStorage;
   4101 
   4102   //
   4103   // Check whether has get AltCfg string for this formset.
   4104   // If yes, no need to get AltCfg for form.
   4105   //
   4106   Link = GetFirstNode (&FormSet->StorageListHead);
   4107   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4108     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   4109     Storage        = FormSetStorage->BrowserStorage;
   4110     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4111     if (BrowserStorage != NULL && BrowserStorage != Storage) {
   4112       continue;
   4113     }
   4114 
   4115     if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE &&
   4116         FormSetStorage->ElementCount != 0 &&
   4117         FormSetStorage->HasCallAltCfg) {
   4118       return;
   4119     }
   4120   }
   4121 
   4122   //
   4123   // Get AltCfg string for each form.
   4124   //
   4125   Link = GetFirstNode (&Form->ConfigRequestHead);
   4126   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   4127     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   4128     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   4129 
   4130     Storage = ConfigInfo->Storage;
   4131     if (BrowserStorage != NULL && BrowserStorage != Storage) {
   4132       continue;
   4133     }
   4134 
   4135     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   4136       continue;
   4137     }
   4138 
   4139     //
   4140     // 1. Skip if there is no RequestElement
   4141     //
   4142     if (ConfigInfo->ElementCount == 0) {
   4143       continue;
   4144     }
   4145 
   4146     //
   4147     // 2. Get value through hii config routine protocol.
   4148     //
   4149     Status = mHiiConfigRouting->ExtractConfig (
   4150                                       mHiiConfigRouting,
   4151                                       ConfigInfo->ConfigRequest,
   4152                                       &Progress,
   4153                                       &Result
   4154                                       );
   4155     if (EFI_ERROR (Status)) {
   4156       continue;
   4157     }
   4158 
   4159     //
   4160     // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
   4161     //    Get the default configuration string according to the default ID.
   4162     //
   4163     Status = mHiiConfigRouting->GetAltConfig (
   4164                                   mHiiConfigRouting,
   4165                                   Result,
   4166                                   &Storage->Guid,
   4167                                   Storage->Name,
   4168                                   NULL,
   4169                                   &DefaultId,  // it can be NULL to get the current setting.
   4170                                   &ConfigResp
   4171                                 );
   4172     FreePool (Result);
   4173     if (EFI_ERROR (Status)) {
   4174       continue;
   4175     }
   4176 
   4177     ConfigInfo->ConfigAltResp = ConfigResp;
   4178   }
   4179 }
   4180 
   4181 /**
   4182   Clean AltCfg string for current form.
   4183 
   4184   @param  Form                   Form data structure.
   4185 
   4186 **/
   4187 VOID
   4188 CleanAltCfgForForm (
   4189   IN FORM_BROWSER_FORM   *Form
   4190   )
   4191 {
   4192   LIST_ENTRY              *Link;
   4193   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   4194 
   4195   Link = GetFirstNode (&Form->ConfigRequestHead);
   4196   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   4197     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   4198     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   4199 
   4200     if (ConfigInfo->ConfigAltResp != NULL) {
   4201       FreePool (ConfigInfo->ConfigAltResp);
   4202       ConfigInfo->ConfigAltResp = NULL;
   4203     }
   4204   }
   4205 }
   4206 
   4207 /**
   4208   Get AltCfg string for current formset.
   4209 
   4210   @param  FormSet                Form data structure.
   4211   @param  DefaultId              The Class of the default.
   4212   @param  BrowserStorage         The input request storage for the questions.
   4213 
   4214 **/
   4215 VOID
   4216 ExtractAltCfgForFormSet (
   4217   IN FORM_BROWSER_FORMSET   *FormSet,
   4218   IN UINT16                 DefaultId,
   4219   IN BROWSER_STORAGE        *BrowserStorage
   4220   )
   4221 {
   4222   EFI_STATUS              Status;
   4223   LIST_ENTRY              *Link;
   4224   CHAR16                  *ConfigResp;
   4225   CHAR16                  *Progress;
   4226   CHAR16                  *Result;
   4227   BROWSER_STORAGE         *Storage;
   4228   FORMSET_STORAGE         *FormSetStorage;
   4229 
   4230   Link = GetFirstNode (&FormSet->StorageListHead);
   4231   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4232     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   4233     Storage        = FormSetStorage->BrowserStorage;
   4234     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4235 
   4236     if (BrowserStorage != NULL && BrowserStorage != Storage) {
   4237       continue;
   4238     }
   4239 
   4240     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   4241       continue;
   4242     }
   4243 
   4244     //
   4245     // 1. Skip if there is no RequestElement
   4246     //
   4247     if (FormSetStorage->ElementCount == 0) {
   4248       continue;
   4249     }
   4250 
   4251     FormSetStorage->HasCallAltCfg = TRUE;
   4252 
   4253     //
   4254     // 2. Get value through hii config routine protocol.
   4255     //
   4256     Status = mHiiConfigRouting->ExtractConfig (
   4257                                       mHiiConfigRouting,
   4258                                       FormSetStorage->ConfigRequest,
   4259                                       &Progress,
   4260                                       &Result
   4261                                       );
   4262     if (EFI_ERROR (Status)) {
   4263       continue;
   4264     }
   4265 
   4266     //
   4267     // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
   4268     //    Get the default configuration string according to the default ID.
   4269     //
   4270     Status = mHiiConfigRouting->GetAltConfig (
   4271                                   mHiiConfigRouting,
   4272                                   Result,
   4273                                   &Storage->Guid,
   4274                                   Storage->Name,
   4275                                   NULL,
   4276                                   &DefaultId,  // it can be NULL to get the current setting.
   4277                                   &ConfigResp
   4278                                 );
   4279 
   4280     FreePool (Result);
   4281     if (EFI_ERROR (Status)) {
   4282       continue;
   4283     }
   4284 
   4285     FormSetStorage->ConfigAltResp = ConfigResp;
   4286   }
   4287 
   4288 }
   4289 
   4290 /**
   4291   Clean AltCfg string for current formset.
   4292 
   4293   @param  FormSet                Form data structure.
   4294 
   4295 **/
   4296 VOID
   4297 CleanAltCfgForFormSet (
   4298   IN FORM_BROWSER_FORMSET   *FormSet
   4299   )
   4300 {
   4301   LIST_ENTRY              *Link;
   4302   FORMSET_STORAGE         *FormSetStorage;
   4303 
   4304   Link = GetFirstNode (&FormSet->StorageListHead);
   4305   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4306     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   4307     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4308 
   4309     if (FormSetStorage->ConfigAltResp != NULL) {
   4310       FreePool (FormSetStorage->ConfigAltResp);
   4311       FormSetStorage->ConfigAltResp = NULL;
   4312     }
   4313 
   4314     FormSetStorage->HasCallAltCfg = FALSE;
   4315   }
   4316 }
   4317 
   4318 /**
   4319   Reset Questions to their initial value or default value in a Form, Formset or System.
   4320 
   4321   GetDefaultValueScope parameter decides which questions will reset
   4322   to its default value.
   4323 
   4324   @param  FormSet                FormSet data structure.
   4325   @param  Form                   Form data structure.
   4326   @param  DefaultId              The Class of the default.
   4327   @param  SettingScope           Setting Scope for Default action.
   4328   @param  GetDefaultValueScope   Get default value scope.
   4329   @param  Storage                Get default value only for this storage.
   4330   @param  RetrieveValueFirst     Whether call the retrieve call back to
   4331                                  get the initial value before get default
   4332                                  value.
   4333   @param  SkipGetAltCfg          Whether skip the get altcfg string process.
   4334 
   4335   @retval EFI_SUCCESS            The function completed successfully.
   4336   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   4337 
   4338 **/
   4339 EFI_STATUS
   4340 ExtractDefault (
   4341   IN FORM_BROWSER_FORMSET             *FormSet,
   4342   IN FORM_BROWSER_FORM                *Form,
   4343   IN UINT16                           DefaultId,
   4344   IN BROWSER_SETTING_SCOPE            SettingScope,
   4345   IN BROWSER_GET_DEFAULT_VALUE        GetDefaultValueScope,
   4346   IN BROWSER_STORAGE                  *Storage OPTIONAL,
   4347   IN BOOLEAN                          RetrieveValueFirst,
   4348   IN BOOLEAN                          SkipGetAltCfg
   4349   )
   4350 {
   4351   EFI_STATUS              Status;
   4352   LIST_ENTRY              *FormLink;
   4353   LIST_ENTRY              *Link;
   4354   FORM_BROWSER_STATEMENT  *Question;
   4355   FORM_BROWSER_FORMSET    *LocalFormSet;
   4356   FORM_BROWSER_FORMSET    *OldFormSet;
   4357 
   4358   Status = EFI_SUCCESS;
   4359 
   4360   //
   4361   // Check the supported setting level.
   4362   //
   4363   if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
   4364     return EFI_UNSUPPORTED;
   4365   }
   4366 
   4367   if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
   4368     return EFI_UNSUPPORTED;
   4369   }
   4370 
   4371   if (SettingScope == FormLevel) {
   4372     //
   4373     // Prepare the AltCfg String for form.
   4374     //
   4375     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4376       ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);
   4377     }
   4378 
   4379     //
   4380     // Extract Form default
   4381     //
   4382     Link = GetFirstNode (&Form->StatementListHead);
   4383     while (!IsNull (&Form->StatementListHead, Link)) {
   4384       Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   4385       Link = GetNextNode (&Form->StatementListHead, Link);
   4386 
   4387       //
   4388       // If get default value only for this storage, check the storage first.
   4389       //
   4390       if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
   4391         continue;
   4392       }
   4393 
   4394       //
   4395       // If get default value only for no storage question, just skip the question which has storage.
   4396       //
   4397       if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
   4398         continue;
   4399       }
   4400 
   4401       //
   4402       // If Question is disabled, don't reset it to default
   4403       //
   4404       if (Question->Expression != NULL) {
   4405         if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
   4406           continue;
   4407         }
   4408       }
   4409 
   4410       if (RetrieveValueFirst) {
   4411         //
   4412         // Call the Retrieve call back to get the initial question value.
   4413         //
   4414         Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
   4415       }
   4416 
   4417       //
   4418       // If not request to get the initial value or get initial value fail, then get default value.
   4419       //
   4420       if (!RetrieveValueFirst || EFI_ERROR (Status)) {
   4421         Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
   4422         if (EFI_ERROR (Status)) {
   4423           continue;
   4424         }
   4425       }
   4426 
   4427       //
   4428       // Synchronize Buffer storage's Edit buffer
   4429       //
   4430       if ((Question->Storage != NULL) &&
   4431           (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
   4432         SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   4433       }
   4434     }
   4435 
   4436     //
   4437     // Clean the AltCfg String.
   4438     //
   4439     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4440       CleanAltCfgForForm(Form);
   4441     }
   4442   } else if (SettingScope == FormSetLevel) {
   4443     //
   4444     // Prepare the AltCfg String for formset.
   4445     //
   4446     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4447       ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);
   4448     }
   4449 
   4450     FormLink = GetFirstNode (&FormSet->FormListHead);
   4451     while (!IsNull (&FormSet->FormListHead, FormLink)) {
   4452       Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
   4453       ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
   4454       FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
   4455     }
   4456 
   4457     //
   4458     // Clean the AltCfg String.
   4459     //
   4460     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4461       CleanAltCfgForFormSet (FormSet);
   4462     }
   4463   } else if (SettingScope == SystemLevel) {
   4464     //
   4465     // Preload all Hii formset.
   4466     //
   4467     LoadAllHiiFormset();
   4468 
   4469     OldFormSet = mSystemLevelFormSet;
   4470 
   4471     //
   4472     // Set Default Value for each FormSet in the maintain list.
   4473     //
   4474     Link = GetFirstNode (&gBrowserFormSetList);
   4475     while (!IsNull (&gBrowserFormSetList, Link)) {
   4476       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   4477       Link = GetNextNode (&gBrowserFormSetList, Link);
   4478       if (!ValidateFormSet(LocalFormSet)) {
   4479         continue;
   4480       }
   4481 
   4482       mSystemLevelFormSet = LocalFormSet;
   4483 
   4484       ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
   4485     }
   4486 
   4487     mSystemLevelFormSet = OldFormSet;
   4488   }
   4489 
   4490   return EFI_SUCCESS;
   4491 }
   4492 
   4493 
   4494 /**
   4495   Validate whether this question's value has changed.
   4496 
   4497   @param  FormSet                FormSet data structure.
   4498   @param  Form                   Form data structure.
   4499   @param  Question               Question to be initialized.
   4500   @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.
   4501 
   4502   @retval TRUE                   Question's value has changed.
   4503   @retval FALSE                  Question's value has not changed
   4504 
   4505 **/
   4506 BOOLEAN
   4507 IsQuestionValueChanged (
   4508   IN FORM_BROWSER_FORMSET             *FormSet,
   4509   IN FORM_BROWSER_FORM                *Form,
   4510   IN OUT FORM_BROWSER_STATEMENT       *Question,
   4511   IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom
   4512   )
   4513 {
   4514   EFI_HII_VALUE    BackUpValue;
   4515   CHAR8            *BackUpBuffer;
   4516   EFI_HII_VALUE    BackUpValue2;
   4517   CHAR8            *BackUpBuffer2;
   4518   EFI_STATUS       Status;
   4519   BOOLEAN          ValueChanged;
   4520   UINTN            BufferWidth;
   4521 
   4522   //
   4523   // For quetion without storage, always mark it as data not changed.
   4524   //
   4525   if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
   4526     return FALSE;
   4527   }
   4528 
   4529   BackUpBuffer = NULL;
   4530   BackUpBuffer2 = NULL;
   4531   ValueChanged = FALSE;
   4532 
   4533   switch (Question->Operand) {
   4534     case EFI_IFR_ORDERED_LIST_OP:
   4535       BufferWidth  = Question->StorageWidth;
   4536       BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4537       ASSERT (BackUpBuffer != NULL);
   4538       break;
   4539 
   4540     case EFI_IFR_STRING_OP:
   4541     case EFI_IFR_PASSWORD_OP:
   4542       BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);
   4543       BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4544       ASSERT (BackUpBuffer != NULL);
   4545       break;
   4546 
   4547     default:
   4548       BufferWidth = 0;
   4549       break;
   4550   }
   4551   CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
   4552 
   4553   if (GetValueFrom == GetSetValueWithBothBuffer) {
   4554     Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   4555     ASSERT_EFI_ERROR(Status);
   4556 
   4557     switch (Question->Operand) {
   4558       case EFI_IFR_ORDERED_LIST_OP:
   4559         BufferWidth  = Question->StorageWidth;
   4560         BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4561         ASSERT (BackUpBuffer2 != NULL);
   4562         break;
   4563 
   4564       case EFI_IFR_STRING_OP:
   4565       case EFI_IFR_PASSWORD_OP:
   4566         BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);
   4567         BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4568         ASSERT (BackUpBuffer2 != NULL);
   4569         break;
   4570 
   4571       default:
   4572         BufferWidth = 0;
   4573         break;
   4574     }
   4575     CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
   4576 
   4577     Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
   4578     ASSERT_EFI_ERROR(Status);
   4579 
   4580     if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
   4581         CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {
   4582       ValueChanged = TRUE;
   4583     }
   4584   } else {
   4585     Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
   4586     ASSERT_EFI_ERROR(Status);
   4587 
   4588     if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
   4589         CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
   4590       ValueChanged = TRUE;
   4591     }
   4592   }
   4593 
   4594   CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
   4595   if (BackUpBuffer != NULL) {
   4596     CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
   4597     FreePool (BackUpBuffer);
   4598   }
   4599 
   4600   if (BackUpBuffer2 != NULL) {
   4601     FreePool (BackUpBuffer2);
   4602   }
   4603 
   4604   Question->ValueChanged = ValueChanged;
   4605 
   4606   return ValueChanged;
   4607 }
   4608 
   4609 /**
   4610   Initialize Question's Edit copy from Storage.
   4611 
   4612   @param  Selection              Selection contains the information about
   4613                                  the Selection, form and formset to be displayed.
   4614                                  Selection action may be updated in retrieve callback.
   4615                                  If Selection is NULL, only initialize Question value.
   4616   @param  FormSet                FormSet data structure.
   4617   @param  Form                   Form data structure.
   4618 
   4619   @retval EFI_SUCCESS            The function completed successfully.
   4620 
   4621 **/
   4622 EFI_STATUS
   4623 LoadFormConfig (
   4624   IN OUT UI_MENU_SELECTION    *Selection,
   4625   IN FORM_BROWSER_FORMSET     *FormSet,
   4626   IN FORM_BROWSER_FORM        *Form
   4627   )
   4628 {
   4629   EFI_STATUS                  Status;
   4630   LIST_ENTRY                  *Link;
   4631   FORM_BROWSER_STATEMENT      *Question;
   4632 
   4633   Link = GetFirstNode (&Form->StatementListHead);
   4634   while (!IsNull (&Form->StatementListHead, Link)) {
   4635     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   4636 
   4637     //
   4638     // Initialize local copy of Value for each Question
   4639     //
   4640     if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
   4641       Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
   4642     } else {
   4643       Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   4644     }
   4645     if (EFI_ERROR (Status)) {
   4646       return Status;
   4647     }
   4648 
   4649     if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
   4650       HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
   4651     }
   4652 
   4653     Link = GetNextNode (&Form->StatementListHead, Link);
   4654   }
   4655 
   4656   return EFI_SUCCESS;
   4657 }
   4658 
   4659 /**
   4660   Initialize Question's Edit copy from Storage for the whole Formset.
   4661 
   4662   @param  Selection              Selection contains the information about
   4663                                  the Selection, form and formset to be displayed.
   4664                                  Selection action may be updated in retrieve callback.
   4665                                  If Selection is NULL, only initialize Question value.
   4666   @param  FormSet                FormSet data structure.
   4667 
   4668   @retval EFI_SUCCESS            The function completed successfully.
   4669 
   4670 **/
   4671 EFI_STATUS
   4672 LoadFormSetConfig (
   4673   IN OUT UI_MENU_SELECTION    *Selection,
   4674   IN     FORM_BROWSER_FORMSET *FormSet
   4675   )
   4676 {
   4677   EFI_STATUS            Status;
   4678   LIST_ENTRY            *Link;
   4679   FORM_BROWSER_FORM     *Form;
   4680 
   4681   Link = GetFirstNode (&FormSet->FormListHead);
   4682   while (!IsNull (&FormSet->FormListHead, Link)) {
   4683     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   4684 
   4685     //
   4686     // Initialize local copy of Value for each Form
   4687     //
   4688     Status = LoadFormConfig (Selection, FormSet, Form);
   4689     if (EFI_ERROR (Status)) {
   4690       return Status;
   4691     }
   4692 
   4693     Link = GetNextNode (&FormSet->FormListHead, Link);
   4694   }
   4695 
   4696   //
   4697   // Finished question initialization.
   4698   //
   4699   FormSet->QuestionInited = TRUE;
   4700 
   4701   return EFI_SUCCESS;
   4702 }
   4703 
   4704 /**
   4705   Remove the Request element from the Config Request.
   4706 
   4707   @param  Storage                Pointer to the browser storage.
   4708   @param  RequestElement         The pointer to the Request element.
   4709 
   4710 **/
   4711 VOID
   4712 RemoveElement (
   4713   IN OUT BROWSER_STORAGE      *Storage,
   4714   IN     CHAR16               *RequestElement
   4715   )
   4716 {
   4717   CHAR16   *NewStr;
   4718   CHAR16   *DestStr;
   4719 
   4720   ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
   4721 
   4722   NewStr = StrStr (Storage->ConfigRequest, RequestElement);
   4723 
   4724   if (NewStr == NULL) {
   4725     return;
   4726   }
   4727 
   4728   //
   4729   // Remove this element from this ConfigRequest.
   4730   //
   4731   DestStr = NewStr;
   4732   NewStr += StrLen (RequestElement);
   4733   CopyMem (DestStr, NewStr, StrSize (NewStr));
   4734 
   4735   Storage->SpareStrLen += StrLen (RequestElement);
   4736 }
   4737 
   4738 /**
   4739   Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
   4740 
   4741   @param  Storage                Pointer to the formset storage.
   4742   @param  ConfigRequest          The pointer to the Request element.
   4743 
   4744 **/
   4745 VOID
   4746 RemoveConfigRequest (
   4747   FORMSET_STORAGE   *Storage,
   4748   CHAR16            *ConfigRequest
   4749   )
   4750 {
   4751   CHAR16       *RequestElement;
   4752   CHAR16       *NextRequestElement;
   4753   CHAR16       *SearchKey;
   4754 
   4755   //
   4756   // No request element in it, just return.
   4757   //
   4758   if (ConfigRequest == NULL) {
   4759     return;
   4760   }
   4761 
   4762   if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   4763     //
   4764     // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
   4765     //
   4766     SearchKey = L"&";
   4767   } else {
   4768     //
   4769     // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
   4770     //
   4771     SearchKey = L"&OFFSET";
   4772   }
   4773 
   4774   //
   4775   // Find SearchKey storage
   4776   //
   4777   if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   4778     RequestElement = StrStr (ConfigRequest, L"PATH");
   4779     ASSERT (RequestElement != NULL);
   4780     RequestElement = StrStr (RequestElement, SearchKey);
   4781   } else {
   4782     RequestElement = StrStr (ConfigRequest, SearchKey);
   4783   }
   4784 
   4785   while (RequestElement != NULL) {
   4786     //
   4787     // +1 to avoid find header itself.
   4788     //
   4789     NextRequestElement = StrStr (RequestElement + 1, SearchKey);
   4790 
   4791     //
   4792     // The last Request element in configRequest string.
   4793     //
   4794     if (NextRequestElement != NULL) {
   4795       //
   4796       // Replace "&" with '\0'.
   4797       //
   4798       *NextRequestElement = L'\0';
   4799     }
   4800 
   4801     RemoveElement (Storage->BrowserStorage, RequestElement);
   4802 
   4803     if (NextRequestElement != NULL) {
   4804       //
   4805       // Restore '&' with '\0' for later used.
   4806       //
   4807       *NextRequestElement = L'&';
   4808     }
   4809 
   4810     RequestElement = NextRequestElement;
   4811   }
   4812 
   4813   //
   4814   // If no request element remain, just remove the ConfigRequest string.
   4815   //
   4816   if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {
   4817     FreePool (Storage->BrowserStorage->ConfigRequest);
   4818     Storage->BrowserStorage->ConfigRequest = NULL;
   4819     Storage->BrowserStorage->SpareStrLen   = 0;
   4820   }
   4821 }
   4822 
   4823 /**
   4824   Base on the current formset info, clean the ConfigRequest string in browser storage.
   4825 
   4826   @param  FormSet                Pointer of the FormSet
   4827 
   4828 **/
   4829 VOID
   4830 CleanBrowserStorage (
   4831   IN OUT FORM_BROWSER_FORMSET  *FormSet
   4832   )
   4833 {
   4834   LIST_ENTRY            *Link;
   4835   FORMSET_STORAGE       *Storage;
   4836 
   4837   Link = GetFirstNode (&FormSet->StorageListHead);
   4838   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4839     Storage = FORMSET_STORAGE_FROM_LINK (Link);
   4840     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4841 
   4842     if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   4843       if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
   4844         continue;
   4845       }
   4846 
   4847       RemoveConfigRequest (Storage, Storage->ConfigRequest);
   4848     } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
   4849                Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   4850       if (Storage->BrowserStorage->ConfigRequest != NULL) {
   4851         FreePool (Storage->BrowserStorage->ConfigRequest);
   4852         Storage->BrowserStorage->ConfigRequest = NULL;
   4853       }
   4854       Storage->BrowserStorage->Initialized = FALSE;
   4855     }
   4856   }
   4857 }
   4858 
   4859 /**
   4860   Check whether current element in the ConfigReqeust string.
   4861 
   4862   @param  BrowserStorage                Storage which includes ConfigReqeust.
   4863   @param  RequestElement                New element need to check.
   4864 
   4865   @retval TRUE        The Element is in the ConfigReqeust string.
   4866   @retval FALSE       The Element not in the configReqeust String.
   4867 
   4868 **/
   4869 BOOLEAN
   4870 ElementValidation (
   4871   BROWSER_STORAGE   *BrowserStorage,
   4872   CHAR16            *RequestElement
   4873   )
   4874 {
   4875   return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
   4876 }
   4877 
   4878 /**
   4879   Append the Request element to the Config Request.
   4880 
   4881   @param  ConfigRequest          Current ConfigRequest info.
   4882   @param  SpareStrLen            Current remain free buffer for config reqeust.
   4883   @param  RequestElement         New Request element.
   4884 
   4885 **/
   4886 VOID
   4887 AppendConfigRequest (
   4888   IN OUT CHAR16               **ConfigRequest,
   4889   IN OUT UINTN                *SpareStrLen,
   4890   IN     CHAR16               *RequestElement
   4891   )
   4892 {
   4893   CHAR16   *NewStr;
   4894   UINTN    StringSize;
   4895   UINTN    StrLength;
   4896   UINTN    MaxLen;
   4897 
   4898   StrLength = StrLen (RequestElement);
   4899   StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
   4900   MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen;
   4901 
   4902   //
   4903   // Append <RequestElement> to <ConfigRequest>
   4904   //
   4905   if (StrLength > *SpareStrLen) {
   4906     //
   4907     // Old String buffer is not sufficient for RequestElement, allocate a new one
   4908     //
   4909     MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
   4910     NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   4911     ASSERT (NewStr != NULL);
   4912 
   4913     if (*ConfigRequest != NULL) {
   4914       CopyMem (NewStr, *ConfigRequest, StringSize);
   4915       FreePool (*ConfigRequest);
   4916     }
   4917     *ConfigRequest = NewStr;
   4918     *SpareStrLen   = CONFIG_REQUEST_STRING_INCREMENTAL;
   4919   }
   4920 
   4921   StrCatS (*ConfigRequest, MaxLen, RequestElement);
   4922   *SpareStrLen -= StrLength;
   4923 }
   4924 
   4925 /**
   4926   Adjust the config request info, remove the request elements which already in AllConfigRequest string.
   4927 
   4928   @param  Storage                Form set Storage.
   4929   @param  Request                The input request string.
   4930   @param  RespString             Whether the input is ConfigRequest or ConfigResp format.
   4931 
   4932   @retval TRUE                   Has element not covered by current used elements, need to continue to call ExtractConfig
   4933   @retval FALSE                  All elements covered by current used elements.
   4934 
   4935 **/
   4936 BOOLEAN
   4937 ConfigRequestAdjust (
   4938   IN  BROWSER_STORAGE         *Storage,
   4939   IN  CHAR16                  *Request,
   4940   IN  BOOLEAN                 RespString
   4941   )
   4942 {
   4943   CHAR16       *RequestElement;
   4944   CHAR16       *NextRequestElement;
   4945   CHAR16       *NextElementBakup;
   4946   CHAR16       *SearchKey;
   4947   CHAR16       *ValueKey;
   4948   BOOLEAN      RetVal;
   4949   CHAR16       *ConfigRequest;
   4950 
   4951   RetVal         = FALSE;
   4952   NextElementBakup = NULL;
   4953   ValueKey         = NULL;
   4954 
   4955   if (Request != NULL) {
   4956     ConfigRequest = Request;
   4957   } else {
   4958     ConfigRequest = Storage->ConfigRequest;
   4959   }
   4960 
   4961   if (Storage->ConfigRequest == NULL) {
   4962     Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
   4963     return TRUE;
   4964   }
   4965 
   4966   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   4967     //
   4968     // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
   4969     //
   4970     SearchKey = L"&";
   4971   } else {
   4972     //
   4973     // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
   4974     //
   4975     SearchKey = L"&OFFSET";
   4976     ValueKey  = L"&VALUE";
   4977   }
   4978 
   4979   //
   4980   // Find SearchKey storage
   4981   //
   4982   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   4983     RequestElement = StrStr (ConfigRequest, L"PATH");
   4984     ASSERT (RequestElement != NULL);
   4985     RequestElement = StrStr (RequestElement, SearchKey);
   4986   } else {
   4987     RequestElement = StrStr (ConfigRequest, SearchKey);
   4988   }
   4989 
   4990   while (RequestElement != NULL) {
   4991 
   4992     //
   4993     // +1 to avoid find header itself.
   4994     //
   4995     NextRequestElement = StrStr (RequestElement + 1, SearchKey);
   4996 
   4997     //
   4998     // The last Request element in configRequest string.
   4999     //
   5000     if (NextRequestElement != NULL) {
   5001       if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   5002         NextElementBakup = NextRequestElement;
   5003         NextRequestElement = StrStr (RequestElement, ValueKey);
   5004         ASSERT (NextRequestElement != NULL);
   5005       }
   5006       //
   5007       // Replace "&" with '\0'.
   5008       //
   5009       *NextRequestElement = L'\0';
   5010     } else {
   5011       if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   5012         NextElementBakup = NextRequestElement;
   5013         NextRequestElement = StrStr (RequestElement, ValueKey);
   5014         ASSERT (NextRequestElement != NULL);
   5015         //
   5016         // Replace "&" with '\0'.
   5017         //
   5018         *NextRequestElement = L'\0';
   5019       }
   5020     }
   5021 
   5022     if (!ElementValidation (Storage, RequestElement)) {
   5023       //
   5024       // Add this element to the Storage->BrowserStorage->AllRequestElement.
   5025       //
   5026       AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
   5027       RetVal = TRUE;
   5028     }
   5029 
   5030     if (NextRequestElement != NULL) {
   5031       //
   5032       // Restore '&' with '\0' for later used.
   5033       //
   5034       *NextRequestElement = L'&';
   5035     }
   5036 
   5037     if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   5038       RequestElement = NextElementBakup;
   5039     } else {
   5040       RequestElement = NextRequestElement;
   5041     }
   5042   }
   5043 
   5044   return RetVal;
   5045 }
   5046 
   5047 /**
   5048   Fill storage's edit copy with settings requested from Configuration Driver.
   5049 
   5050   @param  FormSet                FormSet data structure.
   5051   @param  Storage                Buffer Storage.
   5052 
   5053 **/
   5054 VOID
   5055 LoadStorage (
   5056   IN FORM_BROWSER_FORMSET    *FormSet,
   5057   IN FORMSET_STORAGE         *Storage
   5058   )
   5059 {
   5060   EFI_STATUS  Status;
   5061   EFI_STRING  Progress;
   5062   EFI_STRING  Result;
   5063   CHAR16      *StrPtr;
   5064   EFI_STRING  ConfigRequest;
   5065   UINTN       StrLen;
   5066 
   5067   ConfigRequest = NULL;
   5068 
   5069   switch (Storage->BrowserStorage->Type) {
   5070     case EFI_HII_VARSTORE_EFI_VARIABLE:
   5071       return;
   5072 
   5073     case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
   5074       if (Storage->BrowserStorage->ConfigRequest != NULL) {
   5075         ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
   5076         return;
   5077       }
   5078       break;
   5079 
   5080     case EFI_HII_VARSTORE_BUFFER:
   5081     case EFI_HII_VARSTORE_NAME_VALUE:
   5082       //
   5083       // Skip if there is no RequestElement.
   5084       //
   5085       if (Storage->ElementCount == 0) {
   5086         return;
   5087       }
   5088 
   5089       //
   5090       // Just update the ConfigRequest, if storage already initialized.
   5091       //
   5092       if (Storage->BrowserStorage->Initialized) {
   5093         ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
   5094         return;
   5095       }
   5096 
   5097       Storage->BrowserStorage->Initialized = TRUE;
   5098       break;
   5099 
   5100     default:
   5101       return;
   5102   }
   5103 
   5104   if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
   5105     //
   5106     // Create the config request string to get all fields for this storage.
   5107     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
   5108     // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
   5109     //
   5110     StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);
   5111     ConfigRequest = AllocateZeroPool (StrLen);
   5112     ASSERT (ConfigRequest != NULL);
   5113     UnicodeSPrint (
   5114                ConfigRequest,
   5115                StrLen,
   5116                L"%s&OFFSET=0&WIDTH=%04x",
   5117                Storage->ConfigHdr,
   5118                Storage->BrowserStorage->Size);
   5119   } else {
   5120     ConfigRequest = Storage->ConfigRequest;
   5121   }
   5122 
   5123   //
   5124   // Request current settings from Configuration Driver
   5125   //
   5126   Status = mHiiConfigRouting->ExtractConfig (
   5127                                     mHiiConfigRouting,
   5128                                     ConfigRequest,
   5129                                     &Progress,
   5130                                     &Result
   5131                                     );
   5132 
   5133   //
   5134   // If get value fail, extract default from IFR binary
   5135   //
   5136   if (EFI_ERROR (Status)) {
   5137     ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
   5138   } else {
   5139     //
   5140     // Convert Result from <ConfigAltResp> to <ConfigResp>
   5141     //
   5142     StrPtr = StrStr (Result, L"&GUID=");
   5143     if (StrPtr != NULL) {
   5144       *StrPtr = L'\0';
   5145     }
   5146 
   5147     Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
   5148     FreePool (Result);
   5149   }
   5150 
   5151   Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
   5152 
   5153   //
   5154   // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
   5155   //
   5156   SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);
   5157 
   5158   if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
   5159     if (ConfigRequest != NULL) {
   5160       FreePool (ConfigRequest);
   5161     }
   5162   }
   5163 }
   5164 
   5165 /**
   5166   Get Value changed status from old question.
   5167 
   5168   @param  NewFormSet                FormSet data structure.
   5169   @param  OldQuestion               Old question which has value changed.
   5170 
   5171 **/
   5172 VOID
   5173 SyncStatusForQuestion (
   5174   IN OUT FORM_BROWSER_FORMSET             *NewFormSet,
   5175   IN     FORM_BROWSER_STATEMENT           *OldQuestion
   5176   )
   5177 {
   5178   LIST_ENTRY                  *Link;
   5179   LIST_ENTRY                  *QuestionLink;
   5180   FORM_BROWSER_FORM           *Form;
   5181   FORM_BROWSER_STATEMENT      *Question;
   5182 
   5183   //
   5184   // For each form in one formset.
   5185   //
   5186   Link = GetFirstNode (&NewFormSet->FormListHead);
   5187   while (!IsNull (&NewFormSet->FormListHead, Link)) {
   5188     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   5189     Link = GetNextNode (&NewFormSet->FormListHead, Link);
   5190 
   5191     //
   5192     // for each question in one form.
   5193     //
   5194     QuestionLink = GetFirstNode (&Form->StatementListHead);
   5195     while (!IsNull (&Form->StatementListHead, QuestionLink)) {
   5196       Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
   5197       QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
   5198 
   5199       if (Question->QuestionId == OldQuestion->QuestionId) {
   5200         Question->ValueChanged = TRUE;
   5201         return;
   5202       }
   5203     }
   5204   }
   5205 }
   5206 
   5207 /**
   5208   Get Value changed status from old formset.
   5209 
   5210   @param  NewFormSet                FormSet data structure.
   5211   @param  OldFormSet                FormSet data structure.
   5212 
   5213 **/
   5214 VOID
   5215 SyncStatusForFormSet (
   5216   IN OUT FORM_BROWSER_FORMSET             *NewFormSet,
   5217   IN     FORM_BROWSER_FORMSET             *OldFormSet
   5218   )
   5219 {
   5220   LIST_ENTRY                  *Link;
   5221   LIST_ENTRY                  *QuestionLink;
   5222   FORM_BROWSER_FORM           *Form;
   5223   FORM_BROWSER_STATEMENT      *Question;
   5224 
   5225   //
   5226   // For each form in one formset.
   5227   //
   5228   Link = GetFirstNode (&OldFormSet->FormListHead);
   5229   while (!IsNull (&OldFormSet->FormListHead, Link)) {
   5230     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   5231     Link = GetNextNode (&OldFormSet->FormListHead, Link);
   5232 
   5233     //
   5234     // for each question in one form.
   5235     //
   5236     QuestionLink = GetFirstNode (&Form->StatementListHead);
   5237     while (!IsNull (&Form->StatementListHead, QuestionLink)) {
   5238       Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
   5239       QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
   5240 
   5241       if (!Question->ValueChanged) {
   5242         continue;
   5243       }
   5244 
   5245       //
   5246       // Find the same question in new formset and update the value changed flag.
   5247       //
   5248       SyncStatusForQuestion (NewFormSet, Question);
   5249     }
   5250   }
   5251 }
   5252 
   5253 /**
   5254   Get current setting of Questions.
   5255 
   5256   @param  FormSet                FormSet data structure.
   5257 
   5258 **/
   5259 VOID
   5260 InitializeCurrentSetting (
   5261   IN OUT FORM_BROWSER_FORMSET             *FormSet
   5262   )
   5263 {
   5264   LIST_ENTRY              *Link;
   5265   FORMSET_STORAGE         *Storage;
   5266   FORM_BROWSER_FORMSET    *OldFormSet;
   5267 
   5268   //
   5269   // Try to find pre FormSet in the maintain backup list.
   5270   // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
   5271   //
   5272   OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
   5273   if (OldFormSet != NULL) {
   5274     SyncStatusForFormSet (FormSet, OldFormSet);
   5275     RemoveEntryList (&OldFormSet->Link);
   5276     DestroyFormSet (OldFormSet);
   5277   }
   5278   InsertTailList (&gBrowserFormSetList, &FormSet->Link);
   5279 
   5280   //
   5281   // Extract default from IFR binary for no storage questions.
   5282   //
   5283   ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
   5284 
   5285   //
   5286   // Request current settings from Configuration Driver
   5287   //
   5288   Link = GetFirstNode (&FormSet->StorageListHead);
   5289   while (!IsNull (&FormSet->StorageListHead, Link)) {
   5290     Storage = FORMSET_STORAGE_FROM_LINK (Link);
   5291 
   5292     LoadStorage (FormSet, Storage);
   5293 
   5294     Link = GetNextNode (&FormSet->StorageListHead, Link);
   5295   }
   5296 }
   5297 
   5298 
   5299 /**
   5300   Fetch the Ifr binary data of a FormSet.
   5301 
   5302   @param  Handle                 PackageList Handle
   5303   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
   5304                                  specified (NULL or zero GUID), take the first
   5305                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
   5306                                  found in package list.
   5307                                  On output, GUID of the formset found(if not NULL).
   5308   @param  BinaryLength           The length of the FormSet IFR binary.
   5309   @param  BinaryData             The buffer designed to receive the FormSet.
   5310 
   5311   @retval EFI_SUCCESS            Buffer filled with the requested FormSet.
   5312                                  BufferLength was updated.
   5313   @retval EFI_INVALID_PARAMETER  The handle is unknown.
   5314   @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot
   5315                                  be found with the requested FormId.
   5316 
   5317 **/
   5318 EFI_STATUS
   5319 GetIfrBinaryData (
   5320   IN  EFI_HII_HANDLE   Handle,
   5321   IN OUT EFI_GUID      *FormSetGuid,
   5322   OUT UINTN            *BinaryLength,
   5323   OUT UINT8            **BinaryData
   5324   )
   5325 {
   5326   EFI_STATUS                   Status;
   5327   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
   5328   UINTN                        BufferSize;
   5329   UINT8                        *Package;
   5330   UINT8                        *OpCodeData;
   5331   UINT32                       Offset;
   5332   UINT32                       Offset2;
   5333   UINT32                       PackageListLength;
   5334   EFI_HII_PACKAGE_HEADER       PackageHeader;
   5335   UINT8                        Index;
   5336   UINT8                        NumberOfClassGuid;
   5337   BOOLEAN                      ClassGuidMatch;
   5338   EFI_GUID                     *ClassGuid;
   5339   EFI_GUID                     *ComparingGuid;
   5340 
   5341   OpCodeData = NULL;
   5342   Package = NULL;
   5343   ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
   5344 
   5345   //
   5346   // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
   5347   //
   5348   if (FormSetGuid == NULL) {
   5349     ComparingGuid = &gZeroGuid;
   5350   } else {
   5351     ComparingGuid = FormSetGuid;
   5352   }
   5353 
   5354   //
   5355   // Get HII PackageList
   5356   //
   5357   BufferSize = 0;
   5358   HiiPackageList = NULL;
   5359   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
   5360   if (Status == EFI_BUFFER_TOO_SMALL) {
   5361     HiiPackageList = AllocatePool (BufferSize);
   5362     ASSERT (HiiPackageList != NULL);
   5363 
   5364     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
   5365   }
   5366   if (EFI_ERROR (Status)) {
   5367     return Status;
   5368   }
   5369   ASSERT (HiiPackageList != NULL);
   5370 
   5371   //
   5372   // Get Form package from this HII package List
   5373   //
   5374   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
   5375   Offset2 = 0;
   5376   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
   5377 
   5378   ClassGuidMatch = FALSE;
   5379   while (Offset < PackageListLength) {
   5380     Package = ((UINT8 *) HiiPackageList) + Offset;
   5381     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
   5382 
   5383     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
   5384       //
   5385       // Search FormSet in this Form Package
   5386       //
   5387       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
   5388       while (Offset2 < PackageHeader.Length) {
   5389         OpCodeData = Package + Offset2;
   5390 
   5391         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
   5392           //
   5393           // Try to compare against formset GUID
   5394           //
   5395           if (CompareGuid (FormSetGuid, &gZeroGuid) ||
   5396               CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
   5397             break;
   5398           }
   5399 
   5400           if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
   5401             //
   5402             // Try to compare against formset class GUID
   5403             //
   5404             NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
   5405             ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
   5406             for (Index = 0; Index < NumberOfClassGuid; Index++) {
   5407               if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
   5408                 ClassGuidMatch = TRUE;
   5409                 break;
   5410               }
   5411             }
   5412             if (ClassGuidMatch) {
   5413               break;
   5414             }
   5415           } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
   5416             ClassGuidMatch = TRUE;
   5417             break;
   5418           }
   5419         }
   5420 
   5421         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
   5422       }
   5423 
   5424       if (Offset2 < PackageHeader.Length) {
   5425         //
   5426         // Target formset found
   5427         //
   5428         break;
   5429       }
   5430     }
   5431 
   5432     Offset += PackageHeader.Length;
   5433   }
   5434 
   5435   if (Offset >= PackageListLength) {
   5436     //
   5437     // Form package not found in this Package List
   5438     //
   5439     FreePool (HiiPackageList);
   5440     return EFI_NOT_FOUND;
   5441   }
   5442 
   5443   if (FormSetGuid != NULL) {
   5444     //
   5445     // Return the FormSet GUID
   5446     //
   5447     CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
   5448   }
   5449 
   5450   //
   5451   // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
   5452   // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
   5453   // of the Form Package.
   5454   //
   5455   *BinaryLength = PackageHeader.Length - Offset2;
   5456   *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
   5457 
   5458   FreePool (HiiPackageList);
   5459 
   5460   if (*BinaryData == NULL) {
   5461     return EFI_OUT_OF_RESOURCES;
   5462   }
   5463 
   5464   return EFI_SUCCESS;
   5465 }
   5466 
   5467 
   5468 /**
   5469   Initialize the internal data structure of a FormSet.
   5470 
   5471   @param  Handle                 PackageList Handle
   5472   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
   5473                                  specified (NULL or zero GUID), take the first
   5474                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
   5475                                  found in package list.
   5476                                  On output, GUID of the formset found(if not NULL).
   5477   @param  FormSet                FormSet data structure.
   5478 
   5479   @retval EFI_SUCCESS            The function completed successfully.
   5480   @retval EFI_NOT_FOUND          The specified FormSet could not be found.
   5481 
   5482 **/
   5483 EFI_STATUS
   5484 InitializeFormSet (
   5485   IN  EFI_HII_HANDLE                   Handle,
   5486   IN OUT EFI_GUID                      *FormSetGuid,
   5487   OUT FORM_BROWSER_FORMSET             *FormSet
   5488   )
   5489 {
   5490   EFI_STATUS                Status;
   5491   EFI_HANDLE                DriverHandle;
   5492 
   5493   Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
   5494   if (EFI_ERROR (Status)) {
   5495     return Status;
   5496   }
   5497 
   5498   FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
   5499   FormSet->HiiHandle = Handle;
   5500   CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
   5501   FormSet->QuestionInited = FALSE;
   5502 
   5503   //
   5504   // Retrieve ConfigAccess Protocol associated with this HiiPackageList
   5505   //
   5506   Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
   5507   if (EFI_ERROR (Status)) {
   5508     return Status;
   5509   }
   5510   FormSet->DriverHandle = DriverHandle;
   5511   Status = gBS->HandleProtocol (
   5512                   DriverHandle,
   5513                   &gEfiHiiConfigAccessProtocolGuid,
   5514                   (VOID **) &FormSet->ConfigAccess
   5515                   );
   5516   if (EFI_ERROR (Status)) {
   5517     //
   5518     // Configuration Driver don't attach ConfigAccess protocol to its HII package
   5519     // list, then there will be no configuration action required
   5520     //
   5521     FormSet->ConfigAccess = NULL;
   5522   }
   5523 
   5524   //
   5525   // Parse the IFR binary OpCodes
   5526   //
   5527   Status = ParseOpCodes (FormSet);
   5528 
   5529   return Status;
   5530 }
   5531 
   5532 
   5533 /**
   5534   Save globals used by previous call to SendForm(). SendForm() may be called from
   5535   HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
   5536   So, save globals of previous call to SendForm() and restore them upon exit.
   5537 
   5538 **/
   5539 VOID
   5540 SaveBrowserContext (
   5541   VOID
   5542   )
   5543 {
   5544   BROWSER_CONTEXT      *Context;
   5545   FORM_ENTRY_INFO      *MenuList;
   5546   FORM_BROWSER_FORMSET *FormSet;
   5547 
   5548   gBrowserContextCount++;
   5549   if (gBrowserContextCount == 1) {
   5550     //
   5551     // This is not reentry of SendForm(), no context to save
   5552     //
   5553     return;
   5554   }
   5555 
   5556   Context = AllocatePool (sizeof (BROWSER_CONTEXT));
   5557   ASSERT (Context != NULL);
   5558 
   5559   Context->Signature = BROWSER_CONTEXT_SIGNATURE;
   5560 
   5561   //
   5562   // Save FormBrowser context
   5563   //
   5564   Context->Selection            = gCurrentSelection;
   5565   Context->ResetRequired        = gResetRequired;
   5566   Context->FlagReconnect        = gFlagReconnect;
   5567   Context->CallbackReconnect    = gCallbackReconnect;
   5568   Context->ExitRequired         = gExitRequired;
   5569   Context->HiiHandle            = mCurrentHiiHandle;
   5570   Context->FormId               = mCurrentFormId;
   5571   CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
   5572   Context->SystemLevelFormSet   = mSystemLevelFormSet;
   5573   Context->CurFakeQestId        = mCurFakeQestId;
   5574   Context->HiiPackageListUpdated = mHiiPackageListUpdated;
   5575   Context->FinishRetrieveCall   = mFinishRetrieveCall;
   5576 
   5577   //
   5578   // Save the menu history data.
   5579   //
   5580   InitializeListHead(&Context->FormHistoryList);
   5581   while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
   5582     MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
   5583     RemoveEntryList (&MenuList->Link);
   5584 
   5585     InsertTailList(&Context->FormHistoryList, &MenuList->Link);
   5586   }
   5587 
   5588   //
   5589   // Save formset list.
   5590   //
   5591   InitializeListHead(&Context->FormSetList);
   5592   while (!IsListEmpty (&gBrowserFormSetList)) {
   5593     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink);
   5594     RemoveEntryList (&FormSet->Link);
   5595 
   5596     InsertTailList(&Context->FormSetList, &FormSet->Link);
   5597   }
   5598 
   5599   //
   5600   // Insert to FormBrowser context list
   5601   //
   5602   InsertHeadList (&gBrowserContextList, &Context->Link);
   5603 }
   5604 
   5605 
   5606 /**
   5607   Restore globals used by previous call to SendForm().
   5608 
   5609 **/
   5610 VOID
   5611 RestoreBrowserContext (
   5612   VOID
   5613   )
   5614 {
   5615   LIST_ENTRY       *Link;
   5616   BROWSER_CONTEXT  *Context;
   5617   FORM_ENTRY_INFO      *MenuList;
   5618   FORM_BROWSER_FORMSET *FormSet;
   5619 
   5620   ASSERT (gBrowserContextCount != 0);
   5621   gBrowserContextCount--;
   5622   if (gBrowserContextCount == 0) {
   5623     //
   5624     // This is not reentry of SendForm(), no context to restore
   5625     //
   5626     return;
   5627   }
   5628 
   5629   ASSERT (!IsListEmpty (&gBrowserContextList));
   5630 
   5631   Link = GetFirstNode (&gBrowserContextList);
   5632   Context = BROWSER_CONTEXT_FROM_LINK (Link);
   5633 
   5634   //
   5635   // Restore FormBrowser context
   5636   //
   5637   gCurrentSelection     = Context->Selection;
   5638   gResetRequired        = Context->ResetRequired;
   5639   gFlagReconnect        = Context->FlagReconnect;
   5640   gCallbackReconnect    = Context->CallbackReconnect;
   5641   gExitRequired         = Context->ExitRequired;
   5642   mCurrentHiiHandle     = Context->HiiHandle;
   5643   mCurrentFormId        = Context->FormId;
   5644   CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
   5645   mSystemLevelFormSet   = Context->SystemLevelFormSet;
   5646   mCurFakeQestId        = Context->CurFakeQestId;
   5647   mHiiPackageListUpdated = Context->HiiPackageListUpdated;
   5648   mFinishRetrieveCall   = Context->FinishRetrieveCall;
   5649 
   5650   //
   5651   // Restore the menu history data.
   5652   //
   5653   while (!IsListEmpty (&Context->FormHistoryList)) {
   5654     MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
   5655     RemoveEntryList (&MenuList->Link);
   5656 
   5657     InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
   5658   }
   5659 
   5660   //
   5661   // Restore the Formset data.
   5662   //
   5663   while (!IsListEmpty (&Context->FormSetList)) {
   5664     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink);
   5665     RemoveEntryList (&FormSet->Link);
   5666 
   5667     InsertTailList(&gBrowserFormSetList, &FormSet->Link);
   5668   }
   5669 
   5670   //
   5671   // Remove from FormBrowser context list
   5672   //
   5673   RemoveEntryList (&Context->Link);
   5674   gBS->FreePool (Context);
   5675 }
   5676 
   5677 /**
   5678   Find the matched FormSet context in the backup maintain list based on HiiHandle.
   5679 
   5680   @param Handle  The Hii Handle.
   5681 
   5682   @return the found FormSet context. If no found, NULL will return.
   5683 
   5684 **/
   5685 FORM_BROWSER_FORMSET *
   5686 GetFormSetFromHiiHandle (
   5687   EFI_HII_HANDLE Handle
   5688   )
   5689 {
   5690   LIST_ENTRY           *Link;
   5691   FORM_BROWSER_FORMSET *FormSet;
   5692 
   5693   Link = GetFirstNode (&gBrowserFormSetList);
   5694   while (!IsNull (&gBrowserFormSetList, Link)) {
   5695     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   5696     Link = GetNextNode (&gBrowserFormSetList, Link);
   5697     if (!ValidateFormSet(FormSet)) {
   5698       continue;
   5699     }
   5700     if (FormSet->HiiHandle == Handle) {
   5701       return FormSet;
   5702     }
   5703   }
   5704 
   5705   return NULL;
   5706 }
   5707 
   5708 /**
   5709   Check whether the input HII handle is the FormSet that is being used.
   5710 
   5711   @param Handle  The Hii Handle.
   5712 
   5713   @retval TRUE   HII handle is being used.
   5714   @retval FALSE  HII handle is not being used.
   5715 
   5716 **/
   5717 BOOLEAN
   5718 IsHiiHandleInBrowserContext (
   5719   EFI_HII_HANDLE Handle
   5720   )
   5721 {
   5722   LIST_ENTRY       *Link;
   5723   BROWSER_CONTEXT  *Context;
   5724 
   5725   //
   5726   // HiiHandle is Current FormSet.
   5727   //
   5728   if (mCurrentHiiHandle == Handle) {
   5729     return TRUE;
   5730   }
   5731 
   5732   //
   5733   // Check whether HiiHandle is in BrowserContext.
   5734   //
   5735   Link = GetFirstNode (&gBrowserContextList);
   5736   while (!IsNull (&gBrowserContextList, Link)) {
   5737     Context = BROWSER_CONTEXT_FROM_LINK (Link);
   5738     if (Context->HiiHandle == Handle) {
   5739       //
   5740       // HiiHandle is in BrowserContext
   5741       //
   5742       return TRUE;
   5743     }
   5744     Link = GetNextNode (&gBrowserContextList, Link);
   5745   }
   5746 
   5747   return FALSE;
   5748 }
   5749 
   5750 /**
   5751   Perform Password check.
   5752   Passwork may be encrypted by driver that requires the specific check.
   5753 
   5754   @param  Form             Form where Password Statement is in.
   5755   @param  Statement        Password statement
   5756   @param  PasswordString   Password string to be checked. It may be NULL.
   5757                            NULL means to restore password.
   5758                            "" string can be used to checked whether old password does exist.
   5759 
   5760   @return Status     Status of Password check.
   5761 **/
   5762 EFI_STATUS
   5763 EFIAPI
   5764 PasswordCheck (
   5765   IN FORM_DISPLAY_ENGINE_FORM      *Form,
   5766   IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
   5767   IN EFI_STRING                    PasswordString  OPTIONAL
   5768   )
   5769 {
   5770   EFI_STATUS                      Status;
   5771   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   5772   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   5773   EFI_IFR_TYPE_VALUE              IfrTypeValue;
   5774   FORM_BROWSER_STATEMENT          *Question;
   5775 
   5776   ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
   5777   Question = GetBrowserStatement(Statement);
   5778   ASSERT (Question != NULL);
   5779 
   5780   if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
   5781     if (ConfigAccess == NULL) {
   5782       return EFI_UNSUPPORTED;
   5783     }
   5784   } else {
   5785     if (PasswordString == NULL) {
   5786       return EFI_SUCCESS;
   5787     }
   5788 
   5789     //
   5790     // Check whether has preexisted password.
   5791     //
   5792     if (PasswordString[0] == 0) {
   5793       if (*((CHAR16 *) Question->BufferValue) == 0) {
   5794         return EFI_SUCCESS;
   5795       } else {
   5796         return EFI_NOT_READY;
   5797       }
   5798     }
   5799 
   5800     //
   5801     // Check whether the input password is same as preexisted password.
   5802     //
   5803     if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {
   5804       return EFI_SUCCESS;
   5805     } else {
   5806       return EFI_NOT_READY;
   5807     }
   5808   }
   5809 
   5810   //
   5811   // Prepare password string in HII database
   5812   //
   5813   if (PasswordString != NULL) {
   5814     IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
   5815   } else {
   5816     IfrTypeValue.string = 0;
   5817   }
   5818 
   5819   //
   5820   // Send password to Configuration Driver for validation
   5821   //
   5822   Status = ConfigAccess->Callback (
   5823                            ConfigAccess,
   5824                            EFI_BROWSER_ACTION_CHANGING,
   5825                            Question->QuestionId,
   5826                            Question->HiiValue.Type,
   5827                            &IfrTypeValue,
   5828                            &ActionRequest
   5829                            );
   5830 
   5831   //
   5832   // Remove password string from HII database
   5833   //
   5834   if (PasswordString != NULL) {
   5835     DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
   5836   }
   5837 
   5838   return Status;
   5839 }
   5840 
   5841 /**
   5842   Find the registered HotKey based on KeyData.
   5843 
   5844   @param[in] KeyData     A pointer to a buffer that describes the keystroke
   5845                          information for the hot key.
   5846 
   5847   @return The registered HotKey context. If no found, NULL will return.
   5848 **/
   5849 BROWSER_HOT_KEY *
   5850 GetHotKeyFromRegisterList (
   5851   IN EFI_INPUT_KEY *KeyData
   5852   )
   5853 {
   5854   LIST_ENTRY       *Link;
   5855   BROWSER_HOT_KEY  *HotKey;
   5856 
   5857   Link = GetFirstNode (&gBrowserHotKeyList);
   5858   while (!IsNull (&gBrowserHotKeyList, Link)) {
   5859     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
   5860     if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
   5861       return HotKey;
   5862     }
   5863     Link = GetNextNode (&gBrowserHotKeyList, Link);
   5864   }
   5865 
   5866   return NULL;
   5867 }
   5868 
   5869 /**
   5870   Configure what scope the hot key will impact.
   5871   All hot keys have the same scope. The mixed hot keys with the different level are not supported.
   5872   If no scope is set, the default scope will be FormSet level.
   5873   After all registered hot keys are removed, previous Scope can reset to another level.
   5874 
   5875   @param[in] Scope               Scope level to be set.
   5876 
   5877   @retval EFI_SUCCESS            Scope is set correctly.
   5878   @retval EFI_INVALID_PARAMETER  Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
   5879   @retval EFI_UNSPPORTED         Scope level is different from current one that the registered hot keys have.
   5880 
   5881 **/
   5882 EFI_STATUS
   5883 EFIAPI
   5884 SetScope (
   5885   IN BROWSER_SETTING_SCOPE Scope
   5886   )
   5887 {
   5888   if (Scope >= MaxLevel) {
   5889     return EFI_INVALID_PARAMETER;
   5890   }
   5891 
   5892   //
   5893   // When no hot key registered in system or on the first setting,
   5894   // Scope can be set.
   5895   //
   5896   if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
   5897     gBrowserSettingScope  = Scope;
   5898     mBrowserScopeFirstSet = FALSE;
   5899   } else if (Scope != gBrowserSettingScope) {
   5900     return EFI_UNSUPPORTED;
   5901   }
   5902 
   5903   return EFI_SUCCESS;
   5904 }
   5905 
   5906 /**
   5907   Register the hot key with its browser action, or unregistered the hot key.
   5908   Only support hot key that is not printable character (control key, function key, etc.).
   5909   If the action value is zero, the hot key will be unregistered if it has been registered.
   5910   If the same hot key has been registered, the new action and help string will override the previous ones.
   5911 
   5912   @param[in] KeyData     A pointer to a buffer that describes the keystroke
   5913                          information for the hot key. Its type is EFI_INPUT_KEY to
   5914                          be supported by all ConsoleIn devices.
   5915   @param[in] Action      Action value that describes what action will be trigged when the hot key is pressed.
   5916   @param[in] DefaultId   Specifies the type of defaults to retrieve, which is only for DEFAULT action.
   5917   @param[in] HelpString  Help string that describes the hot key information.
   5918                          Its value may be NULL for the unregistered hot key.
   5919 
   5920   @retval EFI_SUCCESS            Hot key is registered or unregistered.
   5921   @retval EFI_INVALID_PARAMETER  KeyData is NULL or HelpString is NULL on register.
   5922   @retval EFI_NOT_FOUND          KeyData is not found to be unregistered.
   5923   @retval EFI_UNSUPPORTED        Key represents a printable character. It is conflicted with Browser.
   5924   @retval EFI_ALREADY_STARTED    Key already been registered for one hot key.
   5925 **/
   5926 EFI_STATUS
   5927 EFIAPI
   5928 RegisterHotKey (
   5929   IN EFI_INPUT_KEY *KeyData,
   5930   IN UINT32        Action,
   5931   IN UINT16        DefaultId,
   5932   IN EFI_STRING    HelpString OPTIONAL
   5933   )
   5934 {
   5935   BROWSER_HOT_KEY  *HotKey;
   5936 
   5937   //
   5938   // Check input parameters.
   5939   //
   5940   if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
   5941      (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
   5942     return EFI_INVALID_PARAMETER;
   5943   }
   5944 
   5945   //
   5946   // Check whether the input KeyData is in BrowserHotKeyList.
   5947   //
   5948   HotKey = GetHotKeyFromRegisterList (KeyData);
   5949 
   5950   //
   5951   // Unregister HotKey
   5952   //
   5953   if (Action == BROWSER_ACTION_UNREGISTER) {
   5954     if (HotKey != NULL) {
   5955       //
   5956       // The registered HotKey is found.
   5957       // Remove it from List, and free its resource.
   5958       //
   5959       RemoveEntryList (&HotKey->Link);
   5960       FreePool (HotKey->KeyData);
   5961       FreePool (HotKey->HelpString);
   5962       return EFI_SUCCESS;
   5963     } else {
   5964       //
   5965       // The registered HotKey is not found.
   5966       //
   5967       return EFI_NOT_FOUND;
   5968     }
   5969   }
   5970 
   5971   if (HotKey != NULL) {
   5972     return EFI_ALREADY_STARTED;
   5973   }
   5974 
   5975   //
   5976   // Create new Key, and add it into List.
   5977   //
   5978   HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
   5979   ASSERT (HotKey != NULL);
   5980   HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
   5981   HotKey->KeyData   = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
   5982   InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
   5983 
   5984   //
   5985   // Fill HotKey information.
   5986   //
   5987   HotKey->Action     = Action;
   5988   HotKey->DefaultId  = DefaultId;
   5989   if (HotKey->HelpString != NULL) {
   5990     FreePool (HotKey->HelpString);
   5991   }
   5992   HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
   5993 
   5994   return EFI_SUCCESS;
   5995 }
   5996 
   5997 /**
   5998   Register Exit handler function.
   5999   When more than one handler function is registered, the latter one will override the previous one.
   6000   When NULL handler is specified, the previous Exit handler will be unregistered.
   6001 
   6002   @param[in] Handler      Pointer to handler function.
   6003 
   6004 **/
   6005 VOID
   6006 EFIAPI
   6007 RegiserExitHandler (
   6008   IN EXIT_HANDLER Handler
   6009   )
   6010 {
   6011   ExitHandlerFunction = Handler;
   6012   return;
   6013 }
   6014 
   6015 /**
   6016   Check whether the browser data has been modified.
   6017 
   6018   @retval TRUE        Browser data is modified.
   6019   @retval FALSE       No browser data is modified.
   6020 
   6021 **/
   6022 BOOLEAN
   6023 EFIAPI
   6024 IsBrowserDataModified (
   6025   VOID
   6026   )
   6027 {
   6028   LIST_ENTRY              *Link;
   6029   FORM_BROWSER_FORMSET    *FormSet;
   6030 
   6031   switch (gBrowserSettingScope) {
   6032     case FormLevel:
   6033       if (gCurrentSelection == NULL) {
   6034         return FALSE;
   6035       }
   6036       return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
   6037 
   6038     case FormSetLevel:
   6039       if (gCurrentSelection == NULL) {
   6040         return FALSE;
   6041       }
   6042       return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
   6043 
   6044     case SystemLevel:
   6045       Link = GetFirstNode (&gBrowserFormSetList);
   6046       while (!IsNull (&gBrowserFormSetList, Link)) {
   6047         FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   6048         if (!ValidateFormSet(FormSet)) {
   6049           continue;
   6050         }
   6051 
   6052         if (IsNvUpdateRequiredForFormSet (FormSet)) {
   6053           return TRUE;
   6054         }
   6055         Link = GetNextNode (&gBrowserFormSetList, Link);
   6056       }
   6057       return FALSE;
   6058 
   6059     default:
   6060       return FALSE;
   6061   }
   6062 }
   6063 
   6064 /**
   6065   Execute the action requested by the Action parameter.
   6066 
   6067   @param[in] Action     Execute the request action.
   6068   @param[in] DefaultId  The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
   6069 
   6070   @retval EFI_SUCCESS              Execute the request action succss.
   6071   @retval EFI_INVALID_PARAMETER    The input action value is invalid.
   6072 
   6073 **/
   6074 EFI_STATUS
   6075 EFIAPI
   6076 ExecuteAction (
   6077   IN UINT32        Action,
   6078   IN UINT16        DefaultId
   6079   )
   6080 {
   6081   EFI_STATUS              Status;
   6082   FORM_BROWSER_FORMSET    *FormSet;
   6083   FORM_BROWSER_FORM       *Form;
   6084 
   6085   if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
   6086     return EFI_NOT_READY;
   6087   }
   6088 
   6089   Status  = EFI_SUCCESS;
   6090   FormSet = NULL;
   6091   Form    = NULL;
   6092   if (gBrowserSettingScope < SystemLevel) {
   6093     FormSet = gCurrentSelection->FormSet;
   6094     Form    = gCurrentSelection->Form;
   6095   }
   6096 
   6097   //
   6098   // Executet the discard action.
   6099   //
   6100   if ((Action & BROWSER_ACTION_DISCARD) != 0) {
   6101     Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
   6102     if (EFI_ERROR (Status)) {
   6103       return Status;
   6104     }
   6105   }
   6106 
   6107   //
   6108   // Executet the difault action.
   6109   //
   6110   if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
   6111     Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
   6112     if (EFI_ERROR (Status)) {
   6113       return Status;
   6114     }
   6115     UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
   6116   }
   6117 
   6118   //
   6119   // Executet the submit action.
   6120   //
   6121   if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
   6122     Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
   6123     if (EFI_ERROR (Status)) {
   6124       return Status;
   6125     }
   6126   }
   6127 
   6128   //
   6129   // Executet the reset action.
   6130   //
   6131   if ((Action & BROWSER_ACTION_RESET) != 0) {
   6132     gResetRequired = TRUE;
   6133   }
   6134 
   6135   //
   6136   // Executet the exit action.
   6137   //
   6138   if ((Action & BROWSER_ACTION_EXIT) != 0) {
   6139     DiscardForm (FormSet, Form, gBrowserSettingScope);
   6140     if (gBrowserSettingScope == SystemLevel) {
   6141       if (ExitHandlerFunction != NULL) {
   6142         ExitHandlerFunction ();
   6143       }
   6144     }
   6145 
   6146     gExitRequired = TRUE;
   6147   }
   6148 
   6149   return Status;
   6150 }
   6151 
   6152 /**
   6153   Create reminder to let user to choose save or discard the changed browser data.
   6154   Caller can use it to actively check the changed browser data.
   6155 
   6156   @retval BROWSER_NO_CHANGES       No browser data is changed.
   6157   @retval BROWSER_SAVE_CHANGES     The changed browser data is saved.
   6158   @retval BROWSER_DISCARD_CHANGES  The changed browser data is discard.
   6159   @retval BROWSER_KEEP_CURRENT     Browser keep current changes.
   6160 
   6161 **/
   6162 UINT32
   6163 EFIAPI
   6164 SaveReminder (
   6165   VOID
   6166   )
   6167 {
   6168   LIST_ENTRY              *Link;
   6169   FORM_BROWSER_FORMSET    *FormSet;
   6170   BOOLEAN                 IsDataChanged;
   6171   UINT32                  DataSavedAction;
   6172   UINT32                  ConfirmRet;
   6173 
   6174   DataSavedAction  = BROWSER_NO_CHANGES;
   6175   IsDataChanged    = FALSE;
   6176   Link = GetFirstNode (&gBrowserFormSetList);
   6177   while (!IsNull (&gBrowserFormSetList, Link)) {
   6178     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   6179     Link = GetNextNode (&gBrowserFormSetList, Link);
   6180     if (!ValidateFormSet(FormSet)) {
   6181       continue;
   6182     }
   6183     if (IsNvUpdateRequiredForFormSet (FormSet)) {
   6184       IsDataChanged = TRUE;
   6185       break;
   6186     }
   6187   }
   6188 
   6189   //
   6190   // No data is changed. No save is required.
   6191   //
   6192   if (!IsDataChanged) {
   6193     return DataSavedAction;
   6194   }
   6195 
   6196   //
   6197   // If data is changed, prompt user to save or discard it.
   6198   //
   6199   do {
   6200     ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
   6201 
   6202     if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
   6203       SubmitForm (NULL, NULL, SystemLevel);
   6204       DataSavedAction = BROWSER_SAVE_CHANGES;
   6205       break;
   6206     } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
   6207       DiscardForm (NULL, NULL, SystemLevel);
   6208       DataSavedAction = BROWSER_DISCARD_CHANGES;
   6209       break;
   6210     } else if (ConfirmRet == BROWSER_ACTION_NONE) {
   6211       DataSavedAction = BROWSER_KEEP_CURRENT;
   6212       break;
   6213     }
   6214   } while (1);
   6215 
   6216   return DataSavedAction;
   6217 }
   6218 
   6219 /**
   6220   Check whether the Reset Required for the browser
   6221 
   6222   @retval TRUE      Browser required to reset after exit.
   6223   @retval FALSE     Browser not need to reset after exit.
   6224 
   6225 **/
   6226 BOOLEAN
   6227 EFIAPI
   6228 IsResetRequired (
   6229   VOID
   6230   )
   6231 {
   6232   return gResetRequired;
   6233 }
   6234 
   6235