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