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