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