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