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