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