Home | History | Annotate | Download | only in SetupBrowserDxe
      1 /** @file
      2 Entry and initialization module for the browser.
      3 
      4 Copyright (c) 2007 - 2016, 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 (IsZeroGuid (&MenuList->FormSetGuid)) {
    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                   &gEdkiiFormBrowserExProtocolGuid,
    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 
   1433   //
   1434   // Value points to a Unicode hexadecimal string, we need to convert the string to the value with CHAR16/UINT8...type.
   1435   // When generating the Value string, we follow this rule: 1 byte -> 2 Unicode characters (for string: 2 byte(CHAR16) ->4 Unicode characters).
   1436   // So the maximum value string length of a question is : Question->StorageWidth * 2.
   1437   // If the value string length > Question->StorageWidth * 2, only set the string length as Question->StorageWidth * 2, then convert.
   1438   //
   1439   if (LengthStr > (UINTN) Question->StorageWidth * 2) {
   1440     Length = (UINTN) Question->StorageWidth * 2;
   1441   } else {
   1442     Length = LengthStr;
   1443   }
   1444 
   1445   Status    = EFI_SUCCESS;
   1446   if (!IsBufferStorage && IsString) {
   1447     //
   1448     // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
   1449     // Add string tail char L'\0' into Length
   1450     //
   1451     DstBuf = (CHAR16 *) Dst;
   1452     ZeroMem (TemStr, sizeof (TemStr));
   1453     for (Index = 0; Index < Length; Index += 4) {
   1454       StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4);
   1455       DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
   1456     }
   1457     //
   1458     // Add tailing L'\0' character
   1459     //
   1460     DstBuf[Index/4] = L'\0';
   1461   } else {
   1462     ZeroMem (TemStr, sizeof (TemStr));
   1463     for (Index = 0; Index < Length; Index ++) {
   1464       TemStr[0] = Value[LengthStr - Index - 1];
   1465       DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
   1466       if ((Index & 1) == 0) {
   1467         Dst [Index/2] = DigitUint8;
   1468       } else {
   1469         Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
   1470       }
   1471     }
   1472   }
   1473 
   1474   *StringPtr = TempChar;
   1475 
   1476   return Status;
   1477 }
   1478 
   1479 /**
   1480   Get Question's current Value.
   1481 
   1482   @param  FormSet                FormSet data structure.
   1483   @param  Form                   Form data structure.
   1484   @param  Question               Question to be initialized.
   1485   @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.
   1486 
   1487   @retval EFI_SUCCESS            The function completed successfully.
   1488 
   1489 **/
   1490 EFI_STATUS
   1491 GetQuestionValue (
   1492   IN FORM_BROWSER_FORMSET             *FormSet,
   1493   IN FORM_BROWSER_FORM                *Form,
   1494   IN OUT FORM_BROWSER_STATEMENT       *Question,
   1495   IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom
   1496   )
   1497 {
   1498   EFI_STATUS          Status;
   1499   BOOLEAN             Enabled;
   1500   BOOLEAN             Pending;
   1501   UINT8               *Dst;
   1502   UINTN               StorageWidth;
   1503   EFI_TIME            EfiTime;
   1504   BROWSER_STORAGE     *Storage;
   1505   FORMSET_STORAGE     *FormsetStorage;
   1506   EFI_IFR_TYPE_VALUE  *QuestionValue;
   1507   CHAR16              *ConfigRequest;
   1508   CHAR16              *Progress;
   1509   CHAR16              *Result;
   1510   CHAR16              *Value;
   1511   UINTN               Length;
   1512   BOOLEAN             IsBufferStorage;
   1513   UINTN               MaxLen;
   1514 
   1515   Status = EFI_SUCCESS;
   1516   Value  = NULL;
   1517   Result = NULL;
   1518 
   1519   if (GetValueFrom >= GetSetValueWithMax) {
   1520     return EFI_INVALID_PARAMETER;
   1521   }
   1522 
   1523   //
   1524   // Question value is provided by an Expression, evaluate it
   1525   //
   1526   if (Question->ValueExpression != NULL) {
   1527     Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
   1528     if (!EFI_ERROR (Status)) {
   1529       if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
   1530         ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
   1531         if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
   1532           CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
   1533           Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
   1534         } else {
   1535           CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
   1536           Question->HiiValue.BufferLen = Question->StorageWidth;
   1537         }
   1538         FreePool (Question->ValueExpression->Result.Buffer);
   1539       }
   1540       Question->HiiValue.Type = Question->ValueExpression->Result.Type;
   1541       CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
   1542     }
   1543     return Status;
   1544   }
   1545 
   1546   //
   1547   // Get question value by read expression.
   1548   //
   1549   if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
   1550     Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
   1551     if (!EFI_ERROR (Status) &&
   1552       ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
   1553       //
   1554       // Only update question value to the valid result.
   1555       //
   1556       if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
   1557         ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
   1558         if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
   1559           CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
   1560           Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
   1561         } else {
   1562           CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
   1563           Question->HiiValue.BufferLen = Question->StorageWidth;
   1564         }
   1565         FreePool (Question->ReadExpression->Result.Buffer);
   1566       }
   1567       Question->HiiValue.Type = Question->ReadExpression->Result.Type;
   1568       CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
   1569       return EFI_SUCCESS;
   1570     }
   1571   }
   1572 
   1573   //
   1574   // Question value is provided by RTC
   1575   //
   1576   Storage = Question->Storage;
   1577   QuestionValue = &Question->HiiValue.Value;
   1578   if (Storage == NULL) {
   1579     //
   1580     // It's a Question without storage, or RTC date/time
   1581     //
   1582     if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
   1583       //
   1584       // Date and time define the same Flags bit
   1585       //
   1586       switch (Question->Flags & EFI_QF_DATE_STORAGE) {
   1587       case QF_DATE_STORAGE_TIME:
   1588         Status = gRT->GetTime (&EfiTime, NULL);
   1589         break;
   1590 
   1591       case QF_DATE_STORAGE_WAKEUP:
   1592         Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
   1593         break;
   1594 
   1595       case QF_DATE_STORAGE_NORMAL:
   1596       default:
   1597         //
   1598         // For date/time without storage
   1599         //
   1600         return EFI_SUCCESS;
   1601       }
   1602 
   1603       if (EFI_ERROR (Status)) {
   1604         if (Question->Operand == EFI_IFR_DATE_OP){
   1605           QuestionValue->date.Year  = 0xff;
   1606           QuestionValue->date.Month = 0xff;
   1607           QuestionValue->date.Day   = 0xff;
   1608         } else {
   1609           QuestionValue->time.Hour   = 0xff;
   1610           QuestionValue->time.Minute = 0xff;
   1611           QuestionValue->time.Second = 0xff;
   1612         }
   1613         return EFI_SUCCESS;
   1614       }
   1615 
   1616       if (Question->Operand == EFI_IFR_DATE_OP) {
   1617         QuestionValue->date.Year  = EfiTime.Year;
   1618         QuestionValue->date.Month = EfiTime.Month;
   1619         QuestionValue->date.Day   = EfiTime.Day;
   1620       } else {
   1621         QuestionValue->time.Hour   = EfiTime.Hour;
   1622         QuestionValue->time.Minute = EfiTime.Minute;
   1623         QuestionValue->time.Second = EfiTime.Second;
   1624       }
   1625     }
   1626 
   1627     return EFI_SUCCESS;
   1628   }
   1629 
   1630   //
   1631   // Question value is provided by EFI variable
   1632   //
   1633   StorageWidth = Question->StorageWidth;
   1634   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   1635     if (Question->BufferValue != NULL) {
   1636       Dst = Question->BufferValue;
   1637     } else {
   1638       Dst = (UINT8 *) QuestionValue;
   1639     }
   1640 
   1641     Status = gRT->GetVariable (
   1642                      Question->VariableName,
   1643                      &Storage->Guid,
   1644                      NULL,
   1645                      &StorageWidth,
   1646                      Dst
   1647                      );
   1648     //
   1649     // Always return success, even this EFI variable doesn't exist
   1650     //
   1651     return EFI_SUCCESS;
   1652   }
   1653 
   1654   //
   1655   // Question Value is provided by Buffer Storage or NameValue Storage
   1656   //
   1657   if (Question->BufferValue != NULL) {
   1658     //
   1659     // This Question is password or orderedlist
   1660     //
   1661     Dst = Question->BufferValue;
   1662   } else {
   1663     //
   1664     // Other type of Questions
   1665     //
   1666     Dst = (UINT8 *) &Question->HiiValue.Value;
   1667   }
   1668 
   1669   if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   1670       Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   1671     IsBufferStorage = TRUE;
   1672   } else {
   1673     IsBufferStorage = FALSE;
   1674   }
   1675   if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
   1676     if (IsBufferStorage) {
   1677       if (GetValueFrom == GetSetValueWithEditBuffer) {
   1678         //
   1679         // Copy from storage Edit buffer
   1680         //
   1681         CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
   1682       } else {
   1683         //
   1684         // Copy from storage Edit buffer
   1685         //
   1686         CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
   1687       }
   1688     } else {
   1689       Value = NULL;
   1690       Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
   1691       if (EFI_ERROR (Status)) {
   1692         return Status;
   1693       }
   1694 
   1695       ASSERT (Value != NULL);
   1696       Status = BufferToValue (Question, Value);
   1697       FreePool (Value);
   1698     }
   1699   } else {
   1700     FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
   1701     ASSERT (FormsetStorage != NULL);
   1702     //
   1703     // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
   1704     //                   <ConfigHdr> + "&" + <VariableName>
   1705     //
   1706     if (IsBufferStorage) {
   1707       Length = StrLen (FormsetStorage->ConfigHdr);
   1708       Length += StrLen (Question->BlockName);
   1709     } else {
   1710       Length = StrLen (FormsetStorage->ConfigHdr);
   1711       Length += StrLen (Question->VariableName) + 1;
   1712     }
   1713     // Allocate buffer include '\0'
   1714     MaxLen = Length + 1;
   1715     ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1716     ASSERT (ConfigRequest != NULL);
   1717 
   1718     StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr);
   1719     if (IsBufferStorage) {
   1720       StrCatS (ConfigRequest, MaxLen, Question->BlockName);
   1721     } else {
   1722       StrCatS (ConfigRequest, MaxLen, L"&");
   1723       StrCatS (ConfigRequest, MaxLen, Question->VariableName);
   1724     }
   1725 
   1726     //
   1727     // Request current settings from Configuration Driver
   1728     //
   1729     Status = mHiiConfigRouting->ExtractConfig (
   1730                                       mHiiConfigRouting,
   1731                                       ConfigRequest,
   1732                                       &Progress,
   1733                                       &Result
   1734                                       );
   1735     FreePool (ConfigRequest);
   1736     if (EFI_ERROR (Status)) {
   1737       return Status;
   1738     }
   1739 
   1740     //
   1741     // Skip <ConfigRequest>
   1742     //
   1743     if (IsBufferStorage) {
   1744       Value = StrStr (Result, L"&VALUE");
   1745       if (Value == NULL) {
   1746         FreePool (Result);
   1747         return EFI_NOT_FOUND;
   1748       }
   1749       //
   1750       // Skip "&VALUE"
   1751       //
   1752       Value = Value + 6;
   1753     } else {
   1754       Value = Result + Length;
   1755     }
   1756     if (*Value != '=') {
   1757       FreePool (Result);
   1758       return EFI_NOT_FOUND;
   1759     }
   1760     //
   1761     // Skip '=', point to value
   1762     //
   1763     Value = Value + 1;
   1764 
   1765     Status = BufferToValue (Question, Value);
   1766     if (EFI_ERROR (Status)) {
   1767       FreePool (Result);
   1768       return Status;
   1769     }
   1770 
   1771     //
   1772     // Synchronize Edit Buffer
   1773     //
   1774     if (IsBufferStorage) {
   1775       CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
   1776     } else {
   1777       SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
   1778     }
   1779 
   1780     if (Result != NULL) {
   1781       FreePool (Result);
   1782     }
   1783   }
   1784 
   1785   return Status;
   1786 }
   1787 
   1788 
   1789 /**
   1790   Save Question Value to edit copy(cached) or Storage(uncached).
   1791 
   1792   @param  FormSet                FormSet data structure.
   1793   @param  Form                   Form data structure.
   1794   @param  Question               Pointer to the Question.
   1795   @param  SetValueTo             Update the question value to editbuffer , buffer or hii driver.
   1796 
   1797   @retval EFI_SUCCESS            The function completed successfully.
   1798 
   1799 **/
   1800 EFI_STATUS
   1801 SetQuestionValue (
   1802   IN FORM_BROWSER_FORMSET             *FormSet,
   1803   IN FORM_BROWSER_FORM                *Form,
   1804   IN OUT FORM_BROWSER_STATEMENT       *Question,
   1805   IN GET_SET_QUESTION_VALUE_WITH      SetValueTo
   1806   )
   1807 {
   1808   EFI_STATUS          Status;
   1809   BOOLEAN             Enabled;
   1810   BOOLEAN             Pending;
   1811   UINT8               *Src;
   1812   EFI_TIME            EfiTime;
   1813   UINTN               BufferLen;
   1814   UINTN               StorageWidth;
   1815   BROWSER_STORAGE     *Storage;
   1816   FORMSET_STORAGE     *FormsetStorage;
   1817   EFI_IFR_TYPE_VALUE  *QuestionValue;
   1818   CHAR16              *ConfigResp;
   1819   CHAR16              *Progress;
   1820   CHAR16              *Value;
   1821   UINTN               Length;
   1822   BOOLEAN             IsBufferStorage;
   1823   BOOLEAN             IsString;
   1824   UINT8               *TemBuffer;
   1825   CHAR16              *TemName;
   1826   CHAR16              *TemString;
   1827   UINTN               Index;
   1828   NAME_VALUE_NODE     *Node;
   1829   UINTN               MaxLen;
   1830 
   1831   Status = EFI_SUCCESS;
   1832   Node   = NULL;
   1833 
   1834   if (SetValueTo >= GetSetValueWithMax) {
   1835     return EFI_INVALID_PARAMETER;
   1836   }
   1837 
   1838   //
   1839   // If Question value is provided by an Expression, then it is read only
   1840   //
   1841   if (Question->ValueExpression != NULL) {
   1842     return Status;
   1843   }
   1844 
   1845   //
   1846   // Before set question value, evaluate its write expression.
   1847   //
   1848   if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
   1849     Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
   1850     if (EFI_ERROR (Status)) {
   1851       return Status;
   1852     }
   1853   }
   1854 
   1855   //
   1856   // Question value is provided by RTC
   1857   //
   1858   Storage = Question->Storage;
   1859   QuestionValue = &Question->HiiValue.Value;
   1860   if (Storage == NULL) {
   1861     //
   1862     // It's a Question without storage, or RTC date/time
   1863     //
   1864     if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
   1865       //
   1866       // Date and time define the same Flags bit
   1867       //
   1868       switch (Question->Flags & EFI_QF_DATE_STORAGE) {
   1869       case QF_DATE_STORAGE_TIME:
   1870         Status = gRT->GetTime (&EfiTime, NULL);
   1871         break;
   1872 
   1873       case QF_DATE_STORAGE_WAKEUP:
   1874         Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
   1875         break;
   1876 
   1877       case QF_DATE_STORAGE_NORMAL:
   1878       default:
   1879         //
   1880         // For date/time without storage
   1881         //
   1882         return EFI_SUCCESS;
   1883       }
   1884 
   1885       if (EFI_ERROR (Status)) {
   1886         return Status;
   1887       }
   1888 
   1889       if (Question->Operand == EFI_IFR_DATE_OP) {
   1890         EfiTime.Year  = QuestionValue->date.Year;
   1891         EfiTime.Month = QuestionValue->date.Month;
   1892         EfiTime.Day   = QuestionValue->date.Day;
   1893       } else {
   1894         EfiTime.Hour   = QuestionValue->time.Hour;
   1895         EfiTime.Minute = QuestionValue->time.Minute;
   1896         EfiTime.Second = QuestionValue->time.Second;
   1897       }
   1898 
   1899       if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
   1900         Status = gRT->SetTime (&EfiTime);
   1901       } else {
   1902         Status = gRT->SetWakeupTime (TRUE, &EfiTime);
   1903       }
   1904     }
   1905 
   1906     return Status;
   1907   }
   1908 
   1909   //
   1910   // Question value is provided by EFI variable
   1911   //
   1912   StorageWidth = Question->StorageWidth;
   1913   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   1914     if (Question->BufferValue != NULL) {
   1915       Src = Question->BufferValue;
   1916     } else {
   1917       Src = (UINT8 *) QuestionValue;
   1918     }
   1919 
   1920     Status = gRT->SetVariable (
   1921                      Question->VariableName,
   1922                      &Storage->Guid,
   1923                      Storage->Attributes,
   1924                      StorageWidth,
   1925                      Src
   1926                      );
   1927     return Status;
   1928   }
   1929 
   1930   //
   1931   // Question Value is provided by Buffer Storage or NameValue Storage
   1932   //
   1933   if (Question->BufferValue != NULL) {
   1934     Src = Question->BufferValue;
   1935   } else {
   1936     Src = (UINT8 *) &Question->HiiValue.Value;
   1937   }
   1938 
   1939   if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   1940       Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   1941     IsBufferStorage = TRUE;
   1942   } else {
   1943     IsBufferStorage = FALSE;
   1944   }
   1945   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
   1946 
   1947   if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
   1948     if (IsBufferStorage) {
   1949       if (SetValueTo == GetSetValueWithEditBuffer) {
   1950         //
   1951         // Copy to storage edit buffer
   1952         //
   1953         CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
   1954       } else if (SetValueTo == GetSetValueWithBuffer) {
   1955         //
   1956         // Copy to storage edit buffer
   1957         //
   1958         CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
   1959       }
   1960     } else {
   1961       if (IsString) {
   1962         //
   1963         // Allocate enough string buffer.
   1964         //
   1965         Value = NULL;
   1966         BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
   1967         Value = AllocateZeroPool (BufferLen);
   1968         ASSERT (Value != NULL);
   1969         //
   1970         // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
   1971         //
   1972         TemName = (CHAR16 *) Src;
   1973         TemString = Value;
   1974         for (; *TemName != L'\0'; TemName++) {
   1975           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
   1976         }
   1977       } else {
   1978         BufferLen = StorageWidth * 2 + 1;
   1979         Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
   1980         ASSERT (Value != NULL);
   1981         //
   1982         // Convert Buffer to Hex String
   1983         //
   1984         TemBuffer = Src + StorageWidth - 1;
   1985         TemString = Value;
   1986         for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
   1987           TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
   1988         }
   1989       }
   1990 
   1991       Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
   1992       FreePool (Value);
   1993       if (EFI_ERROR (Status)) {
   1994         return Status;
   1995       }
   1996     }
   1997   } else if (SetValueTo == GetSetValueWithHiiDriver) {
   1998     //
   1999     // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
   2000     //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
   2001     //
   2002     if (IsBufferStorage) {
   2003       Length = StrLen (Question->BlockName) + 7;
   2004     } else {
   2005       Length = StrLen (Question->VariableName) + 2;
   2006     }
   2007     if (!IsBufferStorage && IsString) {
   2008       Length += (StrLen ((CHAR16 *) Src) * 4);
   2009     } else {
   2010       Length += (StorageWidth * 2);
   2011     }
   2012     FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
   2013     ASSERT (FormsetStorage != NULL);
   2014     MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1;
   2015     ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   2016     ASSERT (ConfigResp != NULL);
   2017 
   2018     StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr);
   2019     if (IsBufferStorage) {
   2020       StrCatS (ConfigResp, MaxLen, Question->BlockName);
   2021       StrCatS (ConfigResp, MaxLen, L"&VALUE=");
   2022     } else {
   2023       StrCatS (ConfigResp, MaxLen, L"&");
   2024       StrCatS (ConfigResp, MaxLen, Question->VariableName);
   2025       StrCatS (ConfigResp, MaxLen, L"=");
   2026     }
   2027 
   2028     Value = ConfigResp + StrLen (ConfigResp);
   2029 
   2030     if (!IsBufferStorage && IsString) {
   2031       //
   2032       // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
   2033       //
   2034       TemName = (CHAR16 *) Src;
   2035       TemString = Value;
   2036       for (; *TemName != L'\0'; TemName++) {
   2037         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
   2038       }
   2039     } else {
   2040       //
   2041       // Convert Buffer to Hex String
   2042       //
   2043       TemBuffer = Src + StorageWidth - 1;
   2044       TemString = Value;
   2045       for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
   2046         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
   2047       }
   2048     }
   2049 
   2050     //
   2051     // Convert to lower char.
   2052     //
   2053     for (TemString = Value; *Value != L'\0'; Value++) {
   2054       if (*Value >= L'A' && *Value <= L'Z') {
   2055         *Value = (CHAR16) (*Value - L'A' + L'a');
   2056       }
   2057     }
   2058 
   2059     //
   2060     // Submit Question Value to Configuration Driver
   2061     //
   2062     Status = mHiiConfigRouting->RouteConfig (
   2063                                       mHiiConfigRouting,
   2064                                       ConfigResp,
   2065                                       &Progress
   2066                                       );
   2067     if (EFI_ERROR (Status)) {
   2068       FreePool (ConfigResp);
   2069       return Status;
   2070     }
   2071     FreePool (ConfigResp);
   2072 
   2073     //
   2074     // Sync storage, from editbuffer to buffer.
   2075     //
   2076     CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
   2077   }
   2078 
   2079   return Status;
   2080 }
   2081 
   2082 
   2083 /**
   2084   Perform nosubmitif check for a Form.
   2085 
   2086   @param  FormSet                FormSet data structure.
   2087   @param  Form                   Form data structure.
   2088   @param  Question               The Question to be validated.
   2089   @param  Type                   Validation type: NoSubmit
   2090 
   2091   @retval EFI_SUCCESS            Form validation pass.
   2092   @retval other                  Form validation failed.
   2093 
   2094 **/
   2095 EFI_STATUS
   2096 ValidateQuestion (
   2097   IN  FORM_BROWSER_FORMSET            *FormSet,
   2098   IN  FORM_BROWSER_FORM               *Form,
   2099   IN  FORM_BROWSER_STATEMENT          *Question,
   2100   IN  UINTN                           Type
   2101   )
   2102 {
   2103   EFI_STATUS              Status;
   2104   LIST_ENTRY              *Link;
   2105   LIST_ENTRY              *ListHead;
   2106   FORM_EXPRESSION         *Expression;
   2107   UINT32                  BrowserStatus;
   2108   CHAR16                  *ErrorStr;
   2109 
   2110   BrowserStatus = BROWSER_SUCCESS;
   2111   ErrorStr      = NULL;
   2112 
   2113   switch (Type) {
   2114   case EFI_HII_EXPRESSION_INCONSISTENT_IF:
   2115     ListHead = &Question->InconsistentListHead;
   2116     break;
   2117 
   2118   case EFI_HII_EXPRESSION_WARNING_IF:
   2119     ListHead = &Question->WarningListHead;
   2120     break;
   2121 
   2122   case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
   2123     ListHead = &Question->NoSubmitListHead;
   2124     break;
   2125 
   2126   default:
   2127     ASSERT (FALSE);
   2128     return EFI_UNSUPPORTED;
   2129   }
   2130 
   2131   Link = GetFirstNode (ListHead);
   2132   while (!IsNull (ListHead, Link)) {
   2133     Expression = FORM_EXPRESSION_FROM_LINK (Link);
   2134 
   2135     //
   2136     // Evaluate the expression
   2137     //
   2138     Status = EvaluateExpression (FormSet, Form, Expression);
   2139     if (EFI_ERROR (Status)) {
   2140       return Status;
   2141     }
   2142 
   2143     if (IsTrue (&Expression->Result)) {
   2144       switch (Type) {
   2145       case EFI_HII_EXPRESSION_INCONSISTENT_IF:
   2146         BrowserStatus = BROWSER_INCONSISTENT_IF;
   2147         break;
   2148 
   2149       case EFI_HII_EXPRESSION_WARNING_IF:
   2150         BrowserStatus = BROWSER_WARNING_IF;
   2151         break;
   2152 
   2153       case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
   2154         BrowserStatus = BROWSER_NO_SUBMIT_IF;
   2155         //
   2156         // This code only used to compatible with old display engine,
   2157         // New display engine will not use this field.
   2158         //
   2159         if (Expression->Error != 0) {
   2160           ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);
   2161         }
   2162         break;
   2163 
   2164       default:
   2165         ASSERT (FALSE);
   2166         break;
   2167       }
   2168 
   2169       if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {
   2170         //
   2171         // If in system submit process and for no_submit_if check, not popup this error message.
   2172         // Will process this fail again later in not system submit process.
   2173         //
   2174         PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);
   2175       }
   2176 
   2177       if (ErrorStr != NULL) {
   2178         FreePool (ErrorStr);
   2179       }
   2180 
   2181       if (Type == EFI_HII_EXPRESSION_WARNING_IF) {
   2182         return EFI_SUCCESS;
   2183       } else {
   2184         return EFI_NOT_READY;
   2185       }
   2186     }
   2187 
   2188     Link = GetNextNode (ListHead, Link);
   2189   }
   2190 
   2191   return EFI_SUCCESS;
   2192 }
   2193 
   2194 /**
   2195   Perform question check.
   2196 
   2197   If one question has more than one check, process form high priority to low.
   2198   Only one error info will be popup.
   2199 
   2200   @param  FormSet                FormSet data structure.
   2201   @param  Form                   Form data structure.
   2202   @param  Question               The Question to be validated.
   2203 
   2204   @retval EFI_SUCCESS            Form validation pass.
   2205   @retval other                  Form validation failed.
   2206 
   2207 **/
   2208 EFI_STATUS
   2209 ValueChangedValidation (
   2210   IN  FORM_BROWSER_FORMSET            *FormSet,
   2211   IN  FORM_BROWSER_FORM               *Form,
   2212   IN  FORM_BROWSER_STATEMENT          *Question
   2213   )
   2214 {
   2215   EFI_STATUS   Status;
   2216 
   2217   Status = EFI_SUCCESS;
   2218 
   2219   //
   2220   // Do the inconsistentif check.
   2221   //
   2222   if (!IsListEmpty (&Question->InconsistentListHead)) {
   2223     Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
   2224     if (EFI_ERROR (Status)) {
   2225       return Status;
   2226     }
   2227   }
   2228 
   2229   //
   2230   // Do the warningif check.
   2231   //
   2232   if (!IsListEmpty (&Question->WarningListHead)) {
   2233     Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);
   2234   }
   2235 
   2236   return Status;
   2237 }
   2238 
   2239 /**
   2240   Perform NoSubmit check for each Form in FormSet.
   2241 
   2242   @param  FormSet                FormSet data structure.
   2243   @param  CurrentForm            Current input form data structure.
   2244   @param  Statement              The statement for this check.
   2245 
   2246   @retval EFI_SUCCESS            Form validation pass.
   2247   @retval other                  Form validation failed.
   2248 
   2249 **/
   2250 EFI_STATUS
   2251 NoSubmitCheck (
   2252   IN      FORM_BROWSER_FORMSET            *FormSet,
   2253   IN OUT  FORM_BROWSER_FORM               **CurrentForm,
   2254   OUT     FORM_BROWSER_STATEMENT          **Statement
   2255   )
   2256 {
   2257   EFI_STATUS              Status;
   2258   LIST_ENTRY              *Link;
   2259   FORM_BROWSER_STATEMENT  *Question;
   2260   FORM_BROWSER_FORM       *Form;
   2261   LIST_ENTRY              *LinkForm;
   2262 
   2263   LinkForm = GetFirstNode (&FormSet->FormListHead);
   2264   while (!IsNull (&FormSet->FormListHead, LinkForm)) {
   2265     Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
   2266     LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
   2267 
   2268     if (*CurrentForm != NULL && *CurrentForm != Form) {
   2269       continue;
   2270     }
   2271 
   2272     Link = GetFirstNode (&Form->StatementListHead);
   2273     while (!IsNull (&Form->StatementListHead, Link)) {
   2274       Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2275       Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
   2276       if (EFI_ERROR (Status)) {
   2277         if (*CurrentForm == NULL) {
   2278           *CurrentForm = Form;
   2279         }
   2280         if (Statement != NULL) {
   2281           *Statement = Question;
   2282         }
   2283         return Status;
   2284       }
   2285 
   2286       Link = GetNextNode (&Form->StatementListHead, Link);
   2287     }
   2288   }
   2289 
   2290   return EFI_SUCCESS;
   2291 }
   2292 
   2293 /**
   2294   Fill storage's edit copy with settings requested from Configuration Driver.
   2295 
   2296   @param  Storage                The storage which need to sync.
   2297   @param  ConfigRequest          The config request string which used to sync storage.
   2298   @param  SyncOrRestore          Sync the buffer to editbuffer or Restore  the
   2299                                  editbuffer to buffer
   2300                                  if TRUE, copy the editbuffer to the buffer.
   2301                                  if FALSE, copy the buffer to the editbuffer.
   2302 
   2303   @retval EFI_SUCCESS            The function completed successfully.
   2304 
   2305 **/
   2306 EFI_STATUS
   2307 SynchronizeStorage (
   2308   OUT BROWSER_STORAGE             *Storage,
   2309   IN  CHAR16                      *ConfigRequest,
   2310   IN  BOOLEAN                     SyncOrRestore
   2311   )
   2312 {
   2313   EFI_STATUS              Status;
   2314   EFI_STRING              Progress;
   2315   EFI_STRING              Result;
   2316   UINTN                   BufferSize;
   2317   LIST_ENTRY              *Link;
   2318   NAME_VALUE_NODE         *Node;
   2319   UINT8                   *Src;
   2320   UINT8                   *Dst;
   2321 
   2322   Status = EFI_SUCCESS;
   2323   Result = NULL;
   2324 
   2325   if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
   2326       (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   2327     BufferSize = Storage->Size;
   2328 
   2329     if (SyncOrRestore) {
   2330       Src = Storage->EditBuffer;
   2331       Dst = Storage->Buffer;
   2332     } else {
   2333       Src = Storage->Buffer;
   2334       Dst = Storage->EditBuffer;
   2335     }
   2336 
   2337     if (ConfigRequest != NULL) {
   2338       Status = mHiiConfigRouting->BlockToConfig(
   2339                                     mHiiConfigRouting,
   2340                                     ConfigRequest,
   2341                                     Src,
   2342                                     BufferSize,
   2343                                     &Result,
   2344                                     &Progress
   2345                                     );
   2346       if (EFI_ERROR (Status)) {
   2347         return Status;
   2348       }
   2349 
   2350       Status = mHiiConfigRouting->ConfigToBlock (
   2351                                     mHiiConfigRouting,
   2352                                     Result,
   2353                                     Dst,
   2354                                     &BufferSize,
   2355                                     &Progress
   2356                                     );
   2357       if (Result != NULL) {
   2358         FreePool (Result);
   2359       }
   2360     } else {
   2361       CopyMem (Dst, Src, BufferSize);
   2362     }
   2363   } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2364     Link = GetFirstNode (&Storage->NameValueListHead);
   2365     while (!IsNull (&Storage->NameValueListHead, Link)) {
   2366       Node = NAME_VALUE_NODE_FROM_LINK (Link);
   2367 
   2368       if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
   2369           (ConfigRequest == NULL)) {
   2370         if (SyncOrRestore) {
   2371           NewStringCpy (&Node->Value, Node->EditValue);
   2372         } else {
   2373           NewStringCpy (&Node->EditValue, Node->Value);
   2374         }
   2375       }
   2376 
   2377       Link = GetNextNode (&Storage->NameValueListHead, Link);
   2378     }
   2379   }
   2380 
   2381   return Status;
   2382 }
   2383 
   2384 /**
   2385   When discard the question value, call the callback function with Changed type
   2386   to inform the hii driver.
   2387 
   2388   @param  FormSet                FormSet data structure.
   2389   @param  Form                   Form data structure.
   2390 
   2391 **/
   2392 VOID
   2393 SendDiscardInfoToDriver (
   2394   IN FORM_BROWSER_FORMSET             *FormSet,
   2395   IN FORM_BROWSER_FORM                *Form
   2396   )
   2397 {
   2398   LIST_ENTRY                  *Link;
   2399   FORM_BROWSER_STATEMENT      *Question;
   2400   EFI_IFR_TYPE_VALUE          *TypeValue;
   2401   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
   2402 
   2403   if (FormSet->ConfigAccess == NULL) {
   2404     return;
   2405   }
   2406 
   2407   Link = GetFirstNode (&Form->StatementListHead);
   2408   while (!IsNull (&Form->StatementListHead, Link)) {
   2409     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2410     Link = GetNextNode (&Form->StatementListHead, Link);
   2411 
   2412     if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   2413       continue;
   2414     }
   2415 
   2416     if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
   2417       continue;
   2418     }
   2419 
   2420     if (Question->Operand == EFI_IFR_PASSWORD_OP) {
   2421       continue;
   2422     }
   2423 
   2424     if (!Question->ValueChanged) {
   2425       continue;
   2426     }
   2427 
   2428     //
   2429     // Restore the question value before call the CHANGED callback type.
   2430     //
   2431     GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   2432 
   2433     if (Question->Operand == EFI_IFR_STRING_OP){
   2434       HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
   2435     }
   2436 
   2437     if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
   2438       TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
   2439     } else {
   2440       TypeValue = &Question->HiiValue.Value;
   2441     }
   2442 
   2443     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2444     FormSet->ConfigAccess->Callback (
   2445                              FormSet->ConfigAccess,
   2446                              EFI_BROWSER_ACTION_CHANGED,
   2447                              Question->QuestionId,
   2448                              Question->HiiValue.Type,
   2449                              TypeValue,
   2450                              &ActionRequest
   2451                              );
   2452   }
   2453 }
   2454 
   2455 /**
   2456   When submit the question value, call the callback function with Submitted type
   2457   to inform the hii driver.
   2458 
   2459   @param  FormSet                FormSet data structure.
   2460   @param  Form                   Form data structure.
   2461 
   2462 **/
   2463 VOID
   2464 SubmitCallbackForForm (
   2465   IN FORM_BROWSER_FORMSET             *FormSet,
   2466   IN FORM_BROWSER_FORM                *Form
   2467   )
   2468 {
   2469   LIST_ENTRY                  *Link;
   2470   FORM_BROWSER_STATEMENT      *Question;
   2471   EFI_IFR_TYPE_VALUE          *TypeValue;
   2472   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
   2473 
   2474   if (FormSet->ConfigAccess == NULL) {
   2475     return;
   2476   }
   2477 
   2478   Link = GetFirstNode (&Form->StatementListHead);
   2479   while (!IsNull (&Form->StatementListHead, Link)) {
   2480     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2481     Link = GetNextNode (&Form->StatementListHead, Link);
   2482 
   2483     if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   2484       continue;
   2485     }
   2486 
   2487     if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
   2488        continue;
   2489     }
   2490 
   2491     if (Question->Operand == EFI_IFR_PASSWORD_OP) {
   2492        continue;
   2493     }
   2494 
   2495     if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
   2496       TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
   2497     } else {
   2498       TypeValue = &Question->HiiValue.Value;
   2499     }
   2500 
   2501     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2502     FormSet->ConfigAccess->Callback (
   2503                              FormSet->ConfigAccess,
   2504                              EFI_BROWSER_ACTION_SUBMITTED,
   2505                              Question->QuestionId,
   2506                              Question->HiiValue.Type,
   2507                              TypeValue,
   2508                              &ActionRequest
   2509                              );
   2510   }
   2511 }
   2512 
   2513 /**
   2514   When value set Success, call the submit callback function.
   2515 
   2516   @param  FormSet                FormSet data structure.
   2517   @param  Form                   Form data structure.
   2518 
   2519 **/
   2520 VOID
   2521 SubmitCallback (
   2522   IN FORM_BROWSER_FORMSET             *FormSet,
   2523   IN FORM_BROWSER_FORM                *Form
   2524   )
   2525 {
   2526   FORM_BROWSER_FORM       *CurrentForm;
   2527   LIST_ENTRY              *Link;
   2528 
   2529   if (Form != NULL) {
   2530     SubmitCallbackForForm(FormSet, Form);
   2531     return;
   2532   }
   2533 
   2534   Link = GetFirstNode (&FormSet->FormListHead);
   2535   while (!IsNull (&FormSet->FormListHead, Link)) {
   2536     CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
   2537     Link = GetNextNode (&FormSet->FormListHead, Link);
   2538 
   2539     SubmitCallbackForForm(FormSet, CurrentForm);
   2540   }
   2541 }
   2542 
   2543 /**
   2544   Validate the HiiHandle.
   2545 
   2546   @param  HiiHandle              The input HiiHandle which need to validate.
   2547 
   2548   @retval TRUE                   The handle is validate.
   2549   @retval FALSE                  The handle is invalidate.
   2550 
   2551 **/
   2552 BOOLEAN
   2553 ValidateHiiHandle (
   2554   EFI_HII_HANDLE          HiiHandle
   2555   )
   2556 {
   2557   EFI_HII_HANDLE          *HiiHandles;
   2558   UINTN                   Index;
   2559   BOOLEAN                 Find;
   2560 
   2561   if (HiiHandle == NULL) {
   2562     return FALSE;
   2563   }
   2564 
   2565   Find = FALSE;
   2566 
   2567   HiiHandles = HiiGetHiiHandles (NULL);
   2568   ASSERT (HiiHandles != NULL);
   2569 
   2570   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
   2571     if (HiiHandles[Index] == HiiHandle) {
   2572       Find = TRUE;
   2573       break;
   2574     }
   2575   }
   2576 
   2577   FreePool (HiiHandles);
   2578 
   2579   return Find;
   2580 }
   2581 
   2582 /**
   2583   Validate the FormSet. If the formset is not validate, remove it from the list.
   2584 
   2585   @param  FormSet                The input FormSet which need to validate.
   2586 
   2587   @retval TRUE                   The handle is validate.
   2588   @retval FALSE                  The handle is invalidate.
   2589 
   2590 **/
   2591 BOOLEAN
   2592 ValidateFormSet (
   2593   FORM_BROWSER_FORMSET    *FormSet
   2594   )
   2595 {
   2596   BOOLEAN  Find;
   2597 
   2598   ASSERT (FormSet != NULL);
   2599 
   2600   Find = ValidateHiiHandle(FormSet->HiiHandle);
   2601   //
   2602   // Should not remove the formset which is being used.
   2603   //
   2604   if (!Find && (FormSet != gCurrentSelection->FormSet)) {
   2605     CleanBrowserStorage(FormSet);
   2606     RemoveEntryList (&FormSet->Link);
   2607     DestroyFormSet (FormSet);
   2608   }
   2609 
   2610   return Find;
   2611 }
   2612 /**
   2613   Check whether need to enable the reset flag in form level.
   2614   Also clean all ValueChanged flag in question.
   2615 
   2616   @param  SetFlag                Whether need to set the Reset Flag.
   2617   @param  FormSet                FormSet data structure.
   2618   @param  Form                   Form data structure.
   2619 
   2620 **/
   2621 VOID
   2622 UpdateFlagForForm (
   2623   IN BOOLEAN                          SetFlag,
   2624   IN FORM_BROWSER_FORMSET             *FormSet,
   2625   IN FORM_BROWSER_FORM                *Form
   2626   )
   2627 {
   2628   LIST_ENTRY              *Link;
   2629   FORM_BROWSER_STATEMENT  *Question;
   2630   BOOLEAN                 OldValue;
   2631 
   2632   Link = GetFirstNode (&Form->StatementListHead);
   2633   while (!IsNull (&Form->StatementListHead, Link)) {
   2634     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   2635     Link = GetNextNode (&Form->StatementListHead, Link);
   2636 
   2637     if (!Question->ValueChanged) {
   2638       continue;
   2639     }
   2640 
   2641     OldValue = Question->ValueChanged;
   2642 
   2643     //
   2644     // Compare the buffer and editbuffer data to see whether the data has been saved.
   2645     //
   2646     Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);
   2647 
   2648     //
   2649     // Only the changed data has been saved, then need to set the reset flag.
   2650     //
   2651     if (SetFlag && OldValue && !Question->ValueChanged) {
   2652       if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
   2653         gResetRequired = TRUE;
   2654       }
   2655 
   2656       if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
   2657         gFlagReconnect = TRUE;
   2658       }
   2659     }
   2660   }
   2661 }
   2662 
   2663 /**
   2664   Check whether need to enable the reset flag.
   2665   Also clean ValueChanged flag for all statements.
   2666 
   2667   Form level or formset level, only one.
   2668 
   2669   @param  SetFlag                Whether need to set the Reset Flag.
   2670   @param  FormSet                FormSet data structure.
   2671   @param  Form                   Form data structure.
   2672 
   2673 **/
   2674 VOID
   2675 ValueChangeResetFlagUpdate (
   2676   IN BOOLEAN                          SetFlag,
   2677   IN FORM_BROWSER_FORMSET             *FormSet,
   2678   IN FORM_BROWSER_FORM                *Form
   2679   )
   2680 {
   2681   FORM_BROWSER_FORM       *CurrentForm;
   2682   LIST_ENTRY              *Link;
   2683 
   2684   if (Form != NULL) {
   2685     UpdateFlagForForm(SetFlag, FormSet, Form);
   2686     return;
   2687   }
   2688 
   2689   Link = GetFirstNode (&FormSet->FormListHead);
   2690   while (!IsNull (&FormSet->FormListHead, Link)) {
   2691     CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
   2692     Link = GetNextNode (&FormSet->FormListHead, Link);
   2693 
   2694     UpdateFlagForForm(SetFlag, FormSet, CurrentForm);
   2695   }
   2696 }
   2697 
   2698 /**
   2699   Base on the return Progress string to find the form.
   2700 
   2701   Base on the first return Offset/Width (Name) string to find the form
   2702   which keep this string.
   2703 
   2704   @param  FormSet                FormSet data structure.
   2705   @param  Storage                Storage which has this Progress string.
   2706   @param  Progress               The Progress string which has the first fail string.
   2707   @param  RetForm                The return form for this progress string.
   2708   @param  RetQuestion            The return question for the error progress string.
   2709 
   2710   @retval TRUE                   Find the error form and statement for this error progress string.
   2711   @retval FALSE                  Not find the error form.
   2712 
   2713 **/
   2714 BOOLEAN
   2715 FindQuestionFromProgress (
   2716   IN FORM_BROWSER_FORMSET             *FormSet,
   2717   IN BROWSER_STORAGE                  *Storage,
   2718   IN EFI_STRING                       Progress,
   2719   OUT FORM_BROWSER_FORM               **RetForm,
   2720   OUT FORM_BROWSER_STATEMENT          **RetQuestion
   2721   )
   2722 {
   2723   LIST_ENTRY                   *Link;
   2724   LIST_ENTRY                   *LinkStorage;
   2725   LIST_ENTRY                   *LinkStatement;
   2726   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   2727   FORM_BROWSER_FORM            *Form;
   2728   EFI_STRING                   EndStr;
   2729   FORM_BROWSER_STATEMENT       *Statement;
   2730 
   2731   ASSERT ((*Progress == '&') || (*Progress == 'G'));
   2732 
   2733   ConfigInfo   = NULL;
   2734   *RetForm     = NULL;
   2735   *RetQuestion = NULL;
   2736 
   2737   //
   2738   // Skip the first "&" or the ConfigHdr part.
   2739   //
   2740   if (*Progress == '&') {
   2741     Progress++;
   2742   } else {
   2743     //
   2744     // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
   2745     //
   2746     if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2747       //
   2748       // For Name/Value type, Skip the ConfigHdr part.
   2749       //
   2750       EndStr = StrStr (Progress, L"PATH=");
   2751       ASSERT (EndStr != NULL);
   2752       while (*EndStr != '&') {
   2753         EndStr++;
   2754       }
   2755 
   2756       *EndStr = '\0';
   2757     } else {
   2758       //
   2759       // For Buffer type, Skip the ConfigHdr part.
   2760       //
   2761       EndStr = StrStr (Progress, L"&OFFSET=");
   2762       ASSERT (EndStr != NULL);
   2763       *EndStr = '\0';
   2764     }
   2765 
   2766     Progress = EndStr + 1;
   2767   }
   2768 
   2769   //
   2770   // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
   2771   //
   2772   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2773     //
   2774     // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
   2775     // here, just keep the "Fred" string.
   2776     //
   2777     EndStr = StrStr (Progress, L"=");
   2778     ASSERT (EndStr != NULL);
   2779     *EndStr = '\0';
   2780   } else {
   2781     //
   2782     // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
   2783     // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
   2784     //
   2785     EndStr = StrStr (Progress, L"&VALUE=");
   2786     ASSERT (EndStr != NULL);
   2787     *EndStr = '\0';
   2788   }
   2789 
   2790   //
   2791   // Search in the form list.
   2792   //
   2793   Link = GetFirstNode (&FormSet->FormListHead);
   2794   while (!IsNull (&FormSet->FormListHead, Link)) {
   2795     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   2796     Link = GetNextNode (&FormSet->FormListHead, Link);
   2797 
   2798     //
   2799     // Search in the ConfigReqeust list in this form.
   2800     //
   2801     LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
   2802     while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
   2803       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
   2804       LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
   2805 
   2806       if (Storage != ConfigInfo->Storage) {
   2807         continue;
   2808       }
   2809 
   2810       if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
   2811         //
   2812         // Find the OffsetWidth string in this form.
   2813         //
   2814         *RetForm = Form;
   2815         break;
   2816       }
   2817     }
   2818 
   2819     if (*RetForm != NULL) {
   2820       LinkStatement = GetFirstNode (&Form->StatementListHead);
   2821       while (!IsNull (&Form->StatementListHead, LinkStatement)) {
   2822         Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
   2823         LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
   2824 
   2825         if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {
   2826           *RetQuestion = Statement;
   2827           break;
   2828         }
   2829 
   2830         if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) {
   2831           *RetQuestion = Statement;
   2832           break;
   2833         }
   2834       }
   2835     }
   2836 
   2837     if (*RetForm != NULL) {
   2838       break;
   2839     }
   2840   }
   2841 
   2842   //
   2843   // restore the OffsetWidth string to the original format.
   2844   //
   2845   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2846     *EndStr = '=';
   2847   } else {
   2848     *EndStr = '&';
   2849   }
   2850 
   2851   return (BOOLEAN) (*RetForm != NULL);
   2852 }
   2853 
   2854 /**
   2855   Base on the return Progress string to get the SyncConfigRequest and RestoreConfigRequest
   2856   for form and formset.
   2857 
   2858   @param  Storage                 Storage which has this Progress string.
   2859   @param  ConfigRequest           The ConfigRequest string.
   2860   @param  Progress                The Progress string which has the first fail string.
   2861   @param  RestoreConfigRequest    Return the RestoreConfigRequest string.
   2862   @param  SyncConfigRequest       Return the SyncConfigRequest string.
   2863 
   2864 **/
   2865 VOID
   2866 GetSyncRestoreConfigRequest(
   2867   IN  BROWSER_STORAGE   *Storage,
   2868   IN  EFI_STRING        ConfigRequest,
   2869   IN  EFI_STRING        Progress,
   2870   OUT EFI_STRING        *RestoreConfigRequest,
   2871   OUT EFI_STRING        *SyncConfigRequest
   2872   )
   2873 {
   2874   EFI_STRING    EndStr;
   2875   EFI_STRING    ConfigHdrEndStr;
   2876   EFI_STRING    ElementStr;
   2877   UINTN         TotalSize;
   2878   UINTN         RestoreEleSize;
   2879   UINTN         SyncSize;
   2880 
   2881   ASSERT ((*Progress == L'&') || (*Progress == L'G'));
   2882   //
   2883   // If the Progress starts with ConfigHdr, means the failure is in the first name / value pair.
   2884   // Need to restore all the fields in the ConfigRequest.
   2885   //
   2886   if (*Progress == L'G') {
   2887     *RestoreConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
   2888     ASSERT (*RestoreConfigRequest != NULL);
   2889     return;
   2890   }
   2891 
   2892   //
   2893   // Find the first fail "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
   2894   //
   2895   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2896     //
   2897     // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
   2898     // here, just keep the "Fred" string.
   2899     //
   2900     EndStr = StrStr (Progress, L"=");
   2901     ASSERT (EndStr != NULL);
   2902     *EndStr = L'\0';
   2903     //
   2904     // Find the ConfigHdr in ConfigRequest.
   2905     //
   2906     ConfigHdrEndStr = StrStr (ConfigRequest, L"PATH=");
   2907     ASSERT (ConfigHdrEndStr != NULL);
   2908     while (*ConfigHdrEndStr != L'&') {
   2909       ConfigHdrEndStr++;
   2910     }
   2911   } else {
   2912     //
   2913     // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
   2914     // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
   2915     //
   2916     EndStr = StrStr (Progress, L"&VALUE=");
   2917     ASSERT (EndStr != NULL);
   2918     *EndStr = L'\0';
   2919     //
   2920     // Find the ConfigHdr in ConfigRequest.
   2921     //
   2922     ConfigHdrEndStr = StrStr (ConfigRequest, L"&OFFSET=");
   2923   }
   2924   //
   2925   // Find the first fail pair in the ConfigRequest.
   2926   //
   2927   ElementStr = StrStr (ConfigRequest, Progress);
   2928   ASSERT (ElementStr != NULL);
   2929   //
   2930   // To get the RestoreConfigRequest.
   2931   //
   2932   RestoreEleSize = StrSize (ElementStr);
   2933   TotalSize = (ConfigHdrEndStr - ConfigRequest) * sizeof (CHAR16) + RestoreEleSize + sizeof (CHAR16);
   2934   *RestoreConfigRequest = AllocateZeroPool (TotalSize);
   2935   ASSERT (*RestoreConfigRequest != NULL);
   2936   StrnCpyS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ConfigRequest, ConfigHdrEndStr - ConfigRequest);
   2937   StrCatS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ElementStr);
   2938   //
   2939   // To get the SyncConfigRequest.
   2940   //
   2941   SyncSize = StrSize (ConfigRequest) - RestoreEleSize + sizeof (CHAR16);
   2942   *SyncConfigRequest = AllocateZeroPool (SyncSize);
   2943   ASSERT (*SyncConfigRequest != NULL);
   2944   StrnCpyS (*SyncConfigRequest, SyncSize / sizeof (CHAR16), ConfigRequest, SyncSize / sizeof (CHAR16) - 1);
   2945 
   2946   //
   2947   // restore the Progress string to the original format.
   2948   //
   2949   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   2950     *EndStr = L'=';
   2951   } else {
   2952     *EndStr = L'&';
   2953   }
   2954 }
   2955 
   2956 /**
   2957   Popup an save error info and get user input.
   2958 
   2959   @param  TitleId                The form title id.
   2960   @param  HiiHandle              The hii handle for this package.
   2961 
   2962   @retval UINT32                 The user select option for the save fail.
   2963                                  BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
   2964 **/
   2965 UINT32
   2966 ConfirmSaveFail (
   2967   IN EFI_STRING_ID    TitleId,
   2968   IN EFI_HII_HANDLE   HiiHandle
   2969   )
   2970 {
   2971   CHAR16                  *FormTitle;
   2972   CHAR16                  *StringBuffer;
   2973   UINT32                  RetVal;
   2974 
   2975   FormTitle = GetToken (TitleId, HiiHandle);
   2976 
   2977   StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
   2978   ASSERT (StringBuffer != NULL);
   2979 
   2980   UnicodeSPrint (
   2981     StringBuffer,
   2982     24 * sizeof (CHAR16) + StrSize (FormTitle),
   2983     L"Submit Fail For Form: %s.",
   2984     FormTitle
   2985     );
   2986 
   2987   RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
   2988 
   2989   FreePool (StringBuffer);
   2990   FreePool (FormTitle);
   2991 
   2992   return RetVal;
   2993 }
   2994 
   2995 /**
   2996   Popup an NO_SUBMIT_IF error info and get user input.
   2997 
   2998   @param  TitleId                The form title id.
   2999   @param  HiiHandle              The hii handle for this package.
   3000 
   3001   @retval UINT32                 The user select option for the save fail.
   3002                                  BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
   3003 **/
   3004 UINT32
   3005 ConfirmNoSubmitFail (
   3006   IN EFI_STRING_ID    TitleId,
   3007   IN EFI_HII_HANDLE   HiiHandle
   3008   )
   3009 {
   3010   CHAR16                  *FormTitle;
   3011   CHAR16                  *StringBuffer;
   3012   UINT32                  RetVal;
   3013 
   3014   FormTitle = GetToken (TitleId, HiiHandle);
   3015 
   3016   StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
   3017   ASSERT (StringBuffer != NULL);
   3018 
   3019   UnicodeSPrint (
   3020     StringBuffer,
   3021     24 * sizeof (CHAR16) + StrSize (FormTitle),
   3022     L"NO_SUBMIT_IF error For Form: %s.",
   3023     FormTitle
   3024     );
   3025 
   3026   RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
   3027 
   3028   FreePool (StringBuffer);
   3029   FreePool (FormTitle);
   3030 
   3031   return RetVal;
   3032 }
   3033 
   3034 /**
   3035   Discard data based on the input setting scope (Form, FormSet or System).
   3036 
   3037   @param  FormSet                FormSet data structure.
   3038   @param  Form                   Form data structure.
   3039   @param  SettingScope           Setting Scope for Discard action.
   3040 
   3041   @retval EFI_SUCCESS            The function completed successfully.
   3042   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3043 
   3044 **/
   3045 EFI_STATUS
   3046 DiscardForm (
   3047   IN FORM_BROWSER_FORMSET             *FormSet,
   3048   IN FORM_BROWSER_FORM                *Form,
   3049   IN BROWSER_SETTING_SCOPE            SettingScope
   3050   )
   3051 {
   3052   LIST_ENTRY                   *Link;
   3053   FORMSET_STORAGE              *Storage;
   3054   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   3055   FORM_BROWSER_FORMSET         *LocalFormSet;
   3056   FORM_BROWSER_FORMSET         *OldFormSet;
   3057 
   3058   //
   3059   // Check the supported setting level.
   3060   //
   3061   if (SettingScope >= MaxLevel) {
   3062     return EFI_UNSUPPORTED;
   3063   }
   3064 
   3065   if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
   3066     ConfigInfo = NULL;
   3067     Link = GetFirstNode (&Form->ConfigRequestHead);
   3068     while (!IsNull (&Form->ConfigRequestHead, Link)) {
   3069       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   3070       Link = GetNextNode (&Form->ConfigRequestHead, Link);
   3071 
   3072       if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   3073         continue;
   3074       }
   3075 
   3076       //
   3077       // Skip if there is no RequestElement
   3078       //
   3079       if (ConfigInfo->ElementCount == 0) {
   3080         continue;
   3081       }
   3082 
   3083       //
   3084       // Prepare <ConfigResp>
   3085       //
   3086       SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
   3087 
   3088       //
   3089       // Call callback with Changed type to inform the driver.
   3090       //
   3091       SendDiscardInfoToDriver (FormSet, Form);
   3092     }
   3093 
   3094     ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
   3095   } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
   3096 
   3097     //
   3098     // Discard Buffer storage or Name/Value storage
   3099     //
   3100     Link = GetFirstNode (&FormSet->StorageListHead);
   3101     while (!IsNull (&FormSet->StorageListHead, Link)) {
   3102       Storage = FORMSET_STORAGE_FROM_LINK (Link);
   3103       Link = GetNextNode (&FormSet->StorageListHead, Link);
   3104 
   3105       if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   3106         continue;
   3107       }
   3108 
   3109       //
   3110       // Skip if there is no RequestElement
   3111       //
   3112       if (Storage->ElementCount == 0) {
   3113         continue;
   3114       }
   3115 
   3116       SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
   3117     }
   3118 
   3119     Link = GetFirstNode (&FormSet->FormListHead);
   3120     while (!IsNull (&FormSet->FormListHead, Link)) {
   3121       Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   3122       Link = GetNextNode (&FormSet->FormListHead, Link);
   3123 
   3124       //
   3125       // Call callback with Changed type to inform the driver.
   3126       //
   3127       SendDiscardInfoToDriver (FormSet, Form);
   3128     }
   3129 
   3130     ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
   3131   } else if (SettingScope == SystemLevel) {
   3132     //
   3133     // System Level Discard.
   3134     //
   3135     OldFormSet = mSystemLevelFormSet;
   3136 
   3137     //
   3138     // Discard changed value for each FormSet in the maintain list.
   3139     //
   3140     Link = GetFirstNode (&gBrowserFormSetList);
   3141     while (!IsNull (&gBrowserFormSetList, Link)) {
   3142       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   3143       Link = GetNextNode (&gBrowserFormSetList, Link);
   3144       if (!ValidateFormSet(LocalFormSet)) {
   3145         continue;
   3146       }
   3147 
   3148       mSystemLevelFormSet = LocalFormSet;
   3149 
   3150       DiscardForm (LocalFormSet, NULL, FormSetLevel);
   3151       if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
   3152         //
   3153         // Remove maintain backup list after discard except for the current using FormSet.
   3154         //
   3155         CleanBrowserStorage(LocalFormSet);
   3156         RemoveEntryList (&LocalFormSet->Link);
   3157         DestroyFormSet (LocalFormSet);
   3158       }
   3159     }
   3160 
   3161     mSystemLevelFormSet = OldFormSet;
   3162   }
   3163 
   3164   return EFI_SUCCESS;
   3165 }
   3166 
   3167 /**
   3168   Submit data for a form.
   3169 
   3170   @param  FormSet                FormSet data structure.
   3171   @param  Form                   Form data structure.
   3172 
   3173   @retval EFI_SUCCESS            The function completed successfully.
   3174   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3175 
   3176 **/
   3177 EFI_STATUS
   3178 SubmitForForm (
   3179   IN FORM_BROWSER_FORMSET             *FormSet,
   3180   IN FORM_BROWSER_FORM                *Form
   3181   )
   3182 {
   3183   EFI_STATUS              Status;
   3184   LIST_ENTRY              *Link;
   3185   EFI_STRING              ConfigResp;
   3186   EFI_STRING              Progress;
   3187   BROWSER_STORAGE         *Storage;
   3188   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   3189   BOOLEAN                 SubmitFormFail;
   3190 
   3191   SubmitFormFail = FALSE;
   3192 
   3193   if (!IsNvUpdateRequiredForForm (Form)) {
   3194     return EFI_SUCCESS;
   3195   }
   3196 
   3197   Status = NoSubmitCheck (FormSet, &Form, NULL);
   3198   if (EFI_ERROR (Status)) {
   3199     return Status;
   3200   }
   3201 
   3202   Link = GetFirstNode (&Form->ConfigRequestHead);
   3203   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   3204     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   3205     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   3206 
   3207     Storage = ConfigInfo->Storage;
   3208     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   3209       continue;
   3210     }
   3211 
   3212     //
   3213     // Skip if there is no RequestElement
   3214     //
   3215     if (ConfigInfo->ElementCount == 0) {
   3216       continue;
   3217     }
   3218 
   3219     //
   3220     // 1. Prepare <ConfigResp>
   3221     //
   3222     Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
   3223     if (EFI_ERROR (Status)) {
   3224       return Status;
   3225     }
   3226 
   3227     //
   3228     // 2. Set value to hii config routine protocol.
   3229     //
   3230     Status = mHiiConfigRouting->RouteConfig (
   3231                                       mHiiConfigRouting,
   3232                                       ConfigResp,
   3233                                       &Progress
   3234                                       );
   3235 
   3236     if (EFI_ERROR (Status)) {
   3237       //
   3238       // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
   3239       //
   3240       SubmitFormFail = TRUE;
   3241       GetSyncRestoreConfigRequest (ConfigInfo->Storage, ConfigInfo->ConfigRequest, Progress, &ConfigInfo->RestoreConfigRequest, &ConfigInfo->SyncConfigRequest);
   3242       InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
   3243       FreePool (ConfigResp);
   3244       continue;
   3245     }
   3246 
   3247     FreePool (ConfigResp);
   3248     //
   3249     // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
   3250     //
   3251     SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
   3252   }
   3253 
   3254   //
   3255   // 4. Process the save failed storage.
   3256   //
   3257   if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
   3258     if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
   3259       Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3260       while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
   3261         ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
   3262         Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
   3263         //
   3264         // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
   3265         // base on the SyncConfigRequest to Sync the buffer.
   3266         //
   3267         SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->RestoreConfigRequest, FALSE);
   3268         FreePool (ConfigInfo->RestoreConfigRequest);
   3269         ConfigInfo->RestoreConfigRequest = NULL;
   3270         if (ConfigInfo->SyncConfigRequest != NULL) {
   3271           SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->SyncConfigRequest, TRUE);
   3272           FreePool (ConfigInfo->SyncConfigRequest);
   3273           ConfigInfo->SyncConfigRequest = NULL;
   3274         }
   3275 
   3276         Status = EFI_SUCCESS;
   3277       }
   3278       SendDiscardInfoToDriver (FormSet,Form);
   3279     } else {
   3280       Status = EFI_UNSUPPORTED;
   3281     }
   3282 
   3283     //
   3284     // Free Form save fail list.
   3285     //
   3286     while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
   3287       Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3288       ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
   3289       RemoveEntryList (&ConfigInfo->SaveFailLink);
   3290     }
   3291   }
   3292 
   3293   //
   3294   // 5. Update the NV flag.
   3295   //
   3296   ValueChangeResetFlagUpdate(TRUE, FormSet, Form);
   3297 
   3298   //
   3299   // 6 Call callback with Submitted type to inform the driver.
   3300   //
   3301   if (!SubmitFormFail) {
   3302     SubmitCallback (FormSet, Form);
   3303   }
   3304 
   3305   return Status;
   3306 }
   3307 
   3308 /**
   3309   Submit data for a formset.
   3310 
   3311   @param  FormSet                FormSet data structure.
   3312   @param  SkipProcessFail        Whether skip to process the save failed storage.
   3313                                  If submit formset is called when do system level save,
   3314                                  set this value to true and process the failed formset
   3315                                  together.
   3316                                  if submit formset is called when do formset level save,
   3317                                  set the value to false and process the failed storage
   3318                                  right after process all storages for this formset.
   3319 
   3320   @retval EFI_SUCCESS            The function completed successfully.
   3321   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3322 
   3323 **/
   3324 EFI_STATUS
   3325 SubmitForFormSet (
   3326   IN FORM_BROWSER_FORMSET             *FormSet,
   3327   IN BOOLEAN                          SkipProcessFail
   3328   )
   3329 {
   3330   EFI_STATUS              Status;
   3331   LIST_ENTRY              *Link;
   3332   EFI_STRING              ConfigResp;
   3333   EFI_STRING              Progress;
   3334   BROWSER_STORAGE         *Storage;
   3335   FORMSET_STORAGE         *FormSetStorage;
   3336   FORM_BROWSER_FORM       *Form;
   3337   BOOLEAN                 HasInserted;
   3338   FORM_BROWSER_STATEMENT  *Question;
   3339   BOOLEAN                 SubmitFormSetFail;
   3340   BOOLEAN                 DiscardChange;
   3341 
   3342   HasInserted = FALSE;
   3343   SubmitFormSetFail = FALSE;
   3344   DiscardChange     = FALSE;
   3345 
   3346   if (!IsNvUpdateRequiredForFormSet (FormSet)) {
   3347     return EFI_SUCCESS;
   3348   }
   3349 
   3350   Form = NULL;
   3351   Status = NoSubmitCheck (FormSet, &Form, &Question);
   3352   if (EFI_ERROR (Status)) {
   3353     if (SkipProcessFail) {
   3354       //
   3355       // Process NO_SUBMIT check first, so insert it at head.
   3356       //
   3357       FormSet->SaveFailForm = Form;
   3358       FormSet->SaveFailStatement = Question;
   3359       InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
   3360     }
   3361 
   3362     return Status;
   3363   }
   3364 
   3365   Form = NULL;
   3366   Question = NULL;
   3367   //
   3368   // Submit Buffer storage or Name/Value storage
   3369   //
   3370   Link = GetFirstNode (&FormSet->StorageListHead);
   3371   while (!IsNull (&FormSet->StorageListHead, Link)) {
   3372     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   3373     Storage        = FormSetStorage->BrowserStorage;
   3374     Link = GetNextNode (&FormSet->StorageListHead, Link);
   3375 
   3376     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   3377       continue;
   3378     }
   3379 
   3380     //
   3381     // Skip if there is no RequestElement
   3382     //
   3383     if (FormSetStorage->ElementCount == 0) {
   3384       continue;
   3385     }
   3386 
   3387     //
   3388     // 1. Prepare <ConfigResp>
   3389     //
   3390     Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
   3391     if (EFI_ERROR (Status)) {
   3392       return Status;
   3393     }
   3394 
   3395     //
   3396     // 2. Send <ConfigResp> to Routine config Protocol.
   3397     //
   3398     Status = mHiiConfigRouting->RouteConfig (
   3399                                       mHiiConfigRouting,
   3400                                       ConfigResp,
   3401                                       &Progress
   3402                                       );
   3403     if (EFI_ERROR (Status)) {
   3404       //
   3405       // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
   3406       //
   3407       SubmitFormSetFail = TRUE;
   3408       GetSyncRestoreConfigRequest (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, Progress, &FormSetStorage->RestoreConfigRequest, &FormSetStorage->SyncConfigRequest);
   3409       InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
   3410       if (!HasInserted) {
   3411         //
   3412         // Call submit formset for system level, save the formset info
   3413         // and process later.
   3414         //
   3415         FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);
   3416         ASSERT (Form != NULL && Question != NULL);
   3417         FormSet->SaveFailForm = Form;
   3418         FormSet->SaveFailStatement = Question;
   3419         if (SkipProcessFail) {
   3420           InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
   3421         }
   3422         HasInserted = TRUE;
   3423       }
   3424 
   3425       FreePool (ConfigResp);
   3426       continue;
   3427     }
   3428 
   3429     FreePool (ConfigResp);
   3430     //
   3431     // 3. Config success, update storage shadow Buffer
   3432     //
   3433     SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
   3434   }
   3435 
   3436   //
   3437   // 4. Has save fail storage need to handle.
   3438   //
   3439   if (Form != NULL) {
   3440     if (!SkipProcessFail) {
   3441       //
   3442       // If not in system level, just handl the save failed storage here.
   3443       //
   3444       if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
   3445         DiscardChange = TRUE;
   3446         Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
   3447         while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
   3448           FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
   3449           Storage        = FormSetStorage->BrowserStorage;
   3450           Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
   3451           //
   3452           // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
   3453           // base on the SyncConfigRequest to Sync the buffer.
   3454           //
   3455           SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
   3456           FreePool (FormSetStorage->RestoreConfigRequest);
   3457           FormSetStorage->RestoreConfigRequest = NULL;
   3458           if (FormSetStorage->SyncConfigRequest != NULL) {
   3459             SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
   3460             FreePool (FormSetStorage->SyncConfigRequest);
   3461             FormSetStorage->SyncConfigRequest = NULL;
   3462           }
   3463 
   3464           Status = EFI_SUCCESS;
   3465         }
   3466       } else {
   3467         UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
   3468 
   3469         gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
   3470         gCurrentSelection->Handle = FormSet->HiiHandle;
   3471         CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
   3472         gCurrentSelection->FormId = Form->FormId;
   3473         gCurrentSelection->QuestionId = Question->QuestionId;
   3474 
   3475         Status = EFI_UNSUPPORTED;
   3476       }
   3477 
   3478       //
   3479       // Free FormSet save fail list.
   3480       //
   3481       while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
   3482         Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
   3483         FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
   3484         RemoveEntryList (&FormSetStorage->SaveFailLink);
   3485       }
   3486     } else {
   3487       //
   3488       // If in system level, just return error and handle the failed formset later.
   3489       //
   3490       Status = EFI_UNSUPPORTED;
   3491     }
   3492   }
   3493 
   3494   //
   3495   // If user discard the change, send the discard info to driver.
   3496   //
   3497   if (DiscardChange) {
   3498     Link = GetFirstNode (&FormSet->FormListHead);
   3499     while (!IsNull (&FormSet->FormListHead, Link)) {
   3500       Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   3501       Link = GetNextNode (&FormSet->FormListHead, Link);
   3502       //
   3503       // Call callback with Changed type to inform the driver.
   3504       //
   3505       SendDiscardInfoToDriver (FormSet, Form);
   3506     }
   3507   }
   3508 
   3509   //
   3510   // 5. Update the NV flag.
   3511   //
   3512   ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
   3513 
   3514   //
   3515   // 6. Call callback with Submitted type to inform the driver.
   3516   //
   3517   if (!SubmitFormSetFail) {
   3518     SubmitCallback (FormSet, NULL);
   3519   }
   3520 
   3521   return Status;
   3522 }
   3523 
   3524 /**
   3525   Submit data for all formsets.
   3526 
   3527   @retval EFI_SUCCESS            The function completed successfully.
   3528   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3529 
   3530 **/
   3531 EFI_STATUS
   3532 SubmitForSystem (
   3533   VOID
   3534   )
   3535 {
   3536   EFI_STATUS              Status;
   3537   LIST_ENTRY              *Link;
   3538   LIST_ENTRY              *FormLink;
   3539   LIST_ENTRY              *StorageLink;
   3540   FORMSET_STORAGE         *FormSetStorage;
   3541   FORM_BROWSER_FORM       *Form;
   3542   FORM_BROWSER_FORMSET    *LocalFormSet;
   3543   UINT32                  UserSelection;
   3544   FORM_BROWSER_STATEMENT  *Question;
   3545 
   3546   mSystemSubmit = TRUE;
   3547   Link = GetFirstNode (&gBrowserFormSetList);
   3548   while (!IsNull (&gBrowserFormSetList, Link)) {
   3549     LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   3550     Link = GetNextNode (&gBrowserFormSetList, Link);
   3551     if (!ValidateFormSet(LocalFormSet)) {
   3552       continue;
   3553     }
   3554 
   3555     Status = SubmitForFormSet (LocalFormSet, TRUE);
   3556     if (EFI_ERROR (Status)) {
   3557       continue;
   3558     }
   3559 
   3560     //
   3561     // Remove maintain backup list after save except for the current using FormSet.
   3562     //
   3563     if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
   3564       CleanBrowserStorage(LocalFormSet);
   3565       RemoveEntryList (&LocalFormSet->Link);
   3566       DestroyFormSet (LocalFormSet);
   3567     }
   3568   }
   3569   mSystemSubmit = FALSE;
   3570 
   3571   Status = EFI_SUCCESS;
   3572 
   3573   //
   3574   // Process the save failed formsets.
   3575   //
   3576   Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3577   while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
   3578     LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
   3579     Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
   3580 
   3581     if (!ValidateFormSet(LocalFormSet)) {
   3582       continue;
   3583     }
   3584 
   3585     Form = LocalFormSet->SaveFailForm;
   3586     Question= LocalFormSet->SaveFailStatement;
   3587 
   3588     //
   3589     // Confirm with user, get user input.
   3590     //
   3591     if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3592       //
   3593       // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
   3594       //
   3595       UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
   3596     } else {
   3597       UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
   3598     }
   3599 
   3600     if (UserSelection == BROWSER_ACTION_DISCARD) {
   3601       if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3602         StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
   3603         while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
   3604           FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
   3605           StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
   3606 
   3607           SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
   3608         }
   3609       } else {
   3610         StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
   3611         while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
   3612           FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
   3613           StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
   3614           //
   3615           // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
   3616           // base on the SyncConfigRequest to Sync the buffer.
   3617           //
   3618           SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
   3619           FreePool (FormSetStorage->RestoreConfigRequest);
   3620           FormSetStorage->RestoreConfigRequest = NULL;
   3621           if ( FormSetStorage->SyncConfigRequest != NULL) {
   3622             SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
   3623             FreePool (FormSetStorage->SyncConfigRequest);
   3624             FormSetStorage->SyncConfigRequest = NULL;
   3625           }
   3626         }
   3627       }
   3628 
   3629       FormLink = GetFirstNode (&LocalFormSet->FormListHead);
   3630       while (!IsNull (&LocalFormSet->FormListHead, FormLink)) {
   3631         Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
   3632         FormLink = GetNextNode (&LocalFormSet->FormListHead, FormLink);
   3633         //
   3634         // Call callback with Changed type to inform the driver.
   3635         //
   3636         SendDiscardInfoToDriver (LocalFormSet, Form);
   3637       }
   3638 
   3639       if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
   3640         CleanBrowserStorage(LocalFormSet);
   3641         RemoveEntryList (&LocalFormSet->Link);
   3642         RemoveEntryList (&LocalFormSet->SaveFailLink);
   3643         DestroyFormSet (LocalFormSet);
   3644       } else {
   3645         ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);
   3646       }
   3647     } else {
   3648       if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3649         NoSubmitCheck (LocalFormSet, &Form, &Question);
   3650       }
   3651 
   3652       UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
   3653 
   3654       gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
   3655       gCurrentSelection->Handle = LocalFormSet->HiiHandle;
   3656       CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
   3657       gCurrentSelection->FormId = Form->FormId;
   3658       gCurrentSelection->QuestionId = Question->QuestionId;
   3659 
   3660       Status = EFI_UNSUPPORTED;
   3661       break;
   3662     }
   3663   }
   3664 
   3665   //
   3666   // Clean the list which will not process.
   3667   //
   3668   while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
   3669     Link = GetFirstNode (&gBrowserSaveFailFormSetList);
   3670     LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
   3671     RemoveEntryList (&LocalFormSet->SaveFailLink);
   3672 
   3673     while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
   3674       StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
   3675       FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
   3676       RemoveEntryList (&FormSetStorage->SaveFailLink);
   3677     }
   3678   }
   3679 
   3680   return Status;
   3681 }
   3682 
   3683 /**
   3684   Submit data based on the input Setting level (Form, FormSet or System).
   3685 
   3686   @param  FormSet                FormSet data structure.
   3687   @param  Form                   Form data structure.
   3688   @param  SettingScope           Setting Scope for Submit action.
   3689 
   3690   @retval EFI_SUCCESS            The function completed successfully.
   3691   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   3692 
   3693 **/
   3694 EFI_STATUS
   3695 SubmitForm (
   3696   IN FORM_BROWSER_FORMSET             *FormSet,
   3697   IN FORM_BROWSER_FORM                *Form,
   3698   IN BROWSER_SETTING_SCOPE            SettingScope
   3699   )
   3700 {
   3701   EFI_STATUS              Status;
   3702 
   3703   switch (SettingScope) {
   3704   case FormLevel:
   3705     Status = SubmitForForm(FormSet, Form);
   3706     break;
   3707 
   3708   case FormSetLevel:
   3709     Status = SubmitForFormSet (FormSet, FALSE);
   3710     break;
   3711 
   3712   case SystemLevel:
   3713     Status = SubmitForSystem ();
   3714     break;
   3715 
   3716   default:
   3717     Status = EFI_UNSUPPORTED;
   3718     break;
   3719   }
   3720 
   3721   return Status;
   3722 }
   3723 
   3724 /**
   3725   Converts the unicode character of the string from uppercase to lowercase.
   3726   This is a internal function.
   3727 
   3728   @param ConfigString  String to be converted
   3729 
   3730 **/
   3731 VOID
   3732 EFIAPI
   3733 HiiToLower (
   3734   IN EFI_STRING  ConfigString
   3735   )
   3736 {
   3737   EFI_STRING  String;
   3738   BOOLEAN     Lower;
   3739 
   3740   ASSERT (ConfigString != NULL);
   3741 
   3742   //
   3743   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
   3744   //
   3745   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
   3746     if (*String == L'=') {
   3747       Lower = TRUE;
   3748     } else if (*String == L'&') {
   3749       Lower = FALSE;
   3750     } else if (Lower && *String >= L'A' && *String <= L'F') {
   3751       *String = (CHAR16) (*String - L'A' + L'a');
   3752     }
   3753   }
   3754 }
   3755 
   3756 /**
   3757   Find the point in the ConfigResp string for this question.
   3758 
   3759   @param  Question               The question.
   3760   @param  ConfigResp             Get ConfigResp string.
   3761 
   3762   @retval  point to the offset where is for this question.
   3763 
   3764 **/
   3765 CHAR16 *
   3766 GetOffsetFromConfigResp (
   3767   IN FORM_BROWSER_STATEMENT           *Question,
   3768   IN CHAR16                           *ConfigResp
   3769   )
   3770 {
   3771   CHAR16                       *RequestElement;
   3772   CHAR16                       *BlockData;
   3773 
   3774   //
   3775   // Type is EFI_HII_VARSTORE_NAME_VALUE.
   3776   //
   3777   if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   3778     RequestElement = StrStr (ConfigResp, Question->VariableName);
   3779     if (RequestElement != NULL) {
   3780       //
   3781       // Skip the "VariableName=" field.
   3782       //
   3783       RequestElement += StrLen (Question->VariableName) + 1;
   3784     }
   3785 
   3786     return RequestElement;
   3787   }
   3788 
   3789   //
   3790   // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
   3791   //
   3792 
   3793   //
   3794   // Convert all hex digits in ConfigResp to lower case before searching.
   3795   //
   3796   HiiToLower (ConfigResp);
   3797 
   3798   //
   3799   // 1. Directly use Question->BlockName to find.
   3800   //
   3801   RequestElement = StrStr (ConfigResp, Question->BlockName);
   3802   if (RequestElement != NULL) {
   3803     //
   3804     // Skip the "Question->BlockName&VALUE=" field.
   3805     //
   3806     RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
   3807     return RequestElement;
   3808   }
   3809 
   3810   //
   3811   // 2. Change all hex digits in Question->BlockName to lower and compare again.
   3812   //
   3813   BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName);
   3814   ASSERT (BlockData != NULL);
   3815   HiiToLower (BlockData);
   3816   RequestElement = StrStr (ConfigResp, BlockData);
   3817   FreePool (BlockData);
   3818 
   3819   if (RequestElement != NULL) {
   3820     //
   3821     // Skip the "Question->BlockName&VALUE=" field.
   3822     //
   3823     RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
   3824   }
   3825 
   3826   return RequestElement;
   3827 }
   3828 
   3829 /**
   3830   Get Question default value from AltCfg string.
   3831 
   3832   @param  FormSet                The form set.
   3833   @param  Form                   The form
   3834   @param  Question               The question.
   3835 
   3836   @retval EFI_SUCCESS            Question is reset to default value.
   3837 
   3838 **/
   3839 EFI_STATUS
   3840 GetDefaultValueFromAltCfg (
   3841   IN     FORM_BROWSER_FORMSET             *FormSet,
   3842   IN     FORM_BROWSER_FORM                *Form,
   3843   IN OUT FORM_BROWSER_STATEMENT           *Question
   3844   )
   3845 {
   3846   BROWSER_STORAGE              *Storage;
   3847   FORMSET_STORAGE              *FormSetStorage;
   3848   CHAR16                       *ConfigResp;
   3849   CHAR16                       *Value;
   3850   LIST_ENTRY                   *Link;
   3851   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   3852 
   3853   Storage = Question->Storage;
   3854   if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
   3855     return EFI_NOT_FOUND;
   3856   }
   3857 
   3858   //
   3859   // Try to get AltCfg string from form. If not found it, then
   3860   // try to get it from formset.
   3861   //
   3862   ConfigResp    = NULL;
   3863   Link = GetFirstNode (&Form->ConfigRequestHead);
   3864   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   3865     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   3866     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   3867 
   3868     if (Storage == ConfigInfo->Storage) {
   3869       ConfigResp = ConfigInfo->ConfigAltResp;
   3870       break;
   3871     }
   3872   }
   3873 
   3874   if (ConfigResp == NULL) {
   3875     Link = GetFirstNode (&FormSet->StorageListHead);
   3876     while (!IsNull (&FormSet->StorageListHead, Link)) {
   3877       FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   3878       Link = GetNextNode (&FormSet->StorageListHead, Link);
   3879 
   3880       if (Storage == FormSetStorage->BrowserStorage) {
   3881         ConfigResp = FormSetStorage->ConfigAltResp;
   3882         break;
   3883       }
   3884     }
   3885   }
   3886 
   3887   if (ConfigResp == NULL) {
   3888     return EFI_NOT_FOUND;
   3889   }
   3890 
   3891   Value = GetOffsetFromConfigResp (Question, ConfigResp);
   3892   if (Value == NULL) {
   3893     return EFI_NOT_FOUND;
   3894   }
   3895 
   3896   return BufferToValue (Question, Value);
   3897 }
   3898 
   3899 /**
   3900   Get default Id value used for browser.
   3901 
   3902   @param  DefaultId              The default id value used by hii.
   3903 
   3904   @retval Browser used default value.
   3905 
   3906 **/
   3907 INTN
   3908 GetDefaultIdForCallBack (
   3909   UINTN DefaultId
   3910   )
   3911 {
   3912   if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
   3913     return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
   3914   } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
   3915     return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
   3916   } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
   3917     return EFI_BROWSER_ACTION_DEFAULT_SAFE;
   3918   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
   3919     return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
   3920   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
   3921     return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
   3922   } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
   3923     return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
   3924   } else {
   3925     return -1;
   3926   }
   3927 }
   3928 
   3929 
   3930 
   3931 /**
   3932   Return data element in an Array by its Index.
   3933 
   3934   @param  Array                  The data array.
   3935   @param  Type                   Type of the data in this array.
   3936   @param  Index                  Zero based index for data in this array.
   3937 
   3938   @retval Value                  The data to be returned
   3939 
   3940 **/
   3941 UINT64
   3942 GetArrayData (
   3943   IN VOID                     *Array,
   3944   IN UINT8                    Type,
   3945   IN UINTN                    Index
   3946   )
   3947 {
   3948   UINT64 Data;
   3949 
   3950   ASSERT (Array != NULL);
   3951 
   3952   Data = 0;
   3953   switch (Type) {
   3954   case EFI_IFR_TYPE_NUM_SIZE_8:
   3955     Data = (UINT64) *(((UINT8 *) Array) + Index);
   3956     break;
   3957 
   3958   case EFI_IFR_TYPE_NUM_SIZE_16:
   3959     Data = (UINT64) *(((UINT16 *) Array) + Index);
   3960     break;
   3961 
   3962   case EFI_IFR_TYPE_NUM_SIZE_32:
   3963     Data = (UINT64) *(((UINT32 *) Array) + Index);
   3964     break;
   3965 
   3966   case EFI_IFR_TYPE_NUM_SIZE_64:
   3967     Data = (UINT64) *(((UINT64 *) Array) + Index);
   3968     break;
   3969 
   3970   default:
   3971     break;
   3972   }
   3973 
   3974   return Data;
   3975 }
   3976 
   3977 
   3978 /**
   3979   Set value of a data element in an Array by its Index.
   3980 
   3981   @param  Array                  The data array.
   3982   @param  Type                   Type of the data in this array.
   3983   @param  Index                  Zero based index for data in this array.
   3984   @param  Value                  The value to be set.
   3985 
   3986 **/
   3987 VOID
   3988 SetArrayData (
   3989   IN VOID                     *Array,
   3990   IN UINT8                    Type,
   3991   IN UINTN                    Index,
   3992   IN UINT64                   Value
   3993   )
   3994 {
   3995 
   3996   ASSERT (Array != NULL);
   3997 
   3998   switch (Type) {
   3999   case EFI_IFR_TYPE_NUM_SIZE_8:
   4000     *(((UINT8 *) Array) + Index) = (UINT8) Value;
   4001     break;
   4002 
   4003   case EFI_IFR_TYPE_NUM_SIZE_16:
   4004     *(((UINT16 *) Array) + Index) = (UINT16) Value;
   4005     break;
   4006 
   4007   case EFI_IFR_TYPE_NUM_SIZE_32:
   4008     *(((UINT32 *) Array) + Index) = (UINT32) Value;
   4009     break;
   4010 
   4011   case EFI_IFR_TYPE_NUM_SIZE_64:
   4012     *(((UINT64 *) Array) + Index) = (UINT64) Value;
   4013     break;
   4014 
   4015   default:
   4016     break;
   4017   }
   4018 }
   4019 
   4020 /**
   4021   Search an Option of a Question by its value.
   4022 
   4023   @param  Question               The Question
   4024   @param  OptionValue            Value for Option to be searched.
   4025 
   4026   @retval Pointer                Pointer to the found Option.
   4027   @retval NULL                   Option not found.
   4028 
   4029 **/
   4030 QUESTION_OPTION *
   4031 ValueToOption (
   4032   IN FORM_BROWSER_STATEMENT   *Question,
   4033   IN EFI_HII_VALUE            *OptionValue
   4034   )
   4035 {
   4036   LIST_ENTRY       *Link;
   4037   QUESTION_OPTION  *Option;
   4038   INTN             Result;
   4039 
   4040   Link = GetFirstNode (&Question->OptionListHead);
   4041   while (!IsNull (&Question->OptionListHead, Link)) {
   4042     Option = QUESTION_OPTION_FROM_LINK (Link);
   4043 
   4044     if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
   4045       //
   4046       // Check the suppressif condition, only a valid option can be return.
   4047       //
   4048       if ((Option->SuppressExpression == NULL) ||
   4049           ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
   4050         return Option;
   4051       }
   4052     }
   4053 
   4054     Link = GetNextNode (&Question->OptionListHead, Link);
   4055   }
   4056 
   4057   return NULL;
   4058 }
   4059 
   4060 
   4061 /**
   4062   Reset Question to its default value.
   4063 
   4064   @param  FormSet                The form set.
   4065   @param  Form                   The form.
   4066   @param  Question               The question.
   4067   @param  DefaultId              The Class of the default.
   4068 
   4069   @retval EFI_SUCCESS            Question is reset to default value.
   4070 
   4071 **/
   4072 EFI_STATUS
   4073 GetQuestionDefault (
   4074   IN FORM_BROWSER_FORMSET             *FormSet,
   4075   IN FORM_BROWSER_FORM                *Form,
   4076   IN FORM_BROWSER_STATEMENT           *Question,
   4077   IN UINT16                           DefaultId
   4078   )
   4079 {
   4080   EFI_STATUS              Status;
   4081   LIST_ENTRY              *Link;
   4082   QUESTION_DEFAULT        *Default;
   4083   QUESTION_OPTION         *Option;
   4084   EFI_HII_VALUE           *HiiValue;
   4085   UINT8                   Index;
   4086   EFI_STRING              StrValue;
   4087   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   4088   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   4089   INTN                            Action;
   4090   CHAR16                          *NewString;
   4091   EFI_IFR_TYPE_VALUE              *TypeValue;
   4092   UINT16                          OriginalDefaultId;
   4093   FORMSET_DEFAULTSTORE            *DefaultStore;
   4094   LIST_ENTRY                      *DefaultLink;
   4095 
   4096   Status   = EFI_NOT_FOUND;
   4097   StrValue = NULL;
   4098   OriginalDefaultId  = DefaultId;
   4099   DefaultLink        = GetFirstNode (&FormSet->DefaultStoreListHead);
   4100 
   4101   //
   4102   // Statement don't have storage, skip them
   4103   //
   4104   if (Question->QuestionId == 0) {
   4105     return Status;
   4106   }
   4107 
   4108   //
   4109   // There are Five ways to specify default value for a Question:
   4110   //  1, use call back function (highest priority)
   4111   //  2, use ExtractConfig function
   4112   //  3, use nested EFI_IFR_DEFAULT
   4113   //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
   4114   //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
   4115   //
   4116 ReGetDefault:
   4117   HiiValue = &Question->HiiValue;
   4118   TypeValue = &HiiValue->Value;
   4119   if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   4120     //
   4121     // For orderedlist, need to pass the BufferValue to Callback function.
   4122     //
   4123     TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
   4124   }
   4125 
   4126   //
   4127   // Get Question defaut value from call back function.
   4128   //
   4129   ConfigAccess = FormSet->ConfigAccess;
   4130   Action = GetDefaultIdForCallBack (DefaultId);
   4131   if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
   4132     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   4133     Status = ConfigAccess->Callback (
   4134                              ConfigAccess,
   4135                              Action,
   4136                              Question->QuestionId,
   4137                              HiiValue->Type,
   4138                              TypeValue,
   4139                              &ActionRequest
   4140                              );
   4141     if (!EFI_ERROR (Status)) {
   4142       if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
   4143         NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
   4144         ASSERT (NewString != NULL);
   4145 
   4146         ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
   4147         if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
   4148           ZeroMem (Question->BufferValue, Question->StorageWidth);
   4149           CopyMem (Question->BufferValue, NewString, StrSize (NewString));
   4150         } else {
   4151           CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
   4152         }
   4153 
   4154         FreePool (NewString);
   4155       }
   4156       return Status;
   4157     }
   4158   }
   4159 
   4160   //
   4161   // Get default value from altcfg string.
   4162   //
   4163   if (ConfigAccess != NULL) {
   4164     Status = GetDefaultValueFromAltCfg(FormSet, Form, Question);
   4165     if (!EFI_ERROR (Status)) {
   4166         return Status;
   4167     }
   4168   }
   4169 
   4170   //
   4171   // EFI_IFR_DEFAULT has highest priority
   4172   //
   4173   if (!IsListEmpty (&Question->DefaultListHead)) {
   4174     Link = GetFirstNode (&Question->DefaultListHead);
   4175     while (!IsNull (&Question->DefaultListHead, Link)) {
   4176       Default = QUESTION_DEFAULT_FROM_LINK (Link);
   4177 
   4178       if (Default->DefaultId == DefaultId) {
   4179         if (Default->ValueExpression != NULL) {
   4180           //
   4181           // Default is provided by an Expression, evaluate it
   4182           //
   4183           Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
   4184           if (EFI_ERROR (Status)) {
   4185             return Status;
   4186           }
   4187 
   4188           if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
   4189             ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
   4190             if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
   4191               CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
   4192               Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
   4193             } else {
   4194               CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
   4195               Question->HiiValue.BufferLen = Question->StorageWidth;
   4196             }
   4197             FreePool (Default->ValueExpression->Result.Buffer);
   4198           }
   4199           HiiValue->Type = Default->ValueExpression->Result.Type;
   4200           CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
   4201         } else {
   4202           //
   4203           // Default value is embedded in EFI_IFR_DEFAULT
   4204           //
   4205           if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
   4206             ASSERT (HiiValue->Buffer != NULL);
   4207             CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
   4208           } else {
   4209             CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
   4210           }
   4211         }
   4212 
   4213         if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
   4214           StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
   4215           if (StrValue == NULL) {
   4216             return EFI_NOT_FOUND;
   4217           }
   4218           if (Question->StorageWidth > StrSize (StrValue)) {
   4219             ZeroMem (Question->BufferValue, Question->StorageWidth);
   4220             CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
   4221           } else {
   4222             CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
   4223           }
   4224         }
   4225 
   4226         return EFI_SUCCESS;
   4227       }
   4228 
   4229       Link = GetNextNode (&Question->DefaultListHead, Link);
   4230     }
   4231   }
   4232 
   4233   //
   4234   // EFI_ONE_OF_OPTION
   4235   //
   4236   if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
   4237     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
   4238       //
   4239       // OneOfOption could only provide Standard and Manufacturing default
   4240       //
   4241       Link = GetFirstNode (&Question->OptionListHead);
   4242       while (!IsNull (&Question->OptionListHead, Link)) {
   4243         Option = QUESTION_OPTION_FROM_LINK (Link);
   4244         Link = GetNextNode (&Question->OptionListHead, Link);
   4245 
   4246         if ((Option->SuppressExpression != NULL) &&
   4247             EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
   4248           continue;
   4249         }
   4250 
   4251         if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
   4252             ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
   4253            ) {
   4254           CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
   4255 
   4256           return EFI_SUCCESS;
   4257         }
   4258       }
   4259     }
   4260   }
   4261 
   4262   //
   4263   // EFI_IFR_CHECKBOX - lowest priority
   4264   //
   4265   if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
   4266     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
   4267       //
   4268       // Checkbox could only provide Standard and Manufacturing default
   4269       //
   4270       if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
   4271           ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
   4272          ) {
   4273         HiiValue->Value.b = TRUE;
   4274       }
   4275 
   4276       return EFI_SUCCESS;
   4277     }
   4278   }
   4279 
   4280   //
   4281   // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
   4282   // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
   4283   // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
   4284   //
   4285   while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
   4286     DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
   4287     DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
   4288     DefaultId = DefaultStore->DefaultId;
   4289     if (DefaultId == OriginalDefaultId) {
   4290       continue;
   4291     }
   4292     goto ReGetDefault;
   4293   }
   4294 
   4295   //
   4296   // For Questions without default value for all the default id in the DefaultStoreList.
   4297   //
   4298   Status = EFI_NOT_FOUND;
   4299   switch (Question->Operand) {
   4300   case EFI_IFR_CHECKBOX_OP:
   4301     HiiValue->Value.b = FALSE;
   4302     Status = EFI_SUCCESS;
   4303     break;
   4304 
   4305   case EFI_IFR_NUMERIC_OP:
   4306     //
   4307     // Take minimum value as numeric default value
   4308     //
   4309     if ((Question->Flags & EFI_IFR_DISPLAY) == 0) {
   4310       //
   4311       // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
   4312       //
   4313       switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) {
   4314       case EFI_IFR_NUMERIC_SIZE_1:
   4315         if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) {
   4316           HiiValue->Value.u8 = (UINT8) Question->Minimum;
   4317           Status = EFI_SUCCESS;
   4318         }
   4319         break;
   4320       case EFI_IFR_NUMERIC_SIZE_2:
   4321         if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) {
   4322           HiiValue->Value.u16 = (UINT16) Question->Minimum;
   4323           Status = EFI_SUCCESS;
   4324         }
   4325         break;
   4326       case EFI_IFR_NUMERIC_SIZE_4:
   4327         if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) {
   4328           HiiValue->Value.u32 = (UINT32) Question->Minimum;
   4329           Status = EFI_SUCCESS;
   4330         }
   4331         break;
   4332       case EFI_IFR_NUMERIC_SIZE_8:
   4333         if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) {
   4334           HiiValue->Value.u64 = Question->Minimum;
   4335           Status = EFI_SUCCESS;
   4336         }
   4337         break;
   4338       default:
   4339         break;
   4340       }
   4341     } else {
   4342       if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
   4343         HiiValue->Value.u64 = Question->Minimum;
   4344         Status = EFI_SUCCESS;
   4345       }
   4346     }
   4347     break;
   4348 
   4349   case EFI_IFR_ONE_OF_OP:
   4350     //
   4351     // Take first oneof option as oneof's default value
   4352     //
   4353     if (ValueToOption (Question, HiiValue) == NULL) {
   4354       Link = GetFirstNode (&Question->OptionListHead);
   4355       while (!IsNull (&Question->OptionListHead, Link)) {
   4356         Option = QUESTION_OPTION_FROM_LINK (Link);
   4357         Link = GetNextNode (&Question->OptionListHead, Link);
   4358 
   4359         if ((Option->SuppressExpression != NULL) &&
   4360             EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
   4361           continue;
   4362         }
   4363 
   4364         CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
   4365         Status = EFI_SUCCESS;
   4366         break;
   4367       }
   4368     }
   4369     break;
   4370 
   4371   case EFI_IFR_ORDERED_LIST_OP:
   4372     //
   4373     // Take option sequence in IFR as ordered list's default value
   4374     //
   4375     Index = 0;
   4376     Link = GetFirstNode (&Question->OptionListHead);
   4377     while (!IsNull (&Question->OptionListHead, Link)) {
   4378       Status = EFI_SUCCESS;
   4379       Option = QUESTION_OPTION_FROM_LINK (Link);
   4380       Link = GetNextNode (&Question->OptionListHead, Link);
   4381 
   4382       if ((Option->SuppressExpression != NULL) &&
   4383           EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
   4384         continue;
   4385       }
   4386 
   4387       SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
   4388 
   4389       Index++;
   4390       if (Index >= Question->MaxContainers) {
   4391         break;
   4392       }
   4393     }
   4394     break;
   4395 
   4396   default:
   4397     break;
   4398   }
   4399 
   4400   return Status;
   4401 }
   4402 
   4403 /**
   4404   Get AltCfg string for current form.
   4405 
   4406   @param  FormSet                Form data structure.
   4407   @param  Form                   Form data structure.
   4408   @param  DefaultId              The Class of the default.
   4409   @param  BrowserStorage         The input request storage for the questions.
   4410 
   4411 **/
   4412 VOID
   4413 ExtractAltCfgForForm (
   4414   IN FORM_BROWSER_FORMSET   *FormSet,
   4415   IN FORM_BROWSER_FORM      *Form,
   4416   IN UINT16                 DefaultId,
   4417   IN BROWSER_STORAGE        *BrowserStorage
   4418   )
   4419 {
   4420   EFI_STATUS                   Status;
   4421   LIST_ENTRY                   *Link;
   4422   CHAR16                       *ConfigResp;
   4423   CHAR16                       *Progress;
   4424   CHAR16                       *Result;
   4425   BROWSER_STORAGE              *Storage;
   4426   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   4427   FORMSET_STORAGE              *FormSetStorage;
   4428 
   4429   //
   4430   // Check whether has get AltCfg string for this formset.
   4431   // If yes, no need to get AltCfg for form.
   4432   //
   4433   Link = GetFirstNode (&FormSet->StorageListHead);
   4434   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4435     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   4436     Storage        = FormSetStorage->BrowserStorage;
   4437     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4438     if (BrowserStorage != NULL && BrowserStorage != Storage) {
   4439       continue;
   4440     }
   4441 
   4442     if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE &&
   4443         FormSetStorage->ElementCount != 0 &&
   4444         FormSetStorage->HasCallAltCfg) {
   4445       return;
   4446     }
   4447   }
   4448 
   4449   //
   4450   // Get AltCfg string for each form.
   4451   //
   4452   Link = GetFirstNode (&Form->ConfigRequestHead);
   4453   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   4454     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   4455     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   4456 
   4457     Storage = ConfigInfo->Storage;
   4458     if (BrowserStorage != NULL && BrowserStorage != Storage) {
   4459       continue;
   4460     }
   4461 
   4462     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   4463       continue;
   4464     }
   4465 
   4466     //
   4467     // 1. Skip if there is no RequestElement
   4468     //
   4469     if (ConfigInfo->ElementCount == 0) {
   4470       continue;
   4471     }
   4472 
   4473     //
   4474     // 2. Get value through hii config routine protocol.
   4475     //
   4476     Status = mHiiConfigRouting->ExtractConfig (
   4477                                       mHiiConfigRouting,
   4478                                       ConfigInfo->ConfigRequest,
   4479                                       &Progress,
   4480                                       &Result
   4481                                       );
   4482     if (EFI_ERROR (Status)) {
   4483       continue;
   4484     }
   4485 
   4486     //
   4487     // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
   4488     //    Get the default configuration string according to the default ID.
   4489     //
   4490     Status = mHiiConfigRouting->GetAltConfig (
   4491                                   mHiiConfigRouting,
   4492                                   Result,
   4493                                   &Storage->Guid,
   4494                                   Storage->Name,
   4495                                   NULL,
   4496                                   &DefaultId,  // it can be NULL to get the current setting.
   4497                                   &ConfigResp
   4498                                 );
   4499     FreePool (Result);
   4500     if (EFI_ERROR (Status)) {
   4501       continue;
   4502     }
   4503 
   4504     ConfigInfo->ConfigAltResp = ConfigResp;
   4505   }
   4506 }
   4507 
   4508 /**
   4509   Clean AltCfg string for current form.
   4510 
   4511   @param  Form                   Form data structure.
   4512 
   4513 **/
   4514 VOID
   4515 CleanAltCfgForForm (
   4516   IN FORM_BROWSER_FORM   *Form
   4517   )
   4518 {
   4519   LIST_ENTRY              *Link;
   4520   FORM_BROWSER_CONFIG_REQUEST  *ConfigInfo;
   4521 
   4522   Link = GetFirstNode (&Form->ConfigRequestHead);
   4523   while (!IsNull (&Form->ConfigRequestHead, Link)) {
   4524     ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
   4525     Link = GetNextNode (&Form->ConfigRequestHead, Link);
   4526 
   4527     if (ConfigInfo->ConfigAltResp != NULL) {
   4528       FreePool (ConfigInfo->ConfigAltResp);
   4529       ConfigInfo->ConfigAltResp = NULL;
   4530     }
   4531   }
   4532 }
   4533 
   4534 /**
   4535   Get AltCfg string for current formset.
   4536 
   4537   @param  FormSet                Form data structure.
   4538   @param  DefaultId              The Class of the default.
   4539   @param  BrowserStorage         The input request storage for the questions.
   4540 
   4541 **/
   4542 VOID
   4543 ExtractAltCfgForFormSet (
   4544   IN FORM_BROWSER_FORMSET   *FormSet,
   4545   IN UINT16                 DefaultId,
   4546   IN BROWSER_STORAGE        *BrowserStorage
   4547   )
   4548 {
   4549   EFI_STATUS              Status;
   4550   LIST_ENTRY              *Link;
   4551   CHAR16                  *ConfigResp;
   4552   CHAR16                  *Progress;
   4553   CHAR16                  *Result;
   4554   BROWSER_STORAGE         *Storage;
   4555   FORMSET_STORAGE         *FormSetStorage;
   4556 
   4557   Link = GetFirstNode (&FormSet->StorageListHead);
   4558   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4559     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   4560     Storage        = FormSetStorage->BrowserStorage;
   4561     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4562 
   4563     if (BrowserStorage != NULL && BrowserStorage != Storage) {
   4564       continue;
   4565     }
   4566 
   4567     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
   4568       continue;
   4569     }
   4570 
   4571     //
   4572     // 1. Skip if there is no RequestElement
   4573     //
   4574     if (FormSetStorage->ElementCount == 0) {
   4575       continue;
   4576     }
   4577 
   4578     FormSetStorage->HasCallAltCfg = TRUE;
   4579 
   4580     //
   4581     // 2. Get value through hii config routine protocol.
   4582     //
   4583     Status = mHiiConfigRouting->ExtractConfig (
   4584                                       mHiiConfigRouting,
   4585                                       FormSetStorage->ConfigRequest,
   4586                                       &Progress,
   4587                                       &Result
   4588                                       );
   4589     if (EFI_ERROR (Status)) {
   4590       continue;
   4591     }
   4592 
   4593     //
   4594     // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
   4595     //    Get the default configuration string according to the default ID.
   4596     //
   4597     Status = mHiiConfigRouting->GetAltConfig (
   4598                                   mHiiConfigRouting,
   4599                                   Result,
   4600                                   &Storage->Guid,
   4601                                   Storage->Name,
   4602                                   NULL,
   4603                                   &DefaultId,  // it can be NULL to get the current setting.
   4604                                   &ConfigResp
   4605                                 );
   4606 
   4607     FreePool (Result);
   4608     if (EFI_ERROR (Status)) {
   4609       continue;
   4610     }
   4611 
   4612     FormSetStorage->ConfigAltResp = ConfigResp;
   4613   }
   4614 
   4615 }
   4616 
   4617 /**
   4618   Clean AltCfg string for current formset.
   4619 
   4620   @param  FormSet                Form data structure.
   4621 
   4622 **/
   4623 VOID
   4624 CleanAltCfgForFormSet (
   4625   IN FORM_BROWSER_FORMSET   *FormSet
   4626   )
   4627 {
   4628   LIST_ENTRY              *Link;
   4629   FORMSET_STORAGE         *FormSetStorage;
   4630 
   4631   Link = GetFirstNode (&FormSet->StorageListHead);
   4632   while (!IsNull (&FormSet->StorageListHead, Link)) {
   4633     FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
   4634     Link = GetNextNode (&FormSet->StorageListHead, Link);
   4635 
   4636     if (FormSetStorage->ConfigAltResp != NULL) {
   4637       FreePool (FormSetStorage->ConfigAltResp);
   4638       FormSetStorage->ConfigAltResp = NULL;
   4639     }
   4640 
   4641     FormSetStorage->HasCallAltCfg = FALSE;
   4642   }
   4643 }
   4644 
   4645 /**
   4646   Reset Questions to their initial value or default value in a Form, Formset or System.
   4647 
   4648   GetDefaultValueScope parameter decides which questions will reset
   4649   to its default value.
   4650 
   4651   @param  FormSet                FormSet data structure.
   4652   @param  Form                   Form data structure.
   4653   @param  DefaultId              The Class of the default.
   4654   @param  SettingScope           Setting Scope for Default action.
   4655   @param  GetDefaultValueScope   Get default value scope.
   4656   @param  Storage                Get default value only for this storage.
   4657   @param  RetrieveValueFirst     Whether call the retrieve call back to
   4658                                  get the initial value before get default
   4659                                  value.
   4660   @param  SkipGetAltCfg          Whether skip the get altcfg string process.
   4661 
   4662   @retval EFI_SUCCESS            The function completed successfully.
   4663   @retval EFI_UNSUPPORTED        Unsupport SettingScope.
   4664 
   4665 **/
   4666 EFI_STATUS
   4667 ExtractDefault (
   4668   IN FORM_BROWSER_FORMSET             *FormSet,
   4669   IN FORM_BROWSER_FORM                *Form,
   4670   IN UINT16                           DefaultId,
   4671   IN BROWSER_SETTING_SCOPE            SettingScope,
   4672   IN BROWSER_GET_DEFAULT_VALUE        GetDefaultValueScope,
   4673   IN BROWSER_STORAGE                  *Storage OPTIONAL,
   4674   IN BOOLEAN                          RetrieveValueFirst,
   4675   IN BOOLEAN                          SkipGetAltCfg
   4676   )
   4677 {
   4678   EFI_STATUS              Status;
   4679   LIST_ENTRY              *FormLink;
   4680   LIST_ENTRY              *Link;
   4681   FORM_BROWSER_STATEMENT  *Question;
   4682   FORM_BROWSER_FORMSET    *LocalFormSet;
   4683   FORM_BROWSER_FORMSET    *OldFormSet;
   4684 
   4685   Status = EFI_SUCCESS;
   4686 
   4687   //
   4688   // Check the supported setting level.
   4689   //
   4690   if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
   4691     return EFI_UNSUPPORTED;
   4692   }
   4693 
   4694   if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
   4695     return EFI_UNSUPPORTED;
   4696   }
   4697 
   4698   if (SettingScope == FormLevel) {
   4699     //
   4700     // Prepare the AltCfg String for form.
   4701     //
   4702     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4703       ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);
   4704     }
   4705 
   4706     //
   4707     // Extract Form default
   4708     //
   4709     Link = GetFirstNode (&Form->StatementListHead);
   4710     while (!IsNull (&Form->StatementListHead, Link)) {
   4711       Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   4712       Link = GetNextNode (&Form->StatementListHead, Link);
   4713 
   4714       //
   4715       // If get default value only for this storage, check the storage first.
   4716       //
   4717       if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
   4718         continue;
   4719       }
   4720 
   4721       //
   4722       // If get default value only for no storage question, just skip the question which has storage.
   4723       //
   4724       if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
   4725         continue;
   4726       }
   4727 
   4728       //
   4729       // If Question is disabled, don't reset it to default
   4730       //
   4731       if (Question->Expression != NULL) {
   4732         if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
   4733           continue;
   4734         }
   4735       }
   4736 
   4737       if (RetrieveValueFirst) {
   4738         //
   4739         // Call the Retrieve call back to get the initial question value.
   4740         //
   4741         Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
   4742       }
   4743 
   4744       //
   4745       // If not request to get the initial value or get initial value fail, then get default value.
   4746       //
   4747       if (!RetrieveValueFirst || EFI_ERROR (Status)) {
   4748         Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
   4749         if (EFI_ERROR (Status)) {
   4750           continue;
   4751         }
   4752       }
   4753 
   4754       //
   4755       // Synchronize Buffer storage's Edit buffer
   4756       //
   4757       if ((Question->Storage != NULL) &&
   4758           (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
   4759         SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   4760       }
   4761     }
   4762 
   4763     //
   4764     // Clean the AltCfg String.
   4765     //
   4766     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4767       CleanAltCfgForForm(Form);
   4768     }
   4769   } else if (SettingScope == FormSetLevel) {
   4770     //
   4771     // Prepare the AltCfg String for formset.
   4772     //
   4773     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4774       ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);
   4775     }
   4776 
   4777     FormLink = GetFirstNode (&FormSet->FormListHead);
   4778     while (!IsNull (&FormSet->FormListHead, FormLink)) {
   4779       Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
   4780       ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
   4781       FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
   4782     }
   4783 
   4784     //
   4785     // Clean the AltCfg String.
   4786     //
   4787     if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
   4788       CleanAltCfgForFormSet (FormSet);
   4789     }
   4790   } else if (SettingScope == SystemLevel) {
   4791     //
   4792     // Preload all Hii formset.
   4793     //
   4794     LoadAllHiiFormset();
   4795 
   4796     OldFormSet = mSystemLevelFormSet;
   4797 
   4798     //
   4799     // Set Default Value for each FormSet in the maintain list.
   4800     //
   4801     Link = GetFirstNode (&gBrowserFormSetList);
   4802     while (!IsNull (&gBrowserFormSetList, Link)) {
   4803       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   4804       Link = GetNextNode (&gBrowserFormSetList, Link);
   4805       if (!ValidateFormSet(LocalFormSet)) {
   4806         continue;
   4807       }
   4808 
   4809       mSystemLevelFormSet = LocalFormSet;
   4810 
   4811       ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
   4812     }
   4813 
   4814     mSystemLevelFormSet = OldFormSet;
   4815   }
   4816 
   4817   return EFI_SUCCESS;
   4818 }
   4819 
   4820 
   4821 /**
   4822   Validate whether this question's value has changed.
   4823 
   4824   @param  FormSet                FormSet data structure.
   4825   @param  Form                   Form data structure.
   4826   @param  Question               Question to be initialized.
   4827   @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.
   4828 
   4829   @retval TRUE                   Question's value has changed.
   4830   @retval FALSE                  Question's value has not changed
   4831 
   4832 **/
   4833 BOOLEAN
   4834 IsQuestionValueChanged (
   4835   IN FORM_BROWSER_FORMSET             *FormSet,
   4836   IN FORM_BROWSER_FORM                *Form,
   4837   IN OUT FORM_BROWSER_STATEMENT       *Question,
   4838   IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom
   4839   )
   4840 {
   4841   EFI_HII_VALUE    BackUpValue;
   4842   CHAR8            *BackUpBuffer;
   4843   EFI_HII_VALUE    BackUpValue2;
   4844   CHAR8            *BackUpBuffer2;
   4845   EFI_STATUS       Status;
   4846   BOOLEAN          ValueChanged;
   4847   UINTN            BufferWidth;
   4848 
   4849   //
   4850   // For quetion without storage, always mark it as data not changed.
   4851   //
   4852   if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
   4853     return FALSE;
   4854   }
   4855 
   4856   BackUpBuffer = NULL;
   4857   BackUpBuffer2 = NULL;
   4858   ValueChanged = FALSE;
   4859 
   4860   switch (Question->Operand) {
   4861     case EFI_IFR_ORDERED_LIST_OP:
   4862       BufferWidth  = Question->StorageWidth;
   4863       BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4864       ASSERT (BackUpBuffer != NULL);
   4865       break;
   4866 
   4867     case EFI_IFR_STRING_OP:
   4868     case EFI_IFR_PASSWORD_OP:
   4869       BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);
   4870       BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4871       ASSERT (BackUpBuffer != NULL);
   4872       break;
   4873 
   4874     default:
   4875       BufferWidth = 0;
   4876       break;
   4877   }
   4878   CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
   4879 
   4880   if (GetValueFrom == GetSetValueWithBothBuffer) {
   4881     Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   4882     ASSERT_EFI_ERROR(Status);
   4883 
   4884     switch (Question->Operand) {
   4885       case EFI_IFR_ORDERED_LIST_OP:
   4886         BufferWidth  = Question->StorageWidth;
   4887         BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4888         ASSERT (BackUpBuffer2 != NULL);
   4889         break;
   4890 
   4891       case EFI_IFR_STRING_OP:
   4892       case EFI_IFR_PASSWORD_OP:
   4893         BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);
   4894         BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
   4895         ASSERT (BackUpBuffer2 != NULL);
   4896         break;
   4897 
   4898       default:
   4899         BufferWidth = 0;
   4900         break;
   4901     }
   4902     CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
   4903 
   4904     Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
   4905     ASSERT_EFI_ERROR(Status);
   4906 
   4907     if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
   4908         CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {
   4909       ValueChanged = TRUE;
   4910     }
   4911   } else {
   4912     Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
   4913     ASSERT_EFI_ERROR(Status);
   4914 
   4915     if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
   4916         CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
   4917       ValueChanged = TRUE;
   4918     }
   4919   }
   4920 
   4921   CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
   4922   if (BackUpBuffer != NULL) {
   4923     CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
   4924     FreePool (BackUpBuffer);
   4925   }
   4926 
   4927   if (BackUpBuffer2 != NULL) {
   4928     FreePool (BackUpBuffer2);
   4929   }
   4930 
   4931   Question->ValueChanged = ValueChanged;
   4932 
   4933   return ValueChanged;
   4934 }
   4935 
   4936 /**
   4937   Initialize Question's Edit copy from Storage.
   4938 
   4939   @param  Selection              Selection contains the information about
   4940                                  the Selection, form and formset to be displayed.
   4941                                  Selection action may be updated in retrieve callback.
   4942                                  If Selection is NULL, only initialize Question value.
   4943   @param  FormSet                FormSet data structure.
   4944   @param  Form                   Form data structure.
   4945 
   4946   @retval EFI_SUCCESS            The function completed successfully.
   4947 
   4948 **/
   4949 EFI_STATUS
   4950 LoadFormConfig (
   4951   IN OUT UI_MENU_SELECTION    *Selection,
   4952   IN FORM_BROWSER_FORMSET     *FormSet,
   4953   IN FORM_BROWSER_FORM        *Form
   4954   )
   4955 {
   4956   EFI_STATUS                  Status;
   4957   LIST_ENTRY                  *Link;
   4958   FORM_BROWSER_STATEMENT      *Question;
   4959 
   4960   Link = GetFirstNode (&Form->StatementListHead);
   4961   while (!IsNull (&Form->StatementListHead, Link)) {
   4962     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   4963 
   4964     //
   4965     // Initialize local copy of Value for each Question
   4966     //
   4967     if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
   4968       Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
   4969     } else {
   4970       Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
   4971     }
   4972     if (EFI_ERROR (Status)) {
   4973       return Status;
   4974     }
   4975 
   4976     if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
   4977       HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
   4978     }
   4979 
   4980     Link = GetNextNode (&Form->StatementListHead, Link);
   4981   }
   4982 
   4983   return EFI_SUCCESS;
   4984 }
   4985 
   4986 /**
   4987   Initialize Question's Edit copy from Storage for the whole Formset.
   4988 
   4989   @param  Selection              Selection contains the information about
   4990                                  the Selection, form and formset to be displayed.
   4991                                  Selection action may be updated in retrieve callback.
   4992                                  If Selection is NULL, only initialize Question value.
   4993   @param  FormSet                FormSet data structure.
   4994 
   4995   @retval EFI_SUCCESS            The function completed successfully.
   4996 
   4997 **/
   4998 EFI_STATUS
   4999 LoadFormSetConfig (
   5000   IN OUT UI_MENU_SELECTION    *Selection,
   5001   IN     FORM_BROWSER_FORMSET *FormSet
   5002   )
   5003 {
   5004   EFI_STATUS            Status;
   5005   LIST_ENTRY            *Link;
   5006   FORM_BROWSER_FORM     *Form;
   5007 
   5008   Link = GetFirstNode (&FormSet->FormListHead);
   5009   while (!IsNull (&FormSet->FormListHead, Link)) {
   5010     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   5011 
   5012     //
   5013     // Initialize local copy of Value for each Form
   5014     //
   5015     Status = LoadFormConfig (Selection, FormSet, Form);
   5016     if (EFI_ERROR (Status)) {
   5017       return Status;
   5018     }
   5019 
   5020     Link = GetNextNode (&FormSet->FormListHead, Link);
   5021   }
   5022 
   5023   //
   5024   // Finished question initialization.
   5025   //
   5026   FormSet->QuestionInited = TRUE;
   5027 
   5028   return EFI_SUCCESS;
   5029 }
   5030 
   5031 /**
   5032   Remove the Request element from the Config Request.
   5033 
   5034   @param  Storage                Pointer to the browser storage.
   5035   @param  RequestElement         The pointer to the Request element.
   5036 
   5037 **/
   5038 VOID
   5039 RemoveElement (
   5040   IN OUT BROWSER_STORAGE      *Storage,
   5041   IN     CHAR16               *RequestElement
   5042   )
   5043 {
   5044   CHAR16   *NewStr;
   5045   CHAR16   *DestStr;
   5046 
   5047   ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
   5048 
   5049   NewStr = StrStr (Storage->ConfigRequest, RequestElement);
   5050 
   5051   if (NewStr == NULL) {
   5052     return;
   5053   }
   5054 
   5055   //
   5056   // Remove this element from this ConfigRequest.
   5057   //
   5058   DestStr = NewStr;
   5059   NewStr += StrLen (RequestElement);
   5060   CopyMem (DestStr, NewStr, StrSize (NewStr));
   5061 
   5062   Storage->SpareStrLen += StrLen (RequestElement);
   5063 }
   5064 
   5065 /**
   5066   Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
   5067 
   5068   @param  Storage                Pointer to the formset storage.
   5069   @param  ConfigRequest          The pointer to the Request element.
   5070 
   5071 **/
   5072 VOID
   5073 RemoveConfigRequest (
   5074   FORMSET_STORAGE   *Storage,
   5075   CHAR16            *ConfigRequest
   5076   )
   5077 {
   5078   CHAR16       *RequestElement;
   5079   CHAR16       *NextRequestElement;
   5080   CHAR16       *SearchKey;
   5081 
   5082   //
   5083   // No request element in it, just return.
   5084   //
   5085   if (ConfigRequest == NULL) {
   5086     return;
   5087   }
   5088 
   5089   if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   5090     //
   5091     // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
   5092     //
   5093     SearchKey = L"&";
   5094   } else {
   5095     //
   5096     // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
   5097     //
   5098     SearchKey = L"&OFFSET";
   5099   }
   5100 
   5101   //
   5102   // Find SearchKey storage
   5103   //
   5104   if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   5105     RequestElement = StrStr (ConfigRequest, L"PATH");
   5106     ASSERT (RequestElement != NULL);
   5107     RequestElement = StrStr (RequestElement, SearchKey);
   5108   } else {
   5109     RequestElement = StrStr (ConfigRequest, SearchKey);
   5110   }
   5111 
   5112   while (RequestElement != NULL) {
   5113     //
   5114     // +1 to avoid find header itself.
   5115     //
   5116     NextRequestElement = StrStr (RequestElement + 1, SearchKey);
   5117 
   5118     //
   5119     // The last Request element in configRequest string.
   5120     //
   5121     if (NextRequestElement != NULL) {
   5122       //
   5123       // Replace "&" with '\0'.
   5124       //
   5125       *NextRequestElement = L'\0';
   5126     }
   5127 
   5128     RemoveElement (Storage->BrowserStorage, RequestElement);
   5129 
   5130     if (NextRequestElement != NULL) {
   5131       //
   5132       // Restore '&' with '\0' for later used.
   5133       //
   5134       *NextRequestElement = L'&';
   5135     }
   5136 
   5137     RequestElement = NextRequestElement;
   5138   }
   5139 
   5140   //
   5141   // If no request element remain, just remove the ConfigRequest string.
   5142   //
   5143   if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {
   5144     FreePool (Storage->BrowserStorage->ConfigRequest);
   5145     Storage->BrowserStorage->ConfigRequest = NULL;
   5146     Storage->BrowserStorage->SpareStrLen   = 0;
   5147   }
   5148 }
   5149 
   5150 /**
   5151   Base on the current formset info, clean the ConfigRequest string in browser storage.
   5152 
   5153   @param  FormSet                Pointer of the FormSet
   5154 
   5155 **/
   5156 VOID
   5157 CleanBrowserStorage (
   5158   IN OUT FORM_BROWSER_FORMSET  *FormSet
   5159   )
   5160 {
   5161   LIST_ENTRY            *Link;
   5162   FORMSET_STORAGE       *Storage;
   5163 
   5164   Link = GetFirstNode (&FormSet->StorageListHead);
   5165   while (!IsNull (&FormSet->StorageListHead, Link)) {
   5166     Storage = FORMSET_STORAGE_FROM_LINK (Link);
   5167     Link = GetNextNode (&FormSet->StorageListHead, Link);
   5168 
   5169     if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
   5170       if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
   5171         continue;
   5172       }
   5173 
   5174       RemoveConfigRequest (Storage, Storage->ConfigRequest);
   5175     } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
   5176                Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   5177       if (Storage->BrowserStorage->ConfigRequest != NULL) {
   5178         FreePool (Storage->BrowserStorage->ConfigRequest);
   5179         Storage->BrowserStorage->ConfigRequest = NULL;
   5180       }
   5181       Storage->BrowserStorage->Initialized = FALSE;
   5182     }
   5183   }
   5184 }
   5185 
   5186 /**
   5187   Check whether current element in the ConfigReqeust string.
   5188 
   5189   @param  BrowserStorage                Storage which includes ConfigReqeust.
   5190   @param  RequestElement                New element need to check.
   5191 
   5192   @retval TRUE        The Element is in the ConfigReqeust string.
   5193   @retval FALSE       The Element not in the configReqeust String.
   5194 
   5195 **/
   5196 BOOLEAN
   5197 ElementValidation (
   5198   BROWSER_STORAGE   *BrowserStorage,
   5199   CHAR16            *RequestElement
   5200   )
   5201 {
   5202   return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
   5203 }
   5204 
   5205 /**
   5206   Append the Request element to the Config Request.
   5207 
   5208   @param  ConfigRequest          Current ConfigRequest info.
   5209   @param  SpareStrLen            Current remain free buffer for config reqeust.
   5210   @param  RequestElement         New Request element.
   5211 
   5212 **/
   5213 VOID
   5214 AppendConfigRequest (
   5215   IN OUT CHAR16               **ConfigRequest,
   5216   IN OUT UINTN                *SpareStrLen,
   5217   IN     CHAR16               *RequestElement
   5218   )
   5219 {
   5220   CHAR16   *NewStr;
   5221   UINTN    StringSize;
   5222   UINTN    StrLength;
   5223   UINTN    MaxLen;
   5224 
   5225   StrLength = StrLen (RequestElement);
   5226   StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
   5227   MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen;
   5228 
   5229   //
   5230   // Append <RequestElement> to <ConfigRequest>
   5231   //
   5232   if (StrLength > *SpareStrLen) {
   5233     //
   5234     // Old String buffer is not sufficient for RequestElement, allocate a new one
   5235     //
   5236     MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
   5237     NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   5238     ASSERT (NewStr != NULL);
   5239 
   5240     if (*ConfigRequest != NULL) {
   5241       CopyMem (NewStr, *ConfigRequest, StringSize);
   5242       FreePool (*ConfigRequest);
   5243     }
   5244     *ConfigRequest = NewStr;
   5245     *SpareStrLen   = CONFIG_REQUEST_STRING_INCREMENTAL;
   5246   }
   5247 
   5248   StrCatS (*ConfigRequest, MaxLen, RequestElement);
   5249   *SpareStrLen -= StrLength;
   5250 }
   5251 
   5252 /**
   5253   Adjust the config request info, remove the request elements which already in AllConfigRequest string.
   5254 
   5255   @param  Storage                Form set Storage.
   5256   @param  Request                The input request string.
   5257   @param  RespString             Whether the input is ConfigRequest or ConfigResp format.
   5258 
   5259   @retval TRUE                   Has element not covered by current used elements, need to continue to call ExtractConfig
   5260   @retval FALSE                  All elements covered by current used elements.
   5261 
   5262 **/
   5263 BOOLEAN
   5264 ConfigRequestAdjust (
   5265   IN  BROWSER_STORAGE         *Storage,
   5266   IN  CHAR16                  *Request,
   5267   IN  BOOLEAN                 RespString
   5268   )
   5269 {
   5270   CHAR16       *RequestElement;
   5271   CHAR16       *NextRequestElement;
   5272   CHAR16       *NextElementBakup;
   5273   CHAR16       *SearchKey;
   5274   CHAR16       *ValueKey;
   5275   BOOLEAN      RetVal;
   5276   CHAR16       *ConfigRequest;
   5277 
   5278   RetVal         = FALSE;
   5279   NextElementBakup = NULL;
   5280   ValueKey         = NULL;
   5281 
   5282   if (Request != NULL) {
   5283     ConfigRequest = Request;
   5284   } else {
   5285     ConfigRequest = Storage->ConfigRequest;
   5286   }
   5287 
   5288   if (Storage->ConfigRequest == NULL) {
   5289     Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
   5290     return TRUE;
   5291   }
   5292 
   5293   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   5294     //
   5295     // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
   5296     //
   5297     SearchKey = L"&";
   5298   } else {
   5299     //
   5300     // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
   5301     //
   5302     SearchKey = L"&OFFSET";
   5303     ValueKey  = L"&VALUE";
   5304   }
   5305 
   5306   //
   5307   // Find SearchKey storage
   5308   //
   5309   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
   5310     RequestElement = StrStr (ConfigRequest, L"PATH");
   5311     ASSERT (RequestElement != NULL);
   5312     RequestElement = StrStr (RequestElement, SearchKey);
   5313   } else {
   5314     RequestElement = StrStr (ConfigRequest, SearchKey);
   5315   }
   5316 
   5317   while (RequestElement != NULL) {
   5318 
   5319     //
   5320     // +1 to avoid find header itself.
   5321     //
   5322     NextRequestElement = StrStr (RequestElement + 1, SearchKey);
   5323 
   5324     //
   5325     // The last Request element in configRequest string.
   5326     //
   5327     if (NextRequestElement != NULL) {
   5328       if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   5329         NextElementBakup = NextRequestElement;
   5330         NextRequestElement = StrStr (RequestElement, ValueKey);
   5331         ASSERT (NextRequestElement != NULL);
   5332       }
   5333       //
   5334       // Replace "&" with '\0'.
   5335       //
   5336       *NextRequestElement = L'\0';
   5337     } else {
   5338       if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   5339         NextElementBakup = NextRequestElement;
   5340         NextRequestElement = StrStr (RequestElement, ValueKey);
   5341         ASSERT (NextRequestElement != NULL);
   5342         //
   5343         // Replace "&" with '\0'.
   5344         //
   5345         *NextRequestElement = L'\0';
   5346       }
   5347     }
   5348 
   5349     if (!ElementValidation (Storage, RequestElement)) {
   5350       //
   5351       // Add this element to the Storage->BrowserStorage->AllRequestElement.
   5352       //
   5353       AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
   5354       RetVal = TRUE;
   5355     }
   5356 
   5357     if (NextRequestElement != NULL) {
   5358       //
   5359       // Restore '&' with '\0' for later used.
   5360       //
   5361       *NextRequestElement = L'&';
   5362     }
   5363 
   5364     if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
   5365       RequestElement = NextElementBakup;
   5366     } else {
   5367       RequestElement = NextRequestElement;
   5368     }
   5369   }
   5370 
   5371   return RetVal;
   5372 }
   5373 
   5374 /**
   5375   Fill storage's edit copy with settings requested from Configuration Driver.
   5376 
   5377   @param  FormSet                FormSet data structure.
   5378   @param  Storage                Buffer Storage.
   5379 
   5380 **/
   5381 VOID
   5382 LoadStorage (
   5383   IN FORM_BROWSER_FORMSET    *FormSet,
   5384   IN FORMSET_STORAGE         *Storage
   5385   )
   5386 {
   5387   EFI_STATUS  Status;
   5388   EFI_STRING  Progress;
   5389   EFI_STRING  Result;
   5390   CHAR16      *StrPtr;
   5391   EFI_STRING  ConfigRequest;
   5392   UINTN       StrLen;
   5393 
   5394   ConfigRequest = NULL;
   5395 
   5396   switch (Storage->BrowserStorage->Type) {
   5397     case EFI_HII_VARSTORE_EFI_VARIABLE:
   5398       return;
   5399 
   5400     case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
   5401       if (Storage->BrowserStorage->ConfigRequest != NULL) {
   5402         ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
   5403         return;
   5404       }
   5405       break;
   5406 
   5407     case EFI_HII_VARSTORE_BUFFER:
   5408     case EFI_HII_VARSTORE_NAME_VALUE:
   5409       //
   5410       // Skip if there is no RequestElement.
   5411       //
   5412       if (Storage->ElementCount == 0) {
   5413         return;
   5414       }
   5415 
   5416       //
   5417       // Just update the ConfigRequest, if storage already initialized.
   5418       //
   5419       if (Storage->BrowserStorage->Initialized) {
   5420         ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
   5421         return;
   5422       }
   5423 
   5424       Storage->BrowserStorage->Initialized = TRUE;
   5425       break;
   5426 
   5427     default:
   5428       return;
   5429   }
   5430 
   5431   if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
   5432     //
   5433     // Create the config request string to get all fields for this storage.
   5434     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
   5435     // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
   5436     //
   5437     StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);
   5438     ConfigRequest = AllocateZeroPool (StrLen);
   5439     ASSERT (ConfigRequest != NULL);
   5440     UnicodeSPrint (
   5441                ConfigRequest,
   5442                StrLen,
   5443                L"%s&OFFSET=0&WIDTH=%04x",
   5444                Storage->ConfigHdr,
   5445                Storage->BrowserStorage->Size);
   5446   } else {
   5447     ConfigRequest = Storage->ConfigRequest;
   5448   }
   5449 
   5450   //
   5451   // Request current settings from Configuration Driver
   5452   //
   5453   Status = mHiiConfigRouting->ExtractConfig (
   5454                                     mHiiConfigRouting,
   5455                                     ConfigRequest,
   5456                                     &Progress,
   5457                                     &Result
   5458                                     );
   5459 
   5460   //
   5461   // If get value fail, extract default from IFR binary
   5462   //
   5463   if (EFI_ERROR (Status)) {
   5464     ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
   5465   } else {
   5466     //
   5467     // Convert Result from <ConfigAltResp> to <ConfigResp>
   5468     //
   5469     StrPtr = StrStr (Result, L"&GUID=");
   5470     if (StrPtr != NULL) {
   5471       *StrPtr = L'\0';
   5472     }
   5473 
   5474     Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
   5475     FreePool (Result);
   5476   }
   5477 
   5478   Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
   5479 
   5480   //
   5481   // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
   5482   //
   5483   SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);
   5484 
   5485   if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
   5486     if (ConfigRequest != NULL) {
   5487       FreePool (ConfigRequest);
   5488     }
   5489   }
   5490 }
   5491 
   5492 /**
   5493   Get Value changed status from old question.
   5494 
   5495   @param  NewFormSet                FormSet data structure.
   5496   @param  OldQuestion               Old question which has value changed.
   5497 
   5498 **/
   5499 VOID
   5500 SyncStatusForQuestion (
   5501   IN OUT FORM_BROWSER_FORMSET             *NewFormSet,
   5502   IN     FORM_BROWSER_STATEMENT           *OldQuestion
   5503   )
   5504 {
   5505   LIST_ENTRY                  *Link;
   5506   LIST_ENTRY                  *QuestionLink;
   5507   FORM_BROWSER_FORM           *Form;
   5508   FORM_BROWSER_STATEMENT      *Question;
   5509 
   5510   //
   5511   // For each form in one formset.
   5512   //
   5513   Link = GetFirstNode (&NewFormSet->FormListHead);
   5514   while (!IsNull (&NewFormSet->FormListHead, Link)) {
   5515     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   5516     Link = GetNextNode (&NewFormSet->FormListHead, Link);
   5517 
   5518     //
   5519     // for each question in one form.
   5520     //
   5521     QuestionLink = GetFirstNode (&Form->StatementListHead);
   5522     while (!IsNull (&Form->StatementListHead, QuestionLink)) {
   5523       Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
   5524       QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
   5525 
   5526       if (Question->QuestionId == OldQuestion->QuestionId) {
   5527         Question->ValueChanged = TRUE;
   5528         return;
   5529       }
   5530     }
   5531   }
   5532 }
   5533 
   5534 /**
   5535   Get Value changed status from old formset.
   5536 
   5537   @param  NewFormSet                FormSet data structure.
   5538   @param  OldFormSet                FormSet data structure.
   5539 
   5540 **/
   5541 VOID
   5542 SyncStatusForFormSet (
   5543   IN OUT FORM_BROWSER_FORMSET             *NewFormSet,
   5544   IN     FORM_BROWSER_FORMSET             *OldFormSet
   5545   )
   5546 {
   5547   LIST_ENTRY                  *Link;
   5548   LIST_ENTRY                  *QuestionLink;
   5549   FORM_BROWSER_FORM           *Form;
   5550   FORM_BROWSER_STATEMENT      *Question;
   5551 
   5552   //
   5553   // For each form in one formset.
   5554   //
   5555   Link = GetFirstNode (&OldFormSet->FormListHead);
   5556   while (!IsNull (&OldFormSet->FormListHead, Link)) {
   5557     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   5558     Link = GetNextNode (&OldFormSet->FormListHead, Link);
   5559 
   5560     //
   5561     // for each question in one form.
   5562     //
   5563     QuestionLink = GetFirstNode (&Form->StatementListHead);
   5564     while (!IsNull (&Form->StatementListHead, QuestionLink)) {
   5565       Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
   5566       QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
   5567 
   5568       if (!Question->ValueChanged) {
   5569         continue;
   5570       }
   5571 
   5572       //
   5573       // Find the same question in new formset and update the value changed flag.
   5574       //
   5575       SyncStatusForQuestion (NewFormSet, Question);
   5576     }
   5577   }
   5578 }
   5579 
   5580 /**
   5581   Get current setting of Questions.
   5582 
   5583   @param  FormSet                FormSet data structure.
   5584 
   5585 **/
   5586 VOID
   5587 InitializeCurrentSetting (
   5588   IN OUT FORM_BROWSER_FORMSET             *FormSet
   5589   )
   5590 {
   5591   LIST_ENTRY              *Link;
   5592   FORMSET_STORAGE         *Storage;
   5593   FORM_BROWSER_FORMSET    *OldFormSet;
   5594 
   5595   //
   5596   // Try to find pre FormSet in the maintain backup list.
   5597   // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
   5598   //
   5599   OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
   5600   if (OldFormSet != NULL) {
   5601     SyncStatusForFormSet (FormSet, OldFormSet);
   5602     RemoveEntryList (&OldFormSet->Link);
   5603     DestroyFormSet (OldFormSet);
   5604   }
   5605   InsertTailList (&gBrowserFormSetList, &FormSet->Link);
   5606 
   5607   //
   5608   // Extract default from IFR binary for no storage questions.
   5609   //
   5610   ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
   5611 
   5612   //
   5613   // Request current settings from Configuration Driver
   5614   //
   5615   Link = GetFirstNode (&FormSet->StorageListHead);
   5616   while (!IsNull (&FormSet->StorageListHead, Link)) {
   5617     Storage = FORMSET_STORAGE_FROM_LINK (Link);
   5618 
   5619     LoadStorage (FormSet, Storage);
   5620 
   5621     Link = GetNextNode (&FormSet->StorageListHead, Link);
   5622   }
   5623 }
   5624 
   5625 
   5626 /**
   5627   Fetch the Ifr binary data of a FormSet.
   5628 
   5629   @param  Handle                 PackageList Handle
   5630   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
   5631                                  specified (NULL or zero GUID), take the first
   5632                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
   5633                                  found in package list.
   5634                                  On output, GUID of the formset found(if not NULL).
   5635   @param  BinaryLength           The length of the FormSet IFR binary.
   5636   @param  BinaryData             The buffer designed to receive the FormSet.
   5637 
   5638   @retval EFI_SUCCESS            Buffer filled with the requested FormSet.
   5639                                  BufferLength was updated.
   5640   @retval EFI_INVALID_PARAMETER  The handle is unknown.
   5641   @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot
   5642                                  be found with the requested FormId.
   5643 
   5644 **/
   5645 EFI_STATUS
   5646 GetIfrBinaryData (
   5647   IN  EFI_HII_HANDLE   Handle,
   5648   IN OUT EFI_GUID      *FormSetGuid,
   5649   OUT UINTN            *BinaryLength,
   5650   OUT UINT8            **BinaryData
   5651   )
   5652 {
   5653   EFI_STATUS                   Status;
   5654   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
   5655   UINTN                        BufferSize;
   5656   UINT8                        *Package;
   5657   UINT8                        *OpCodeData;
   5658   UINT32                       Offset;
   5659   UINT32                       Offset2;
   5660   UINT32                       PackageListLength;
   5661   EFI_HII_PACKAGE_HEADER       PackageHeader;
   5662   UINT8                        Index;
   5663   UINT8                        NumberOfClassGuid;
   5664   BOOLEAN                      ClassGuidMatch;
   5665   EFI_GUID                     *ClassGuid;
   5666   EFI_GUID                     *ComparingGuid;
   5667 
   5668   OpCodeData = NULL;
   5669   Package = NULL;
   5670   ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
   5671 
   5672   //
   5673   // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
   5674   //
   5675   if (FormSetGuid == NULL) {
   5676     ComparingGuid = &gZeroGuid;
   5677   } else {
   5678     ComparingGuid = FormSetGuid;
   5679   }
   5680 
   5681   //
   5682   // Get HII PackageList
   5683   //
   5684   BufferSize = 0;
   5685   HiiPackageList = NULL;
   5686   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
   5687   if (Status == EFI_BUFFER_TOO_SMALL) {
   5688     HiiPackageList = AllocatePool (BufferSize);
   5689     ASSERT (HiiPackageList != NULL);
   5690 
   5691     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
   5692   }
   5693   if (EFI_ERROR (Status)) {
   5694     return Status;
   5695   }
   5696   ASSERT (HiiPackageList != NULL);
   5697 
   5698   //
   5699   // Get Form package from this HII package List
   5700   //
   5701   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
   5702   Offset2 = 0;
   5703   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
   5704 
   5705   ClassGuidMatch = FALSE;
   5706   while (Offset < PackageListLength) {
   5707     Package = ((UINT8 *) HiiPackageList) + Offset;
   5708     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
   5709 
   5710     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
   5711       //
   5712       // Search FormSet in this Form Package
   5713       //
   5714       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
   5715       while (Offset2 < PackageHeader.Length) {
   5716         OpCodeData = Package + Offset2;
   5717 
   5718         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
   5719           //
   5720           // Try to compare against formset GUID
   5721           //
   5722           if (IsZeroGuid (FormSetGuid) ||
   5723               CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
   5724             break;
   5725           }
   5726 
   5727           if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
   5728             //
   5729             // Try to compare against formset class GUID
   5730             //
   5731             NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
   5732             ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
   5733             for (Index = 0; Index < NumberOfClassGuid; Index++) {
   5734               if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
   5735                 ClassGuidMatch = TRUE;
   5736                 break;
   5737               }
   5738             }
   5739             if (ClassGuidMatch) {
   5740               break;
   5741             }
   5742           } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
   5743             ClassGuidMatch = TRUE;
   5744             break;
   5745           }
   5746         }
   5747 
   5748         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
   5749       }
   5750 
   5751       if (Offset2 < PackageHeader.Length) {
   5752         //
   5753         // Target formset found
   5754         //
   5755         break;
   5756       }
   5757     }
   5758 
   5759     Offset += PackageHeader.Length;
   5760   }
   5761 
   5762   if (Offset >= PackageListLength) {
   5763     //
   5764     // Form package not found in this Package List
   5765     //
   5766     FreePool (HiiPackageList);
   5767     return EFI_NOT_FOUND;
   5768   }
   5769 
   5770   if (FormSetGuid != NULL) {
   5771     //
   5772     // Return the FormSet GUID
   5773     //
   5774     CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
   5775   }
   5776 
   5777   //
   5778   // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
   5779   // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
   5780   // of the Form Package.
   5781   //
   5782   *BinaryLength = PackageHeader.Length - Offset2;
   5783   *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
   5784 
   5785   FreePool (HiiPackageList);
   5786 
   5787   if (*BinaryData == NULL) {
   5788     return EFI_OUT_OF_RESOURCES;
   5789   }
   5790 
   5791   return EFI_SUCCESS;
   5792 }
   5793 
   5794 
   5795 /**
   5796   Initialize the internal data structure of a FormSet.
   5797 
   5798   @param  Handle                 PackageList Handle
   5799   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
   5800                                  specified (NULL or zero GUID), take the first
   5801                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
   5802                                  found in package list.
   5803                                  On output, GUID of the formset found(if not NULL).
   5804   @param  FormSet                FormSet data structure.
   5805 
   5806   @retval EFI_SUCCESS            The function completed successfully.
   5807   @retval EFI_NOT_FOUND          The specified FormSet could not be found.
   5808 
   5809 **/
   5810 EFI_STATUS
   5811 InitializeFormSet (
   5812   IN  EFI_HII_HANDLE                   Handle,
   5813   IN OUT EFI_GUID                      *FormSetGuid,
   5814   OUT FORM_BROWSER_FORMSET             *FormSet
   5815   )
   5816 {
   5817   EFI_STATUS                Status;
   5818   EFI_HANDLE                DriverHandle;
   5819 
   5820   Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
   5821   if (EFI_ERROR (Status)) {
   5822     return Status;
   5823   }
   5824 
   5825   FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
   5826   FormSet->HiiHandle = Handle;
   5827   CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
   5828   FormSet->QuestionInited = FALSE;
   5829 
   5830   //
   5831   // Retrieve ConfigAccess Protocol associated with this HiiPackageList
   5832   //
   5833   Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
   5834   if (EFI_ERROR (Status)) {
   5835     return Status;
   5836   }
   5837   FormSet->DriverHandle = DriverHandle;
   5838   Status = gBS->HandleProtocol (
   5839                   DriverHandle,
   5840                   &gEfiHiiConfigAccessProtocolGuid,
   5841                   (VOID **) &FormSet->ConfigAccess
   5842                   );
   5843   if (EFI_ERROR (Status)) {
   5844     //
   5845     // Configuration Driver don't attach ConfigAccess protocol to its HII package
   5846     // list, then there will be no configuration action required
   5847     //
   5848     FormSet->ConfigAccess = NULL;
   5849   }
   5850 
   5851   //
   5852   // Parse the IFR binary OpCodes
   5853   //
   5854   Status = ParseOpCodes (FormSet);
   5855 
   5856   return Status;
   5857 }
   5858 
   5859 
   5860 /**
   5861   Save globals used by previous call to SendForm(). SendForm() may be called from
   5862   HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
   5863   So, save globals of previous call to SendForm() and restore them upon exit.
   5864 
   5865 **/
   5866 VOID
   5867 SaveBrowserContext (
   5868   VOID
   5869   )
   5870 {
   5871   BROWSER_CONTEXT      *Context;
   5872   FORM_ENTRY_INFO      *MenuList;
   5873   FORM_BROWSER_FORMSET *FormSet;
   5874 
   5875   gBrowserContextCount++;
   5876   if (gBrowserContextCount == 1) {
   5877     //
   5878     // This is not reentry of SendForm(), no context to save
   5879     //
   5880     return;
   5881   }
   5882 
   5883   Context = AllocatePool (sizeof (BROWSER_CONTEXT));
   5884   ASSERT (Context != NULL);
   5885 
   5886   Context->Signature = BROWSER_CONTEXT_SIGNATURE;
   5887 
   5888   //
   5889   // Save FormBrowser context
   5890   //
   5891   Context->Selection            = gCurrentSelection;
   5892   Context->ResetRequired        = gResetRequired;
   5893   Context->FlagReconnect        = gFlagReconnect;
   5894   Context->CallbackReconnect    = gCallbackReconnect;
   5895   Context->ExitRequired         = gExitRequired;
   5896   Context->HiiHandle            = mCurrentHiiHandle;
   5897   Context->FormId               = mCurrentFormId;
   5898   CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
   5899   Context->SystemLevelFormSet   = mSystemLevelFormSet;
   5900   Context->CurFakeQestId        = mCurFakeQestId;
   5901   Context->HiiPackageListUpdated = mHiiPackageListUpdated;
   5902   Context->FinishRetrieveCall   = mFinishRetrieveCall;
   5903 
   5904   //
   5905   // Save the menu history data.
   5906   //
   5907   InitializeListHead(&Context->FormHistoryList);
   5908   while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
   5909     MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
   5910     RemoveEntryList (&MenuList->Link);
   5911 
   5912     InsertTailList(&Context->FormHistoryList, &MenuList->Link);
   5913   }
   5914 
   5915   //
   5916   // Save formset list.
   5917   //
   5918   InitializeListHead(&Context->FormSetList);
   5919   while (!IsListEmpty (&gBrowserFormSetList)) {
   5920     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink);
   5921     RemoveEntryList (&FormSet->Link);
   5922 
   5923     InsertTailList(&Context->FormSetList, &FormSet->Link);
   5924   }
   5925 
   5926   //
   5927   // Insert to FormBrowser context list
   5928   //
   5929   InsertHeadList (&gBrowserContextList, &Context->Link);
   5930 }
   5931 
   5932 
   5933 /**
   5934   Restore globals used by previous call to SendForm().
   5935 
   5936 **/
   5937 VOID
   5938 RestoreBrowserContext (
   5939   VOID
   5940   )
   5941 {
   5942   LIST_ENTRY       *Link;
   5943   BROWSER_CONTEXT  *Context;
   5944   FORM_ENTRY_INFO      *MenuList;
   5945   FORM_BROWSER_FORMSET *FormSet;
   5946 
   5947   ASSERT (gBrowserContextCount != 0);
   5948   gBrowserContextCount--;
   5949   if (gBrowserContextCount == 0) {
   5950     //
   5951     // This is not reentry of SendForm(), no context to restore
   5952     //
   5953     return;
   5954   }
   5955 
   5956   ASSERT (!IsListEmpty (&gBrowserContextList));
   5957 
   5958   Link = GetFirstNode (&gBrowserContextList);
   5959   Context = BROWSER_CONTEXT_FROM_LINK (Link);
   5960 
   5961   //
   5962   // Restore FormBrowser context
   5963   //
   5964   gCurrentSelection     = Context->Selection;
   5965   gResetRequired        = Context->ResetRequired;
   5966   gFlagReconnect        = Context->FlagReconnect;
   5967   gCallbackReconnect    = Context->CallbackReconnect;
   5968   gExitRequired         = Context->ExitRequired;
   5969   mCurrentHiiHandle     = Context->HiiHandle;
   5970   mCurrentFormId        = Context->FormId;
   5971   CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
   5972   mSystemLevelFormSet   = Context->SystemLevelFormSet;
   5973   mCurFakeQestId        = Context->CurFakeQestId;
   5974   mHiiPackageListUpdated = Context->HiiPackageListUpdated;
   5975   mFinishRetrieveCall   = Context->FinishRetrieveCall;
   5976 
   5977   //
   5978   // Restore the menu history data.
   5979   //
   5980   while (!IsListEmpty (&Context->FormHistoryList)) {
   5981     MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
   5982     RemoveEntryList (&MenuList->Link);
   5983 
   5984     InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
   5985   }
   5986 
   5987   //
   5988   // Restore the Formset data.
   5989   //
   5990   while (!IsListEmpty (&Context->FormSetList)) {
   5991     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink);
   5992     RemoveEntryList (&FormSet->Link);
   5993 
   5994     InsertTailList(&gBrowserFormSetList, &FormSet->Link);
   5995   }
   5996 
   5997   //
   5998   // Remove from FormBrowser context list
   5999   //
   6000   RemoveEntryList (&Context->Link);
   6001   gBS->FreePool (Context);
   6002 }
   6003 
   6004 /**
   6005   Find the matched FormSet context in the backup maintain list based on HiiHandle.
   6006 
   6007   @param Handle  The Hii Handle.
   6008 
   6009   @return the found FormSet context. If no found, NULL will return.
   6010 
   6011 **/
   6012 FORM_BROWSER_FORMSET *
   6013 GetFormSetFromHiiHandle (
   6014   EFI_HII_HANDLE Handle
   6015   )
   6016 {
   6017   LIST_ENTRY           *Link;
   6018   FORM_BROWSER_FORMSET *FormSet;
   6019 
   6020   Link = GetFirstNode (&gBrowserFormSetList);
   6021   while (!IsNull (&gBrowserFormSetList, Link)) {
   6022     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   6023     Link = GetNextNode (&gBrowserFormSetList, Link);
   6024     if (!ValidateFormSet(FormSet)) {
   6025       continue;
   6026     }
   6027     if (FormSet->HiiHandle == Handle) {
   6028       return FormSet;
   6029     }
   6030   }
   6031 
   6032   return NULL;
   6033 }
   6034 
   6035 /**
   6036   Check whether the input HII handle is the FormSet that is being used.
   6037 
   6038   @param Handle  The Hii Handle.
   6039 
   6040   @retval TRUE   HII handle is being used.
   6041   @retval FALSE  HII handle is not being used.
   6042 
   6043 **/
   6044 BOOLEAN
   6045 IsHiiHandleInBrowserContext (
   6046   EFI_HII_HANDLE Handle
   6047   )
   6048 {
   6049   LIST_ENTRY       *Link;
   6050   BROWSER_CONTEXT  *Context;
   6051 
   6052   //
   6053   // HiiHandle is Current FormSet.
   6054   //
   6055   if (mCurrentHiiHandle == Handle) {
   6056     return TRUE;
   6057   }
   6058 
   6059   //
   6060   // Check whether HiiHandle is in BrowserContext.
   6061   //
   6062   Link = GetFirstNode (&gBrowserContextList);
   6063   while (!IsNull (&gBrowserContextList, Link)) {
   6064     Context = BROWSER_CONTEXT_FROM_LINK (Link);
   6065     if (Context->HiiHandle == Handle) {
   6066       //
   6067       // HiiHandle is in BrowserContext
   6068       //
   6069       return TRUE;
   6070     }
   6071     Link = GetNextNode (&gBrowserContextList, Link);
   6072   }
   6073 
   6074   return FALSE;
   6075 }
   6076 
   6077 /**
   6078   Perform Password check.
   6079   Passwork may be encrypted by driver that requires the specific check.
   6080 
   6081   @param  Form             Form where Password Statement is in.
   6082   @param  Statement        Password statement
   6083   @param  PasswordString   Password string to be checked. It may be NULL.
   6084                            NULL means to restore password.
   6085                            "" string can be used to checked whether old password does exist.
   6086 
   6087   @return Status     Status of Password check.
   6088 **/
   6089 EFI_STATUS
   6090 EFIAPI
   6091 PasswordCheck (
   6092   IN FORM_DISPLAY_ENGINE_FORM      *Form,
   6093   IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
   6094   IN EFI_STRING                    PasswordString  OPTIONAL
   6095   )
   6096 {
   6097   EFI_STATUS                      Status;
   6098   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   6099   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   6100   EFI_IFR_TYPE_VALUE              IfrTypeValue;
   6101   FORM_BROWSER_STATEMENT          *Question;
   6102 
   6103   ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
   6104   Question = GetBrowserStatement(Statement);
   6105   ASSERT (Question != NULL);
   6106 
   6107   if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
   6108     if (ConfigAccess == NULL) {
   6109       return EFI_UNSUPPORTED;
   6110     }
   6111   } else {
   6112     //
   6113     // If a password doesn't have the CALLBACK flag, browser will not handle it.
   6114     //
   6115     return EFI_UNSUPPORTED;
   6116   }
   6117 
   6118   //
   6119   // Prepare password string in HII database
   6120   //
   6121   if (PasswordString != NULL) {
   6122     IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
   6123   } else {
   6124     IfrTypeValue.string = 0;
   6125   }
   6126 
   6127   //
   6128   // Send password to Configuration Driver for validation
   6129   //
   6130   Status = ConfigAccess->Callback (
   6131                            ConfigAccess,
   6132                            EFI_BROWSER_ACTION_CHANGING,
   6133                            Question->QuestionId,
   6134                            Question->HiiValue.Type,
   6135                            &IfrTypeValue,
   6136                            &ActionRequest
   6137                            );
   6138 
   6139   //
   6140   // Remove password string from HII database
   6141   //
   6142   if (PasswordString != NULL) {
   6143     DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
   6144   }
   6145 
   6146   return Status;
   6147 }
   6148 
   6149 /**
   6150   Find the registered HotKey based on KeyData.
   6151 
   6152   @param[in] KeyData     A pointer to a buffer that describes the keystroke
   6153                          information for the hot key.
   6154 
   6155   @return The registered HotKey context. If no found, NULL will return.
   6156 **/
   6157 BROWSER_HOT_KEY *
   6158 GetHotKeyFromRegisterList (
   6159   IN EFI_INPUT_KEY *KeyData
   6160   )
   6161 {
   6162   LIST_ENTRY       *Link;
   6163   BROWSER_HOT_KEY  *HotKey;
   6164 
   6165   Link = GetFirstNode (&gBrowserHotKeyList);
   6166   while (!IsNull (&gBrowserHotKeyList, Link)) {
   6167     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
   6168     if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
   6169       return HotKey;
   6170     }
   6171     Link = GetNextNode (&gBrowserHotKeyList, Link);
   6172   }
   6173 
   6174   return NULL;
   6175 }
   6176 
   6177 /**
   6178   Configure what scope the hot key will impact.
   6179   All hot keys have the same scope. The mixed hot keys with the different level are not supported.
   6180   If no scope is set, the default scope will be FormSet level.
   6181   After all registered hot keys are removed, previous Scope can reset to another level.
   6182 
   6183   @param[in] Scope               Scope level to be set.
   6184 
   6185   @retval EFI_SUCCESS            Scope is set correctly.
   6186   @retval EFI_INVALID_PARAMETER  Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
   6187   @retval EFI_UNSPPORTED         Scope level is different from current one that the registered hot keys have.
   6188 
   6189 **/
   6190 EFI_STATUS
   6191 EFIAPI
   6192 SetScope (
   6193   IN BROWSER_SETTING_SCOPE Scope
   6194   )
   6195 {
   6196   if (Scope >= MaxLevel) {
   6197     return EFI_INVALID_PARAMETER;
   6198   }
   6199 
   6200   //
   6201   // When no hot key registered in system or on the first setting,
   6202   // Scope can be set.
   6203   //
   6204   if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
   6205     gBrowserSettingScope  = Scope;
   6206     mBrowserScopeFirstSet = FALSE;
   6207   } else if (Scope != gBrowserSettingScope) {
   6208     return EFI_UNSUPPORTED;
   6209   }
   6210 
   6211   return EFI_SUCCESS;
   6212 }
   6213 
   6214 /**
   6215   Register the hot key with its browser action, or unregistered the hot key.
   6216   Only support hot key that is not printable character (control key, function key, etc.).
   6217   If the action value is zero, the hot key will be unregistered if it has been registered.
   6218   If the same hot key has been registered, the new action and help string will override the previous ones.
   6219 
   6220   @param[in] KeyData     A pointer to a buffer that describes the keystroke
   6221                          information for the hot key. Its type is EFI_INPUT_KEY to
   6222                          be supported by all ConsoleIn devices.
   6223   @param[in] Action      Action value that describes what action will be trigged when the hot key is pressed.
   6224   @param[in] DefaultId   Specifies the type of defaults to retrieve, which is only for DEFAULT action.
   6225   @param[in] HelpString  Help string that describes the hot key information.
   6226                          Its value may be NULL for the unregistered hot key.
   6227 
   6228   @retval EFI_SUCCESS            Hot key is registered or unregistered.
   6229   @retval EFI_INVALID_PARAMETER  KeyData is NULL or HelpString is NULL on register.
   6230   @retval EFI_NOT_FOUND          KeyData is not found to be unregistered.
   6231   @retval EFI_UNSUPPORTED        Key represents a printable character. It is conflicted with Browser.
   6232   @retval EFI_ALREADY_STARTED    Key already been registered for one hot key.
   6233 **/
   6234 EFI_STATUS
   6235 EFIAPI
   6236 RegisterHotKey (
   6237   IN EFI_INPUT_KEY *KeyData,
   6238   IN UINT32        Action,
   6239   IN UINT16        DefaultId,
   6240   IN EFI_STRING    HelpString OPTIONAL
   6241   )
   6242 {
   6243   BROWSER_HOT_KEY  *HotKey;
   6244 
   6245   //
   6246   // Check input parameters.
   6247   //
   6248   if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
   6249      (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
   6250     return EFI_INVALID_PARAMETER;
   6251   }
   6252 
   6253   //
   6254   // Check whether the input KeyData is in BrowserHotKeyList.
   6255   //
   6256   HotKey = GetHotKeyFromRegisterList (KeyData);
   6257 
   6258   //
   6259   // Unregister HotKey
   6260   //
   6261   if (Action == BROWSER_ACTION_UNREGISTER) {
   6262     if (HotKey != NULL) {
   6263       //
   6264       // The registered HotKey is found.
   6265       // Remove it from List, and free its resource.
   6266       //
   6267       RemoveEntryList (&HotKey->Link);
   6268       FreePool (HotKey->KeyData);
   6269       FreePool (HotKey->HelpString);
   6270       return EFI_SUCCESS;
   6271     } else {
   6272       //
   6273       // The registered HotKey is not found.
   6274       //
   6275       return EFI_NOT_FOUND;
   6276     }
   6277   }
   6278 
   6279   if (HotKey != NULL) {
   6280     return EFI_ALREADY_STARTED;
   6281   }
   6282 
   6283   //
   6284   // Create new Key, and add it into List.
   6285   //
   6286   HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
   6287   ASSERT (HotKey != NULL);
   6288   HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
   6289   HotKey->KeyData   = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
   6290   InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
   6291 
   6292   //
   6293   // Fill HotKey information.
   6294   //
   6295   HotKey->Action     = Action;
   6296   HotKey->DefaultId  = DefaultId;
   6297   if (HotKey->HelpString != NULL) {
   6298     FreePool (HotKey->HelpString);
   6299   }
   6300   HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
   6301 
   6302   return EFI_SUCCESS;
   6303 }
   6304 
   6305 /**
   6306   Register Exit handler function.
   6307   When more than one handler function is registered, the latter one will override the previous one.
   6308   When NULL handler is specified, the previous Exit handler will be unregistered.
   6309 
   6310   @param[in] Handler      Pointer to handler function.
   6311 
   6312 **/
   6313 VOID
   6314 EFIAPI
   6315 RegiserExitHandler (
   6316   IN EXIT_HANDLER Handler
   6317   )
   6318 {
   6319   ExitHandlerFunction = Handler;
   6320   return;
   6321 }
   6322 
   6323 /**
   6324   Check whether the browser data has been modified.
   6325 
   6326   @retval TRUE        Browser data is modified.
   6327   @retval FALSE       No browser data is modified.
   6328 
   6329 **/
   6330 BOOLEAN
   6331 EFIAPI
   6332 IsBrowserDataModified (
   6333   VOID
   6334   )
   6335 {
   6336   LIST_ENTRY              *Link;
   6337   FORM_BROWSER_FORMSET    *FormSet;
   6338 
   6339   switch (gBrowserSettingScope) {
   6340     case FormLevel:
   6341       if (gCurrentSelection == NULL) {
   6342         return FALSE;
   6343       }
   6344       return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
   6345 
   6346     case FormSetLevel:
   6347       if (gCurrentSelection == NULL) {
   6348         return FALSE;
   6349       }
   6350       return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
   6351 
   6352     case SystemLevel:
   6353       Link = GetFirstNode (&gBrowserFormSetList);
   6354       while (!IsNull (&gBrowserFormSetList, Link)) {
   6355         FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   6356         if (!ValidateFormSet(FormSet)) {
   6357           continue;
   6358         }
   6359 
   6360         if (IsNvUpdateRequiredForFormSet (FormSet)) {
   6361           return TRUE;
   6362         }
   6363         Link = GetNextNode (&gBrowserFormSetList, Link);
   6364       }
   6365       return FALSE;
   6366 
   6367     default:
   6368       return FALSE;
   6369   }
   6370 }
   6371 
   6372 /**
   6373   Execute the action requested by the Action parameter.
   6374 
   6375   @param[in] Action     Execute the request action.
   6376   @param[in] DefaultId  The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
   6377 
   6378   @retval EFI_SUCCESS              Execute the request action succss.
   6379   @retval EFI_INVALID_PARAMETER    The input action value is invalid.
   6380 
   6381 **/
   6382 EFI_STATUS
   6383 EFIAPI
   6384 ExecuteAction (
   6385   IN UINT32        Action,
   6386   IN UINT16        DefaultId
   6387   )
   6388 {
   6389   EFI_STATUS              Status;
   6390   FORM_BROWSER_FORMSET    *FormSet;
   6391   FORM_BROWSER_FORM       *Form;
   6392 
   6393   if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
   6394     return EFI_NOT_READY;
   6395   }
   6396 
   6397   Status  = EFI_SUCCESS;
   6398   FormSet = NULL;
   6399   Form    = NULL;
   6400   if (gBrowserSettingScope < SystemLevel) {
   6401     FormSet = gCurrentSelection->FormSet;
   6402     Form    = gCurrentSelection->Form;
   6403   }
   6404 
   6405   //
   6406   // Executet the discard action.
   6407   //
   6408   if ((Action & BROWSER_ACTION_DISCARD) != 0) {
   6409     Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
   6410     if (EFI_ERROR (Status)) {
   6411       return Status;
   6412     }
   6413   }
   6414 
   6415   //
   6416   // Executet the difault action.
   6417   //
   6418   if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
   6419     Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
   6420     if (EFI_ERROR (Status)) {
   6421       return Status;
   6422     }
   6423     UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
   6424   }
   6425 
   6426   //
   6427   // Executet the submit action.
   6428   //
   6429   if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
   6430     Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
   6431     if (EFI_ERROR (Status)) {
   6432       return Status;
   6433     }
   6434   }
   6435 
   6436   //
   6437   // Executet the reset action.
   6438   //
   6439   if ((Action & BROWSER_ACTION_RESET) != 0) {
   6440     gResetRequired = TRUE;
   6441   }
   6442 
   6443   //
   6444   // Executet the exit action.
   6445   //
   6446   if ((Action & BROWSER_ACTION_EXIT) != 0) {
   6447     DiscardForm (FormSet, Form, gBrowserSettingScope);
   6448     if (gBrowserSettingScope == SystemLevel) {
   6449       if (ExitHandlerFunction != NULL) {
   6450         ExitHandlerFunction ();
   6451       }
   6452     }
   6453 
   6454     gExitRequired = TRUE;
   6455   }
   6456 
   6457   return Status;
   6458 }
   6459 
   6460 /**
   6461   Create reminder to let user to choose save or discard the changed browser data.
   6462   Caller can use it to actively check the changed browser data.
   6463 
   6464   @retval BROWSER_NO_CHANGES       No browser data is changed.
   6465   @retval BROWSER_SAVE_CHANGES     The changed browser data is saved.
   6466   @retval BROWSER_DISCARD_CHANGES  The changed browser data is discard.
   6467   @retval BROWSER_KEEP_CURRENT     Browser keep current changes.
   6468 
   6469 **/
   6470 UINT32
   6471 EFIAPI
   6472 SaveReminder (
   6473   VOID
   6474   )
   6475 {
   6476   LIST_ENTRY              *Link;
   6477   FORM_BROWSER_FORMSET    *FormSet;
   6478   BOOLEAN                 IsDataChanged;
   6479   UINT32                  DataSavedAction;
   6480   UINT32                  ConfirmRet;
   6481 
   6482   DataSavedAction  = BROWSER_NO_CHANGES;
   6483   IsDataChanged    = FALSE;
   6484   Link = GetFirstNode (&gBrowserFormSetList);
   6485   while (!IsNull (&gBrowserFormSetList, Link)) {
   6486     FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
   6487     Link = GetNextNode (&gBrowserFormSetList, Link);
   6488     if (!ValidateFormSet(FormSet)) {
   6489       continue;
   6490     }
   6491     if (IsNvUpdateRequiredForFormSet (FormSet)) {
   6492       IsDataChanged = TRUE;
   6493       break;
   6494     }
   6495   }
   6496 
   6497   //
   6498   // No data is changed. No save is required.
   6499   //
   6500   if (!IsDataChanged) {
   6501     return DataSavedAction;
   6502   }
   6503 
   6504   //
   6505   // If data is changed, prompt user to save or discard it.
   6506   //
   6507   do {
   6508     ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
   6509 
   6510     if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
   6511       SubmitForm (NULL, NULL, SystemLevel);
   6512       DataSavedAction = BROWSER_SAVE_CHANGES;
   6513       break;
   6514     } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
   6515       DiscardForm (NULL, NULL, SystemLevel);
   6516       DataSavedAction = BROWSER_DISCARD_CHANGES;
   6517       break;
   6518     } else if (ConfirmRet == BROWSER_ACTION_NONE) {
   6519       DataSavedAction = BROWSER_KEEP_CURRENT;
   6520       break;
   6521     }
   6522   } while (1);
   6523 
   6524   return DataSavedAction;
   6525 }
   6526 
   6527 /**
   6528   Check whether the Reset Required for the browser
   6529 
   6530   @retval TRUE      Browser required to reset after exit.
   6531   @retval FALSE     Browser not need to reset after exit.
   6532 
   6533 **/
   6534 BOOLEAN
   6535 EFIAPI
   6536 IsResetRequired (
   6537   VOID
   6538   )
   6539 {
   6540   return gResetRequired;
   6541 }
   6542 
   6543